From 8b50f11fcdac3a48a69f6a0e57e51eb92a6360d2 Mon Sep 17 00:00:00 2001 From: 0X-SquidSol Date: Mon, 31 Aug 2026 09:51:26 -0400 Subject: [PATCH 1/3] =?UTF-8?q?fix(nft):=20the=20burn=20holder=20is=20the?= =?UTF-8?q?=20rent=20recipient=20=E2=80=94=20mark=20it=20writable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ACCOUNTS_NFT_BURN` and `ACCOUNTS_NFT_EMERGENCY_BURN` marked account 0, the NFT holder, as "s": signer but NOT writable. The program requires signer AND writable, because the holder receives the rent from every account those instructions close — the ATA, the mint, the PositionNft PDA and the ExtraAccountMetaList. percolator-nft rejects a read-only holder outright: fn require_writable_rent_recipient(holder: &AccountInfo) -> ProgramResult { if !holder.is_writable { return Err(ProgramError::InvalidAccountData); } Ok(()) } called from BurnPositionNft (processor.rs:825) and EmergencyBurn (:1000). The program's own ABI table documents account 0 as `[signer, writable]` (instruction.rs:44 and :99). So every burn instruction built from these templates via buildNftAccountMetas went on the wire with isWritable: false and was rejected with InvalidAccountData. This is a live break against the deployed programs. It went unnoticed because nothing in this repo consumes the templates — there is no in-repo call site of buildNftAccountMetas or of any ACCOUNTS_NFT_* array, so only external callers ever exercised them. The existing drift tests could not have caught it either: they assert the shorthand string codes, and the defect is only visible once those become {isSigner, isWritable} booleans. Add account-list tests that round-trip through the real builder and assert those booleans. That is the assertion that makes this class visible, and it also covers the historical wrong-builder bug documented above buildNftAccountMetas, where every flag silently became `undefined`. Closes #376 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 33 +++++++++++++++++++++ dist/abi/nft.d.ts | 5 ++-- dist/index.js | 4 +-- dist/index.js.map | 2 +- src/abi/nft.ts | 9 +++--- test/drift-check.test.ts | 62 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de2befa..b48e815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,39 @@ Versioning follows [Semantic Versioning](https://semver.org/). --- +## [5.0.0] — unreleased + +`package.json` was bumped to 5.0.0 by `3704dfd` without a changelog section; +this collects that change and everything since. + +### Fixed + +- **`ACCOUNTS_NFT_BURN` / `ACCOUNTS_NFT_EMERGENCY_BURN`: the NFT holder is now + `[signer, writable]`, not `[signer]`.** The holder is the rent recipient for + every account those instructions close — the ATA, the mint, the PositionNft + PDA and the ExtraAccountMetaList — and percolator-nft rejects a read-only + holder outright via `require_writable_rent_recipient` (`processor.rs:825`, + `:1000`); its own ABI table documents account 0 as `[signer, writable]` + (`instruction.rs:44`, `:99`). Every burn built from these templates through + `buildNftAccountMetas` previously went on the wire with `isWritable: false` + and was rejected with `InvalidAccountData`. This was a live break against the + deployed programs. (dcccrypto/percolator-sdk#376) + +### Breaking + +- **`fix(stake)!`** (`3704dfd`): an ambiguous network now throws instead of + defaulting to mainnet. + +### Added + +- Account-list drift tests (`test/drift-check.test.ts`) that round-trip each + `ACCOUNTS_NFT_*` template through `buildNftAccountMetas` and assert the + resulting `{isSigner, isWritable}` booleans. The previous tests asserted the + shorthand string codes, at which level the holder defect above was invisible. + Nothing in this repo consumes these templates, so they had no coverage at all. + +--- + ## [4.3.0] — 2026-07-24 Creator fee claim: the read side (`creatorFeeClaimableAtoms`) and the write side diff --git a/dist/abi/nft.d.ts b/dist/abi/nft.d.ts index ea16c5a..73604d8 100644 --- a/dist/abi/nft.d.ts +++ b/dist/abi/nft.d.ts @@ -103,7 +103,8 @@ export declare const ACCOUNTS_NFT_MINT: AccountMeta[]; /** * Account metas for BurnPositionNft (tag 1). 10 accounts. * - * 0. [signer] NFT holder + * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint, + * PositionNft PDA and ExtraAccountMetaList rent) * 1. [writable] PositionNft PDA (closed) * 2. [writable] NFT mint (supply → 0) * 3. [writable] Holder's NFT ATA (closed) @@ -121,7 +122,7 @@ export declare const ACCOUNTS_NFT_BURN: AccountMeta[]; /** * Account metas for EmergencyBurn (tag 5). 10 accounts. * - * 0. [signer] NFT holder + * 0. [signer, writable] NFT holder (rent recipient) * 1. [writable] PositionNft PDA (closed) * 2. [writable] NFT mint * 3. [writable] Holder's NFT ATA diff --git a/dist/index.js b/dist/index.js index 38a7e9c..332090e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2761,7 +2761,7 @@ var ACCOUNTS_NFT_MINT = [ "r" ]; var ACCOUNTS_NFT_BURN = [ - "s", + "sw", "w", "w", "w", @@ -2773,7 +2773,7 @@ var ACCOUNTS_NFT_BURN = [ "r" ]; var ACCOUNTS_NFT_EMERGENCY_BURN = [ - "s", + "sw", "w", "w", "w", diff --git a/dist/index.js.map b/dist/index.js.map index ee702e6..ed3a64b 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\n\nconst U8_MAX = 0xFF;\nconst U16_MAX = 0xFFFF;\nconst U32_MAX = 0xFFFFFFFF;\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\n\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\n if (typeof val === \"bigint\") return val;\n if (typeof val !== \"string\") {\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\n }\n if (!DECIMAL_INT_RE.test(val)) {\n throw new Error(`${fnName}: value must be a decimal integer string`);\n }\n return BigInt(val);\n}\n\n/**\n * Encode u8 (1 byte)\n */\nexport function encU8(val: number): Uint8Array {\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\n }\n return new Uint8Array([val]);\n}\n\n/**\n * Encode u16 little-endian (2 bytes)\n */\nexport function encU16(val: number): Uint8Array {\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\n }\n const buf = new Uint8Array(2);\n new DataView(buf.buffer).setUint16(0, val, true);\n return buf;\n}\n\n/**\n * Encode u32 little-endian (4 bytes)\n */\nexport function encU32(val: number): Uint8Array {\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\n }\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, val, true);\n return buf;\n}\n\n/**\n * Encode u64 little-endian (8 bytes)\n * Input: bigint or string (decimal)\n */\nexport function encU64(val: bigint | string): Uint8Array {\n const n = parseDecimalBigInt(val, \"encU64\");\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\n const buf = new Uint8Array(8);\n new DataView(buf.buffer).setBigUint64(0, n, true);\n return buf;\n}\n\n/**\n * Encode i64 little-endian (8 bytes), two's complement\n * Input: bigint or string (decimal, may be negative)\n */\nexport function encI64(val: bigint | string): Uint8Array {\n const n = parseDecimalBigInt(val, \"encI64\");\n const min = -(1n << 63n);\n const max = (1n << 63n) - 1n;\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\n const buf = new Uint8Array(8);\n new DataView(buf.buffer).setBigInt64(0, n, true);\n return buf;\n}\n\n/**\n * Encode u128 little-endian (16 bytes)\n * Input: bigint or string (decimal)\n */\nexport function encU128(val: bigint | string): Uint8Array {\n const n = parseDecimalBigInt(val, \"encU128\");\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\n const max = (1n << 128n) - 1n;\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\n const buf = new Uint8Array(16);\n const view = new DataView(buf.buffer);\n const lo = n & 0xffff_ffff_ffff_ffffn;\n const hi = n >> 64n;\n view.setBigUint64(0, lo, true);\n view.setBigUint64(8, hi, true);\n return buf;\n}\n\n/**\n * Encode i128 little-endian (16 bytes), two's complement\n * Input: bigint or string (decimal, may be negative)\n */\nexport function encI128(val: bigint | string): Uint8Array {\n const n = parseDecimalBigInt(val, \"encI128\");\n const min = -(1n << 127n);\n const max = (1n << 127n) - 1n;\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\n\n // Convert to unsigned representation (two's complement)\n let unsigned = n;\n if (n < 0n) {\n unsigned = (1n << 128n) + n;\n }\n\n const buf = new Uint8Array(16);\n const view = new DataView(buf.buffer);\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\n const hi = unsigned >> 64n;\n view.setBigUint64(0, lo, true);\n view.setBigUint64(8, hi, true);\n return buf;\n}\n\n/**\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\n *\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\n * objects are validated before their bytes are returned so JavaScript callers\n * cannot provide malformed `toBytes()` output.\n *\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\n */\nexport function encPubkey(val: PublicKey | string): Uint8Array {\n try {\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\n\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\n throw new Error(\"value must be a PublicKey or base58 string\");\n }\n\n const bytes = pk.toBytes();\n\n if (!(bytes instanceof Uint8Array)) {\n throw new Error(\"toBytes() must return a Uint8Array\");\n }\n\n if (bytes.length !== 32) {\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\n }\n\n return bytes;\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\n }\n}\n\n/**\n * Encode a boolean as u8 (0 = false, 1 = true)\n */\nexport function encBool(val: boolean): Uint8Array {\n return encU8(val ? 1 : 0);\n}\n\n/**\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\n */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\n const result = new Uint8Array(totalLen);\n let offset = 0;\n for (const arr of arrays) {\n result.set(arr, offset);\n offset += arr.length;\n }\n return result;\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport {\n encU8,\n encU16,\n encU32,\n encU64,\n encI64,\n encU128,\n encI128,\n encPubkey,\n concatBytes,\n} from \"./encode.js\";\n\n/**\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\n * v17 converged wrapper (percolator-prog @v17-convergence, source\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\n * InvalidInstructionData.\n *\n * v17 breaking changes vs v12.x:\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\n * all callers — the program hard-rejects nonzero.\n * - Domain fields: u8→u16 everywhere.\n */\nexport const IX_TAG = {\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\n InitMarket: 0,\n InitPortfolio: 1,\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\n InitUser: 1,\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\n InitLP: 2,\n Deposit: 3,\n /** @alias DepositCollateral @since v12.x alias */\n DepositCollateral: 3,\n Withdraw: 4,\n /** @alias WithdrawCollateral @since v12.x alias */\n WithdrawCollateral: 4,\n /**\n * PermissionlessCrank (tag 5).\n *\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\n * construct the payload manually and omit this field — that produces a\n * malformed instruction (missing bytes).\n */\n PermissionlessCrank: 5,\n /** @alias KeeperCrank @since v12.x alias */\n KeeperCrank: 5,\n TradeNoCpi: 6,\n LiquidateAtOracle: 7,\n ClosePortfolio: 8,\n /** @alias CloseAccount @since v12.x alias */\n CloseAccount: 8,\n TopUpInsurance: 9,\n TradeCpi: 10,\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\n SetRiskThreshold: 11,\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\n UpdateAdmin: 12,\n CloseSlab: 13,\n ResolveMarket: 19,\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\n TopUpBackingBucket: 24,\n ConvertReleasedPnl: 28,\n CloseResolved: 30,\n /**\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\n *\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\n * rotation uses tag 65 (UpdateAssetAuthority).\n */\n UpdateAuthority: 32,\n ConfigureHybridOracle: 34,\n ConfigureEwmaMark: 35,\n PushEwmaMark: 36,\n UpdateLiquidationFeePolicy: 37,\n ConfigurePermissionlessResolve: 38,\n ResolveStalePermissionless: 39,\n UpdateAssetLifecycle: 40,\n WithdrawInsurance: 41,\n CureAndCancelClose: 42,\n ForfeitRecoveryLeg: 43,\n RebalanceReduce: 44,\n FinalizeResetSide: 45,\n ClaimResolvedPayoutTopup: 46,\n RefineResolvedUnreceiptedBound: 47,\n SyncMaintenanceFee: 48,\n UpdateMaintenanceFeePolicy: 49,\n WithdrawBackingBucket: 50,\n UpdateBackingFeePolicy: 51,\n WithdrawBackingBucketEarnings: 52,\n SyncBackingDomainLedger: 53,\n SyncInsuranceLedger: 54,\n UpdateTradeFeePolicy: 55,\n TopUpInsuranceDomain: 56,\n /**\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\n *\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\n */\n WithdrawInsuranceAsset: 57,\n UpdateFeeRedirectPolicy: 58,\n UpdateMarketInitFeePolicy: 59,\n UpdateBaseUnitMints: 60,\n SwapSecondaryForPrimary: 61,\n ConfigureAuthMark: 62,\n PushAuthMark: 63,\n ForceCloseAbandonedAsset: 64,\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\n /**\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\n *\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\n *\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\n * 1 = INSURANCE — insurance_authority\n * 2 = INSURANCE_OPERATOR — insurance_operator\n * 3 = BACKING_BUCKET — backing_bucket_authority\n * 4 = ORACLE — oracle_authority\n *\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\n * See stake-program docs.\n */\n UpdateAssetAuthority: 65,\n /**\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\n *\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\n */\n BatchTradeNoCpi: 66,\n /**\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\n *\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\n */\n BatchTradeCpi: 67,\n /**\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\n *\n * Wire: tag(1) + enabled(u8) = 2 bytes.\n */\n SetMatcherConfig: 68,\n /**\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\n *\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\n */\n RestartAssetOracle: 69,\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\n /**\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\n *\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\n */\n TransferPortfolioOwnership: 72,\n /**\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\n *\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\n */\n SetNftProgramId: 73,\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\n /**\n * CreateLpVault (tag 74).\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\n */\n CreateLpVault: 74,\n /**\n * DepositToLpVault (tag 75).\n * Wire: tag(1) + amount(u128) = 17 bytes.\n */\n DepositToLpVault: 75,\n /**\n * RequestRedeemLpShares (tag 76).\n * Wire: tag(1) + shares(u128) = 17 bytes.\n */\n RequestRedeemLpShares: 76,\n /**\n * ExecuteRedemption (tag 77).\n * Wire: tag(1) = 1 byte.\n */\n ExecuteRedemption: 77,\n /**\n * LpVaultCrankFees (tag 78).\n * Wire: tag(1) = 1 byte.\n */\n LpVaultCrankFees: 78,\n /**\n * SetLpVaultPaused (tag 79).\n * Wire: tag(1) + paused(u8) = 2 bytes.\n */\n SetLpVaultPaused: 79,\n /**\n * CloseLpVault (tag 80).\n * Wire: tag(1) = 1 byte.\n */\n CloseLpVault: 80,\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\n LpVaultDeposit: 75,\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\n LpVaultWithdraw: 76,\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\n /** @deprecated v12.x tag 14. Removed in v17. */\n UpdateConfig: 14,\n /** @deprecated v12.x tag 15. Removed in v17. */\n SetMaintenanceFee: 15,\n /** @deprecated v12.x tag 16. Removed in v17. */\n SetOraclePriceCap: 16,\n /** @deprecated v12.x tag 17. Removed in v17. */\n AdminForceClose: 17,\n /** @deprecated v12.x tag 18. Removed in v17. */\n UpdateRiskParams: 18,\n /** @deprecated v12.x tag 20. Removed in v17. */\n SetPythOracle: 20,\n /** @deprecated v12.x tag 21. Removed in v17. */\n RenounceAdmin: 21,\n /** @deprecated v12.x tag 22. Removed in v17. */\n SetInsuranceWithdrawPolicy: 22,\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\n WithdrawInsuranceLimited: 23,\n /** @deprecated v12.x tag 25. Removed in v17. */\n FundMarketInsurance: 25,\n /** @deprecated v12.x tag 26. Removed in v17. */\n SetInsuranceIsolation: 26,\n /** @deprecated v12.x tag 27. Removed in v17. */\n DepositFeeCredits: 27,\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\n ResolvePermissionless: 29,\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\n ForceCloseResolved: 30,\n /** @deprecated v12.x tag 33. Removed in v17. */\n UpdateInsurancePolicy: 33,\n /** @deprecated v12.x tag 36. Removed in v12.17. */\n UnresolveMarket: 36,\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\n ChallengeSettlement: 43,\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\n ResolveDispute: 44,\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\n DepositLpCollateral: 45,\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\n WithdrawLpCollateral: 46,\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\n SetOffsetPair: 54,\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\n AttestCrossMargin: 55,\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\n PauseMarket: 56,\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\n UnpauseMarket: 58,\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\n MintPositionNft: 64,\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\n TransferPositionOwnership: 65,\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\n BurnPositionNft: 66,\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\n SetPendingSettlement: 67,\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\n ClearPendingSettlement: 68,\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\n TransferOwnershipCpi: 69,\n /** @deprecated v12.x tag 70. Not in v17. */\n SetWalletCap: 70,\n /** @deprecated v12.x tag 71. Not in v17. */\n SetOiImbalanceHardBlock: 71,\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\n RescueOrphanVault: 72,\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\n CloseOrphanSlab: 73,\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\n SetDexPool: 74,\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\n InitMatcherCtxV12: 75,\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\n SetMaxPnlCap: 78,\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\n SetOiCapMultiplier: 79,\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\n SetDisputeParams: 80,\n /** @deprecated v12.x tag 81. Not in v17. */\n SetLpCollateralParams: 81,\n /** @deprecated v12.x tag 82. Not in v17. */\n AcceptAdmin: 82,\n /**\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\n *\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\n * skew_spread_mult_bps(u16) = 70 bytes total.\n *\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\n *\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\n *\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\n * free tag 83 for this instruction rather than the reverse.\n */\n InitMatcherCtx: 83,\n /**\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\n *\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\n *\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\n */\n WithdrawProtocolFee: 84,\n /**\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\n * cfg.protocol_fee_authority.\n *\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\n *\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\n */\n SetProtocolFeeAuthority: 85,\n /**\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\n *\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\n *\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\n * FeeSplitFloorViolation.\n *\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\n * `encodeStakeAdminUpdateFeeSplit`.\n */\n UpdateFeeSplit: 86,\n /**\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\n * vault and into the bound stake pool's vault, where percolator-stake's\n * AccrueFees measures it as surplus and distributes it to stakers.\n *\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\n *\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\n * id. The only thing a caller decides is *when* the push happens.\n *\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\n * ResolveMarket, not after.\n */\n WithdrawInsuranceReserveToStake: 87,\n /**\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\n * argument with no setter anywhere in the dispatch table and was therefore\n * frozen for the life of the market.\n *\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\n *\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\n * (v16_program.rs tag-88 arm), matching both the storage type\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\n * rejects the whole instruction with InvalidInstructionData.\n *\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\n */\n UpdateMaintenanceFeePerSlot: 88,\n /**\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\n * bucket to `Expired`/`Impaired` so settlement against that domain can\n * proceed again.\n *\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\n *\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\n * horizon defers the lapse, it does not avoid it. See\n * {@link encodeExpireBackingBucket} for the full keeper contract.\n */\n ExpireBackingBucket: 89,\n /**\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\n * Pays the market creator's accrued trade-fee share out of the vault and\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\n * EXACTLY `amount`.\n *\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\n * tag 84).\n *\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\n * config and pass that to drain it.\n *\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\n * alone, so this deliberate divergence is what lets the creator still claim\n * after staking (and stops the pool PDA claiming creator revenue).\n *\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\n * saturated — there is no partial fill. Nothing is debited on failure.\n */\n WithdrawCreatorFee: 90,\n /**\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\n * between the two domains of the LP vault's asset, carrying ledger principal\n * in lockstep. No tokens move: `header.vault` is untouched.\n *\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\n * gains from the OPPOSITE domain, so without this the pot the house actually\n * needs can never be refilled (spec.md L410 requires refill be source-domain\n * local).\n */\n RebalanceLpVaultBacking: 91,\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\n ReclaimEmptyAccount: 85,\n /** @deprecated v12.x tag 86. Not in v17. */\n SettleAccount: 86,\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\n UpdateMarkPrice: 90,\n /** @deprecated v12.x tag 91. Not in v17. */\n AuditCrank: 91,\n /** @deprecated v12.x tag 92. Not in v17. */\n AdvanceOraclePhase: 92,\n /** @deprecated v12.x tag 93. Not in v17. */\n SlashCreationDeposit: 93,\n /** @deprecated v12.x tag 94. Not in v17. */\n InitSharedVault: 94,\n /** @deprecated v12.x tag 95. Not in v17. */\n AllocateMarket: 95,\n /** @deprecated v12.x tag 96. Not in v17. */\n QueueWithdrawalSV: 96,\n /** @deprecated v12.x tag 97. Not in v17. */\n ClaimEpochWithdrawal: 97,\n /** @deprecated v12.x tag 98. Not in v17. */\n AdvanceEpoch: 98,\n /** @deprecated v12.x tag 99. Not in v17. */\n ReclaimSlabRent: 99,\n /** @deprecated v12.x tag 100. Not in v17. */\n CloseStaleSlabs: 100,\n /** @deprecated v12.x tag 101. Not in v17. */\n ExecuteAdl: 101,\n /** @deprecated v12.x tag 102. Not in v17. */\n QueueWithdrawal: 102,\n /** @deprecated v12.x tag 103. Not in v17. */\n ClaimQueuedWithdrawal: 103,\n /** @deprecated v12.x tag 104. Not in v17. */\n CancelQueuedWithdrawal: 104,\n /** @deprecated v12.x tag 105. Not in v17. */\n TradeCpiV: 105,\n} as const;\nObject.freeze(IX_TAG);\n\n/**\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\n *\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\n */\nexport const EXPECTED_SLAB_VERSION = 16;\n\n/**\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\n */\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\n\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\n throw new Error(\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\n );\n}\n\n/**\n * InitMarket instruction data — v17 wire format.\n *\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\n *\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\n * provided as account metas or configured separately via ConfigureHybridOracle /\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\n *\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\n * is completely rejected by the v17 program — the first field read is now\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\n * a u16 portfolio count, producing invalid config or rejection at every call.\n *\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\n */\n/**\n * Optional 66-byte extended tail for InitMarket (S-4).\n *\n * When present and any field is non-zero the encoder appends a 66-byte block\n * in the exact order that the program reads it (percolator.rs:1516-1545):\n * insurance_withdraw_max_bps u16 (2 bytes)\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\n * permissionless_resolve_stale_slots u64 (8 bytes)\n * funding_horizon_slots u64 (8 bytes)\n * funding_k_bps u64 (8 bytes)\n * funding_max_premium_bps i64 (8 bytes)\n * funding_max_bps_per_slot i64 (8 bytes)\n * mark_min_fee u64 (8 bytes)\n * force_close_delay_slots u64 (8 bytes)\n * total = 2 + 8*8 = 66 bytes\n *\n * When absent (or all fields are zero) the encoder omits the tail and the\n * program treats all extended fields as their default zero values. This\n * preserves full backward compatibility with existing 344-byte payloads.\n */\nexport interface InitMarketExtendedTail {\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\n insuranceWithdrawMaxBps: number;\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\n insuranceWithdrawCooldownSlots: bigint | string;\n /** Slots after which an unresolved market may be permissionlessly resolved. */\n permissionlessResolveStaleSlots: bigint | string;\n /** Funding rate horizon in slots (custom_funding_k denominator). */\n fundingHorizonSlots: bigint | string;\n /** Funding rate K parameter in bps (0 = disabled). */\n fundingKBps: bigint | string;\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\n fundingMaxPremiumBps: bigint | string;\n /** Maximum funding rate change per slot in bps (i64). */\n fundingMaxBpsPerSlot: bigint | string;\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\n markMinFee: bigint | string;\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\n forceCloseDelaySlots: bigint | string;\n /**\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\n *\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\n * the wrapper applies its deployment default\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\n * emits a 74-byte v2 tail with this value appended after\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\n * `InvalidConfigParam`; the engine then re-validates the solvency\n * envelope at `init_in_place`.\n *\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\n */\n maxPriceMoveBpsPerSlot?: bigint | string;\n}\n\nexport interface InitMarketArgs {\n admin: PublicKey | string;\n collateralMint: PublicKey | string;\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\n maxStalenessSecs: bigint | string;\n confFilterBps: number;\n invert: number;\n unitScale: number;\n initialMarkPriceE6: bigint | string;\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\n maxInsuranceFloor?: bigint | string;\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\n minOraclePriceCap?: bigint | string;\n // RiskParams block (16 fields, read by read_risk_params on-chain)\n /**\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\n * when hMin/hMax are not provided.\n */\n warmupPeriodSlots?: bigint | string;\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\n hMin?: bigint | string;\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\n hMax?: bigint | string;\n maintenanceMarginBps: bigint | string;\n initialMarginBps: bigint | string;\n tradingFeeBps: bigint | string;\n maxAccounts: bigint | string;\n newAccountFee: bigint | string;\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\n maintenanceFeePerSlot: bigint | string;\n maxCrankStalenessSlots: bigint | string;\n liquidationFeeBps: bigint | string;\n liquidationFeeCap: bigint | string;\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\n minLiquidationAbs: bigint | string;\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\n minInitialDeposit?: bigint | string;\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\n /**\n * Optional 66-byte extended tail (S-4).\n * When present and any field is non-zero, appended after the 344-byte base payload.\n * When absent (or all zeros), the base 344-byte payload is sent and the program\n * uses default zero values for all extended fields.\n * @see InitMarketExtendedTail\n */\n extendedTail?: InitMarketExtendedTail;\n}\n\n/**\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\n *\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\n * Retained as a utility for off-chain feed ID validation.\n */\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\n\nexport function encodeFeedId(feedId: string): Uint8Array {\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\n if (!HEX_RE.test(hex)) {\n throw new Error(\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\n );\n }\n const bytes = new Uint8Array(32);\n for (let i = 0; i < 64; i += 2) {\n const byte = parseInt(hex.substring(i, i + 2), 16);\n if (Number.isNaN(byte)) {\n throw new Error(\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\n );\n }\n bytes[i / 2] = byte;\n }\n return bytes;\n}\n\n/**\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\n * (10_000_000_000_000_000 — effectively unlimited).\n *\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\n * engine returns `RecoveryRequired` and refuses further liquidation until\n * the insurance fund covers the residual. Production markets MUST use this\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\n * limit is intended AND the insurance fund is sized accordingly.\n *\n * @example\n * ```ts\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\n * const data = encodeInitMarket({\n * ...otherParams,\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\n * maintenanceFeePerSlot: 0n,\n * });\n * ```\n */\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\n\n// v17 wire layout (v16_program.rs decode arm at tag 0):\n// tag(1) +\n// max_portfolio_assets(u16=2) +\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\n// liquidation_fee_bps(u64=8) +\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\n// max_bankrupt_close_lifetime_slots(u64=8) +\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\nconst INIT_MARKET_V17_LEN = 219;\n\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\n// with no optional tail — all parameters are required fields in the main body.\n\n/**\n * InitMarket v17 argument interface.\n *\n * admin and collateralMint are passed as account metas (accounts[0] and\n * accounts[2] respectively), NOT in instruction data.\n *\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\n * after the market is created.\n *\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\n * max_portfolio_assets, h_min, h_max, initial_price,\n * min_nonzero_mm_req, min_nonzero_im_req,\n * maintenance_margin_bps, initial_margin_bps,\n * max_trading_fee_bps, trade_fee_base_bps,\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\n * max_bankrupt_close_lifetime_slots,\n * public_b_chunk_atoms, maintenance_fee_per_slot.\n */\nexport interface InitMarketV17Args {\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\n maxPortfolioAssets: number;\n /** Minimum funding horizon in slots (u64). */\n hMin: bigint | string;\n /** Maximum funding horizon in slots (u64). */\n hMax: bigint | string;\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\n initialPrice: bigint | string;\n /** Minimum non-zero maintenance margin requirement (u128). */\n minNonzeroMmReq: bigint | string;\n /** Minimum non-zero initial margin requirement (u128). */\n minNonzeroImReq: bigint | string;\n /** Maintenance margin ratio in bps (u64). */\n maintenanceMarginBps: bigint | string;\n /** Initial margin ratio in bps (u64). */\n initialMarginBps: bigint | string;\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\n maxTradingFeeBps: bigint | string;\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\n tradeFeeBaseBps: bigint | string;\n /** Liquidation fee in bps (u64). */\n liquidationFeeBps: bigint | string;\n /** Liquidation fee cap in absolute units (u128). */\n liquidationFeeCap: bigint | string;\n /** Minimum liquidation size in absolute units (u128). */\n minLiquidationAbs: bigint | string;\n /** Maximum price movement per slot in bps (u64). */\n maxPriceMoveBpsPerSlot: bigint | string;\n /** Maximum accrual delta-time in slots (u64). */\n maxAccrualDtSlots: bigint | string;\n /** Maximum absolute funding rate in e9 per slot (u64). */\n maxAbsFundingE9PerSlot: bigint | string;\n /** Minimum funding lifetime in slots (u64). */\n minFundingLifetimeSlots: bigint | string;\n /** Maximum account-B settlement chunks per crank (u64). */\n maxAccountBSettlementChunks: bigint | string;\n /** Maximum bankrupt-close chunks per crank (u64). */\n maxBankruptCloseChunks: bigint | string;\n /** Maximum bankrupt-close lifetime in slots (u64). */\n maxBankruptCloseLifetimeSlots: bigint | string;\n /**\n * Public-B chunk size in atoms (u128).\n *\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\n * the engine returns `RecoveryRequired` when the bankrupt position's\n * liability exceeds this limit and insurance is insufficient to cover it.\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\n * and a funded insurance pool.\n */\n publicBChunkAtoms: bigint | string;\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\n maintenanceFeePerSlot: bigint | string;\n}\n\n/**\n * Encode InitMarket instruction data (v17 wire format).\n *\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\n *\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\n *\n * @param args v17 market parameters (InitMarketV17Args)\n * @returns 227-byte Uint8Array\n *\n * @example\n * ```ts\n * const data = encodeInitMarket({\n * maxPortfolioAssets: 256,\n * hMin: 1000n,\n * hMax: 100000n,\n * initialPrice: 50_000_000_000n,\n * minNonzeroMmReq: 1_000_000n,\n * minNonzeroImReq: 2_000_000n,\n * maintenanceMarginBps: 500n,\n * initialMarginBps: 1000n,\n * maxTradingFeeBps: 100n,\n * tradeFeeBaseBps: 30n,\n * liquidationFeeBps: 100n,\n * liquidationFeeCap: 10_000_000n,\n * minLiquidationAbs: 1_000_000n,\n * maxPriceMoveBpsPerSlot: 4n,\n * maxAccrualDtSlots: 600n,\n * maxAbsFundingE9PerSlot: 1000n,\n * minFundingLifetimeSlots: 50n,\n * maxAccountBSettlementChunks: 10n,\n * maxBankruptCloseChunks: 10n,\n * maxBankruptCloseLifetimeSlots: 500n,\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\n * maintenanceFeePerSlot: 0n,\n * });\n * ```\n */\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\n const isV17Args = 'maxPortfolioAssets' in args;\n\n let maxPortfolioAssets: number;\n let hMin: bigint | string;\n let hMax: bigint | string;\n let initialPrice: bigint | string;\n let minNonzeroMmReq: bigint | string;\n let minNonzeroImReq: bigint | string;\n let maintenanceMarginBps: bigint | string;\n let initialMarginBps: bigint | string;\n let maxTradingFeeBps: bigint | string;\n let tradeFeeBaseBps: bigint | string;\n let liquidationFeeBps: bigint | string;\n let liquidationFeeCap: bigint | string;\n let minLiquidationAbs: bigint | string;\n let maxPriceMoveBpsPerSlot: bigint | string;\n let maxAccrualDtSlots: bigint | string;\n let maxAbsFundingE9PerSlot: bigint | string;\n let minFundingLifetimeSlots: bigint | string;\n let maxAccountBSettlementChunks: bigint | string;\n let maxBankruptCloseChunks: bigint | string;\n let maxBankruptCloseLifetimeSlots: bigint | string;\n let publicBChunkAtoms: bigint | string;\n let maintenanceFeePerSlot: bigint | string;\n\n if (isV17Args) {\n const v = args as InitMarketV17Args;\n maxPortfolioAssets = v.maxPortfolioAssets;\n hMin = v.hMin;\n hMax = v.hMax;\n initialPrice = v.initialPrice;\n minNonzeroMmReq = v.minNonzeroMmReq;\n minNonzeroImReq = v.minNonzeroImReq;\n maintenanceMarginBps = v.maintenanceMarginBps;\n initialMarginBps = v.initialMarginBps;\n maxTradingFeeBps = v.maxTradingFeeBps;\n tradeFeeBaseBps = v.tradeFeeBaseBps;\n liquidationFeeBps = v.liquidationFeeBps;\n liquidationFeeCap = v.liquidationFeeCap;\n minLiquidationAbs = v.minLiquidationAbs;\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\n maxAccrualDtSlots = v.maxAccrualDtSlots;\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\n publicBChunkAtoms = v.publicBChunkAtoms;\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\n } else {\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\n // invert, unitScale, extendedTail) are silently ignored.\n const v = args as InitMarketArgs;\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\n hMin = resolvedHMin;\n hMax = resolvedHMax;\n initialPrice = v.initialMarkPriceE6;\n minNonzeroMmReq = v.minNonzeroMmReq;\n minNonzeroImReq = v.minNonzeroImReq;\n maintenanceMarginBps = v.maintenanceMarginBps;\n initialMarginBps = v.initialMarginBps;\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\n maxTradingFeeBps = v.tradingFeeBps;\n tradeFeeBaseBps = v.tradingFeeBps;\n liquidationFeeBps = v.liquidationFeeBps;\n liquidationFeeCap = v.liquidationFeeCap;\n minLiquidationAbs = v.minLiquidationAbs;\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\n minFundingLifetimeSlots = 0n;\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\n // them to functional values instead so v12-initialized markets stay recoverable; callers\n // wanting explicit control should migrate to InitMarketV17Args.\n maxAccountBSettlementChunks = 10n;\n maxBankruptCloseChunks = 10n;\n maxBankruptCloseLifetimeSlots = 500n;\n publicBChunkAtoms = 1_000_000n;\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\n }\n\n const data = concatBytes(\n encU8(IX_TAG.InitMarket),\n encU16(maxPortfolioAssets),\n encU64(hMin),\n encU64(hMax),\n encU64(initialPrice),\n encU128(minNonzeroMmReq),\n encU128(minNonzeroImReq),\n encU64(maintenanceMarginBps),\n encU64(initialMarginBps),\n encU64(maxTradingFeeBps),\n encU64(tradeFeeBaseBps),\n encU64(liquidationFeeBps),\n encU128(liquidationFeeCap),\n encU128(minLiquidationAbs),\n encU64(maxPriceMoveBpsPerSlot),\n encU64(maxAccrualDtSlots),\n encU64(maxAbsFundingE9PerSlot),\n encU64(minFundingLifetimeSlots),\n encU64(maxAccountBSettlementChunks),\n encU64(maxBankruptCloseChunks),\n encU64(maxBankruptCloseLifetimeSlots),\n encU128(publicBChunkAtoms),\n encU128(maintenanceFeePerSlot),\n );\n\n if (data.length !== INIT_MARKET_V17_LEN) {\n throw new Error(\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\n );\n }\n\n return data;\n}\n\n/**\n * InitPortfolio / InitUser instruction data.\n *\n * v17 wire: tag(1) only — 1 byte total.\n *\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\n * Sending extra bytes causes garbage reads in downstream decoder arms.\n *\n * @example\n * ```ts\n * const data = encodeInitUser();\n * ```\n */\nexport interface InitUserArgs {\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\n feePayment?: bigint | string;\n}\n\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\n return new Uint8Array([IX_TAG.InitPortfolio]);\n}\n\n/**\n * InitLP (tag 2) — REMOVED in v17.\n *\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\n * results in ProgramError::InvalidInstructionData on-chain.\n *\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\n */\nexport interface InitLPArgs {\n matcherProgram: PublicKey | string;\n matcherContext: PublicKey | string;\n feePayment: bigint | string;\n}\n\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\n}\n\n/**\n * DepositCollateral instruction data.\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\n *\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\n *\n * @example\n * ```ts\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\n * ```\n */\nexport interface DepositCollateralArgs {\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\n userIdx?: number;\n amount: bigint | string;\n}\n\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.DepositCollateral),\n encU128(args.amount),\n );\n}\n\n/**\n * WithdrawCollateral instruction data.\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\n *\n * @param amount Collateral to withdraw (u128).\n *\n * @example\n * ```ts\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\n * ```\n */\nexport interface WithdrawCollateralArgs {\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\n userIdx?: number;\n amount: bigint | string;\n}\n\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawCollateral),\n encU128(args.amount),\n );\n}\n\n/**\n * PermissionlessCrank (tag 5) action byte values.\n *\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\n */\nexport const CrankAction = {\n FeeSweep: 0,\n Liquidate: 1,\n} as const;\n\n/**\n * PermissionlessCrank (tag 5) instruction args.\n *\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\n * and the fee rate is always read from config inside\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\n * while still making forward progress. Any client still encoding the old\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\n * side, not a runtime check.\n *\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\n *\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\n * `read_u64`/`read_i128`/`push_*` call sequence.\n *\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\n * The program hard-rejects any nonzero value with InvalidInstructionData.\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\n * produces a truncated instruction (missing 16 bytes).\n *\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\n * @param assetIndex Asset/domain index to operate on.\n * @param nowSlot Current slot (for crank freshness check).\n * @param recoveryReason Recovery reason byte (0 for normal operations).\n *\n * @example\n * ```ts\n * // Simple fee-sweep crank\n * const data = encodePermissionlessCrank({\n * action: CrankAction.FeeSweep,\n * assetIndex: 0,\n * nowSlot: currentSlot,\n * recoveryReason: 0,\n * });\n * ```\n */\nexport interface PermissionlessCrankArgs {\n action: number;\n assetIndex: number;\n nowSlot: bigint | string;\n recoveryReason: number;\n}\n\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.PermissionlessCrank),\n encU8(args.action),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\n encU8(args.recoveryReason),\n );\n}\n\n/**\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\n * Use encodePermissionlessCrank() instead.\n *\n * Retained for source-compat only. Will throw to prevent silent misuse.\n */\nexport interface KeeperCrankArgs {\n callerIdx: number;\n candidates?: unknown[];\n}\n\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\n throw new Error(\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\n \"Use encodePermissionlessCrank() instead.\"\n );\n}\n\n/**\n * TradeNoCpi instruction data (v17 wire format).\n *\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\n * = 28 bytes.\n *\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\n * v17 has asset_index+size_q+exec_price+fee_bps.\n *\n * @param assetIndex Asset/domain index.\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\n * @param execPrice Execution price in e6 units.\n * @param feeBps Fee in basis points.\n *\n * @example\n * ```ts\n * const data = encodeTradeNoCpi({\n * assetIndex: 0,\n * sizeQ: 1_000_000n,\n * execPrice: 50_000_000_000n,\n * feeBps: 30n,\n * });\n * ```\n */\nexport interface TradeNoCpiArgs {\n assetIndex: number;\n sizeQ: bigint | string;\n execPrice: bigint | string;\n feeBps: bigint | string;\n}\n\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\n const data = concatBytes(\n encU8(IX_TAG.TradeNoCpi),\n encU16(args.assetIndex),\n encI128(args.sizeQ),\n encU64(args.execPrice),\n encU64(args.feeBps),\n );\n if (data.length !== 35) {\n throw new Error(\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\n );\n }\n return data;\n}\n\n/**\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\n *\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\n * results in ProgramError::InvalidInstructionData on-chain.\n *\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\n */\nexport interface LiquidateAtOracleArgs {\n targetIdx: number;\n}\n\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\n return removedInstruction(\n \"LiquidateAtOracle\",\n IX_TAG.LiquidateAtOracle,\n \"PermissionlessCrank (tag 5)\",\n );\n}\n\n/**\n * ClosePortfolio / CloseAccount instruction data.\n *\n * v17 wire: tag(1) only — 1 byte total.\n *\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\n * bytes from the old userIdx field cause InvalidInstructionData.\n *\n * @example\n * ```ts\n * const data = encodeCloseAccount();\n * ```\n */\nexport interface CloseAccountArgs {\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\n userIdx?: number;\n}\n\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\n return new Uint8Array([IX_TAG.ClosePortfolio]);\n}\n\n/**\n * TopUpInsurance instruction data.\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\n *\n * @param amount Amount to top up the insurance fund (u128).\n *\n * @example\n * ```ts\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\n * ```\n */\nexport interface TopUpInsuranceArgs {\n amount: bigint | string;\n}\n\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\n}\n\n/**\n * TopUpBackingBucket instruction data (tag 24).\n *\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\n * = 27 bytes.\n *\n * Deposits `amount` quote atoms of external collateral into a source domain's\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\n *\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\n * SHORT domain is `2*i + 1`.\n *\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\n * every later automatic loss-reserve requests the SAME existing expiry and\n * hits the harmless no-op arm instead of the LockActive trap.\n *\n * @param domain Backing-bucket domain index (2*assetIndex for long,\n * 2*assetIndex+1 for short).\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\n * nonzero \"dust\" amount is sufficient — there is no\n * minimum floor enforced by the engine.\n * @param expirySlot Requested fresh-expiry slot (u64). Use\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\n *\n * @example\n * ```ts\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\n * const data = encodeTopUpBackingBucket({\n * domain: 0,\n * amount: 10_000n, // 0.01 Sim-USDC dust\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\n * });\n * ```\n */\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\n\nexport interface TopUpBackingBucketArgs {\n domain: number;\n amount: bigint | string;\n expirySlot: bigint | string;\n}\n\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.TopUpBackingBucket),\n encU16(args.domain),\n encU128(args.amount),\n encU64(args.expirySlot),\n );\n}\n\n/**\n * WithdrawBackingBucket instruction data (tag 50).\n *\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\n *\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\n * back to the authority's token account. Gated by the asset's\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\n *\n * Together with TopUpBackingBucket (24, deposit) and\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\n * LP-provider backing-bucket loop.\n *\n * @param domain Backing-bucket domain index (2*assetIndex for long,\n * 2*assetIndex+1 for short).\n * @param amount Quote atoms to withdraw (u128; must be > 0).\n */\nexport interface WithdrawBackingBucketArgs {\n domain: number;\n amount: bigint | string;\n}\n\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawBackingBucket),\n encU16(args.domain),\n encU128(args.amount),\n );\n}\n\n/**\n * UpdateBackingFeePolicy instruction data (tag 51).\n *\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\n * insurance_share_bps(u16 LE) = 7 bytes.\n *\n * THE switch that turns on LP-vault yield for a domain: sets the\n * backing-trade fee charged on that domain's fills, of which\n * `insurance_share_bps` is diverted to the insurance budget and the\n * remainder accrues to the domain's backing-bucket providers as\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\n * currently has this at 0 — which is why LP APY is 0%.\n *\n * Gated by the asset's `insurance_authority` (v16_program.rs\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\n * the market creator can call it even after the launch flow rotates\n * marketauth to the stake-pool PDA. Market must be Live.\n *\n * Handler-side validation (reverts InvalidInstruction otherwise):\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\n *\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\n * of the fee (the rest goes to backing providers).\n */\nexport interface UpdateBackingFeePolicyArgs {\n domain: number;\n feeBps: number;\n insuranceShareBps: number;\n}\n\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateBackingFeePolicy),\n encU16(args.domain),\n encU16(args.feeBps),\n encU16(args.insuranceShareBps),\n );\n}\n\n/**\n * WithdrawBackingBucketEarnings instruction data (tag 52).\n *\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\n *\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\n * the authority's token account. Gated by the asset's\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\n * `handle_withdraw_backing_bucket_earnings` → same\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\n * per-domain ledger account is REQUIRED (account [2]).\n *\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\n */\nexport interface WithdrawBackingBucketEarningsArgs {\n domain: number;\n amount: bigint | string;\n}\n\nexport function encodeWithdrawBackingBucketEarnings(\n args: WithdrawBackingBucketEarningsArgs,\n): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\n encU16(args.domain),\n encU128(args.amount),\n );\n}\n\n/**\n * TradeCpi instruction data (v17 wire format).\n *\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\n * = 28 bytes.\n *\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\n * v17 has asset_index+size_q+fee_bps+limit_price.\n *\n * @param assetIndex Asset/domain index.\n * @param sizeQ Trade quantity (signed).\n * @param feeBps Fee in basis points.\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\n * Buys: reject if exec_price > limit_price.\n * Sells: reject if exec_price < limit_price.\n *\n * @example\n * ```ts\n * const data = encodeTradeCpi({\n * assetIndex: 0,\n * sizeQ: 1_000_000n,\n * feeBps: 30n,\n * limitPrice: 51_000_000_000n, // max price for a buy\n * });\n * ```\n */\nexport interface TradeCpiArgs {\n assetIndex: number;\n sizeQ: bigint | string;\n feeBps: bigint | string;\n /** Limit price in e6 units. 0 = no limit. */\n limitPrice: bigint | string;\n}\n\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\n const data = concatBytes(\n encU8(IX_TAG.TradeCpi),\n encU16(args.assetIndex),\n encI128(args.sizeQ),\n encU64(args.feeBps),\n encU64(args.limitPrice),\n );\n if (data.length !== 35) {\n throw new Error(\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\n );\n }\n return data;\n}\n\n/**\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\n */\nexport interface TradeCpiV2Args {\n lpIdx: number;\n userIdx: number;\n size: bigint | string;\n bump: number;\n}\n\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\n}\n\n/**\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\n */\nexport interface UnresolveMarketArgs {\n confirmation: bigint | string;\n}\n\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\n}\n\n/**\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\n * Sending this instruction will fail with InvalidInstructionData.\n */\nexport interface SetRiskThresholdArgs {\n newThreshold: bigint | string;\n}\n\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\n}\n\n/**\n * UpdateAdmin (tag 12) — REMOVED in v17.\n *\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\n * results in ProgramError::InvalidInstructionData on-chain.\n *\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\n */\nexport interface UpdateAdminArgs {\n newAdmin: PublicKey | string;\n}\n\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\n return removedInstruction(\n \"UpdateAdmin\",\n IX_TAG.UpdateAdmin,\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\n );\n}\n\n/**\n * CloseSlab instruction data (1 byte)\n */\nexport function encodeCloseSlab(): Uint8Array {\n return encU8(IX_TAG.CloseSlab);\n}\n\n/**\n * UpdateConfig instruction data.\n *\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\n * src/percolator.rs:2027-2041 (handle_update_config decode).\n */\nexport interface UpdateConfigArgs {\n fundingHorizonSlots: bigint | string;\n fundingKBps: bigint | string;\n fundingMaxPremiumBps: bigint | string;\n fundingMaxBpsPerSlot: bigint | string;\n /**\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\n * Wrapper field added at src/percolator.rs:2031.\n */\n tvlInsuranceCapMult?: number;\n}\n\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\n}\n\n/**\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\n * Sending this instruction will fail with InvalidInstructionData.\n */\nexport interface SetMaintenanceFeeArgs {\n newFee: bigint | string;\n}\n\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\n}\n\n/**\n * SetOraclePriceCap instruction data (9 bytes)\n * Set oracle price circuit breaker cap (admin only).\n *\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\n * 1_000_000 = 100% max move per slot.\n *\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\n *\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\n */\nexport interface SetOraclePriceCapArgs {\n maxChangeE2bps: bigint | string;\n}\n\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\n}\n\n/**\n * ResolveMode constants — retained for source compatibility with v12.x callers.\n *\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\n * no longer encoded into the instruction data. They may be used in logging or\n * off-chain logic but must not be passed to encodeResolveMarket.\n */\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\n\n/**\n * ResolveMarket instruction data.\n *\n * v17 wire: tag(1) only — 1 byte total.\n *\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\n * next read in a subsequent call, corrupting the instruction stream.\n *\n * The `mode` argument is accepted for source compatibility but is silently ignored.\n *\n * @example\n * ```ts\n * const data = encodeResolveMarket();\n * ```\n */\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\n return new Uint8Array([IX_TAG.ResolveMarket]);\n}\n\n/**\n * WithdrawInsurance instruction data.\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\n * 1-byte payload fails on devnet/mainnet.\n *\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\n *\n * @param amount Amount to withdraw from the insurance fund (u128).\n *\n * @example\n * ```ts\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\n * ```\n */\nexport interface WithdrawInsuranceArgs {\n amount: bigint | string;\n}\n\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\n}\n\n/**\n * AdminForceClose instruction data (3 bytes)\n * Force-close any position at oracle price (admin only, skips margin checks).\n */\nexport interface AdminForceCloseArgs {\n targetIdx: number;\n}\n\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\n}\n\n/**\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\n * Use encodeSetInsuranceWithdrawPolicy instead.\n */\nexport interface UpdateRiskParamsArgs {\n initialMarginBps: bigint | string;\n maintenanceMarginBps: bigint | string;\n tradingFeeBps?: bigint | string;\n}\n\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\n return removedInstruction(\n \"UpdateRiskParams\",\n IX_TAG.UpdateRiskParams,\n \"encodeSetInsuranceWithdrawPolicy()\",\n );\n}\n\n/**\n * On-chain confirmation code for RenounceAdmin (must match program constant).\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\n */\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\n\n/**\n * On-chain confirmation code for UnresolveMarket (must match program constant).\n */\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\n\n/**\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\n * Use encodeWithdrawInsuranceLimited instead.\n */\nexport function encodeRenounceAdmin(): Uint8Array {\n return removedInstruction(\n \"RenounceAdmin\",\n IX_TAG.RenounceAdmin,\n \"encodeWithdrawInsuranceLimited()\",\n );\n}\n\n// ============================================================================\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\n// ============================================================================\n\n/**\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\n * withdraw proportional collateral.\n *\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\n *\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\n *\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\n * [0] withdrawer signer\n * [1] slab writable\n * [2] withdrawerAta writable\n * [3] vault writable\n * [4] tokenProgram\n * [5] lpVaultMint writable\n * [6] withdrawerLpAta writable\n * [7] vaultAuthority\n * [8] lpVaultState writable\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\n *\n * @param lpAmount - Amount of LP vault tokens to burn.\n *\n * @example\n * ```ts\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\n *\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\n *\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\n * });\n * ```\n */\nexport interface LpVaultWithdrawArgs {\n /** Amount of LP vault tokens to burn. */\n lpAmount: bigint | string;\n}\n\n/**\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\n */\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\n return removedInstruction(\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\n IX_TAG.LpVaultWithdraw,\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\n );\n}\n\n/**\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\n */\nexport function encodePauseMarket(): Uint8Array {\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\n}\n\n/**\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\n */\nexport function encodeUnpauseMarket(): Uint8Array {\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\n}\n\n// ============================================================================\n// PERC-117: Pyth Oracle CPI Instructions\n// ============================================================================\n\n/**\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\n * Sending this instruction will fail with InvalidInstructionData.\n */\nexport interface SetPythOracleArgs {\n feedId: Uint8Array;\n maxStalenessSecs: bigint;\n confFilterBps: number;\n}\n\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\n void args;\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\n}\n\n/**\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\n *\n * @param feedId 32-byte Pyth feed ID\n * @param shardId Shard index (default 0 for mainnet/devnet)\n */\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\n\nexport async function derivePythPriceUpdateAccount(\n feedId: Uint8Array,\n shardId = 0,\n): Promise {\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\n }\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\n }\n const { PublicKey } = await import('@solana/web3.js');\n const shardBuf = new Uint8Array(2);\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\n const [pda] = PublicKey.findProgramAddressSync(\n [shardBuf, feedId],\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\n );\n return pda.toBase58();\n}\n\n// SetPythOracle tag (32) is already defined in IX_TAG above.\n\n// PERC-118: Mark Price EMA Instructions\n// ============================================================================\n\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\n\n/**\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\n * Sending this instruction will fail with InvalidInstructionData.\n */\nexport function encodeUpdateMarkPrice(): Uint8Array {\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\n}\n\n/**\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\n */\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\n\n/**\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\n */\nexport function computeEmaMarkPrice(\n markPrevE6: bigint,\n oracleE6: bigint,\n dtSlots: bigint,\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\n capE2bps = 0n,\n): bigint {\n if (oracleE6 === 0n) return markPrevE6;\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\n\n let oracleClamped = oracleE6;\n if (capE2bps > 0n) {\n // Avoid overflow: divide early to reduce intermediate product\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\n const hi = markPrevE6 + maxDelta;\n if (oracleClamped < lo) oracleClamped = lo;\n if (oracleClamped > hi) oracleClamped = hi;\n }\n\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\n\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\n}\n\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\n// ============================================================================\n\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\n\n/**\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\n *\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\n * to authority_price_e6 on the slab.\n *\n * This is the core mechanism for permissionless token markets — no Pyth or\n * Chainlink feed is needed. The DEX AMM IS the oracle.\n *\n * Instruction data: 1 byte (tag only)\n *\n * Accounts:\n * 0. [writable] Slab\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\n */\nexport function encodeUpdateHyperpMark(): Uint8Array {\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\n return removedInstruction(\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\n 34,\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\n );\n}\n\n// ============================================================================\n// PERC-306: Per-Market Insurance Isolation\n// ============================================================================\n\n/**\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\n */\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\n}\n\n/**\n * Set insurance isolation BPS for a market.\n * Accounts: [admin(signer), slab(writable)]\n */\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\n void args;\n return removedInstruction(\n \"SetInsuranceIsolation\",\n IX_TAG.SetInsuranceIsolation,\n \"encodeFundMarketInsurance()\",\n );\n}\n\n// ============================================================================\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\n// ============================================================================\n\n// ============================================================================\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\n// ============================================================================\n\n/**\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\n *\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\n *\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\n *\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\n *\n * @example\n * ```ts\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\n * ```\n */\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\n}\n\n/**\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\n *\n * Burns LP tokens and releases one tranche of SOL to the user.\n * Call once per epoch until epochs_remaining == 0.\n *\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\n */\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\n}\n\n/**\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\n *\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\n * Use only to abandon a partial withdrawal.\n *\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\n */\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\n}\n\n// ============================================================================\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\n// ============================================================================\n\n/**\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\n *\n * Permissionless. Surgically closes or reduces `targetIdx` position when\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\n * the incentive is unblocking the market for normal trading.\n *\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\n *\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\n *\n * @param targetIdx - Account index of the position to deleverage.\n *\n * @example\n * ```ts\n * const data = encodeExecuteAdl({ targetIdx: 5 });\n * ```\n */\nexport interface ExecuteAdlArgs {\n targetIdx: number;\n}\n\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\n}\n\n// ============================================================================\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\n// ============================================================================\n\n/**\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\n *\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\n * whose size does not match any current valid tier.\n *\n * Accounts: [dest(signer,writable), slab(writable)]\n */\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\nexport function encodeCloseStaleSlabs(): Uint8Array {\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\n}\n\n/**\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\n *\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\n * The slab account must sign (proves the caller holds the slab keypair).\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\n *\n * Accounts: [dest(signer,writable), slab(signer,writable)]\n */\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\nexport function encodeReclaimSlabRent(): Uint8Array {\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\n}\n\n// ============================================================================\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\n// ============================================================================\n\n/**\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\n *\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\n * prevent DoS from transient failures).\n *\n * Accounts: [slab(writable)]\n *\n * @example\n * ```ts\n * const data = encodeAuditCrank();\n * ```\n */\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\nexport function encodeAuditCrank(): Uint8Array {\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\n}\n\n// ============================================================================\n// SMART PRICE ROUTER — quote computation for LP selection\n// ============================================================================\n\n/**\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\n */\nexport interface VammMatcherParams {\n mode: number; // 0 = Passive, 1 = vAMM\n tradingFeeBps: number;\n baseSpreadBps: number;\n maxTotalBps: number;\n impactKBps: number;\n liquidityNotionalE6: bigint;\n}\n\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\nexport const VAMM_MAGIC = 0x504552434d415443n;\n/** Alias matching the Rust constant name for parity tests */\nexport const MATCHER_MAGIC = VAMM_MAGIC;\n\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\nexport const CTX_RETURN_OFFSET = 0;\n/** Byte length of the MatcherReturn section of the context account */\nexport const MATCHER_RETURN_LEN = 64;\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\nexport const CTX_VAMM_OFFSET = 64;\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\nexport const CTX_VAMM_LEN = 256;\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\nexport const MATCHER_CONTEXT_LEN = 320;\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\nexport const MATCHER_CALL_LEN = 67;\n/**\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\n */\nexport const INIT_CTX_LEN = 78;\n\nconst BPS_DENOM = 10_000n;\n\n/**\n * Compute execution price for a given LP quote.\n * For buys (isLong=true): price above oracle.\n * For sells (isLong=false): price below oracle.\n */\nexport function computeVammQuote(\n params: VammMatcherParams,\n oraclePriceE6: bigint,\n tradeSize: bigint,\n isLong: boolean,\n): bigint {\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\n\n // Impact for vAMM mode\n let impactBps = 0n;\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\n }\n\n // Total = base_spread + trading_fee + impact, capped at max_total\n const maxTotal = BigInt(params.maxTotalBps);\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\n let totalBps = baseFee + clampedImpact;\n if (totalBps > maxTotal) totalBps = maxTotal;\n\n if (isLong) {\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\n } else {\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\n }\n}\n\n// ============================================================================\n// PERC-622: AdvanceOraclePhase (permissionless crank)\n// ============================================================================\n\n/**\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\n *\n * Checks if a market should transition from Phase 0→1→2 based on\n * time elapsed and cumulative volume. Anyone can call this.\n *\n * Instruction data: 1 byte (tag only)\n *\n * Accounts:\n * 0. [writable] Slab\n */\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\nexport function encodeAdvanceOraclePhase(): Uint8Array {\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\n}\n\n/** Oracle phase constants matching on-chain values */\nexport const ORACLE_PHASE_NASCENT = 0;\nexport const ORACLE_PHASE_GROWING = 1;\nexport const ORACLE_PHASE_MATURE = 2;\n\n/** Phase transition thresholds (must match program constants) */\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\n\n/**\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\n *\n * @returns [newPhase, shouldTransition]\n */\nexport function checkPhaseTransition(\n currentSlot: bigint,\n marketCreatedSlot: bigint,\n oraclePhase: number,\n cumulativeVolumeE6: bigint,\n phase2DeltaSlots: number,\n hasMatureOracle: boolean,\n): [number, boolean] {\n switch (oraclePhase) {\n case 0: {\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\n if (timeReady || volumeReady) {\n return [ORACLE_PHASE_GROWING, true];\n }\n return [ORACLE_PHASE_NASCENT, false];\n }\n case 1: {\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\n const elapsedSincePhase2 = currentSlot - phase2Start;\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\n return [ORACLE_PHASE_MATURE, true];\n }\n return [ORACLE_PHASE_GROWING, false];\n }\n default:\n return [ORACLE_PHASE_MATURE, false];\n }\n}\n\n// ============================================================================\n// PERC-629: Dynamic Creation Deposit\n// ============================================================================\n\n/**\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\n * after the spam grace period has elapsed (PERC-629).\n *\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\n * handler in the on-chain program. Sending this instruction will fail with\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\n *\n * Instruction data: 1 byte (tag only)\n *\n * Accounts:\n * 0. [signer] Caller (anyone)\n * 1. [] Slab\n * 2. [writable] Creator history PDA\n * 3. [writable] Insurance vault\n * 4. [writable] Treasury\n * 5. [] System program\n *\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\n */\nexport function encodeSlashCreationDeposit(): Uint8Array {\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\n}\n\n// ============================================================================\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\n// ============================================================================\n\n/**\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\n *\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\n *\n * Accounts:\n * 0. [signer] Admin\n * 1. [writable] Shared vault PDA\n * 2. [] System program\n */\nexport interface InitSharedVaultArgs {\n epochDurationSlots: bigint | string;\n maxMarketExposureBps: number;\n}\n\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\n}\n\n/**\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\n * to a market (PERC-628).\n *\n * Instruction data: tag(1) + amount(16) = 17 bytes\n *\n * Accounts:\n * 0. [signer] Admin\n * 1. [] Slab\n * 2. [writable] Shared vault PDA\n * 3. [writable] Market alloc PDA\n * 4. [] System program\n */\nexport interface AllocateMarketArgs {\n amount: bigint | string;\n}\n\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\n}\n\n/**\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\n *\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\n *\n * Accounts:\n * 0. [signer] User\n * 1. [writable] Shared vault PDA\n * 2. [writable] Withdraw request PDA\n * 3. [] System program\n */\nexport interface QueueWithdrawalSVArgs {\n lpAmount: bigint | string;\n}\n\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\n}\n\n/**\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\n *\n * Instruction data: 1 byte (tag only)\n *\n * Accounts:\n * 0. [signer] User\n * 1. [writable] Shared vault PDA\n * 2. [writable] Withdraw request PDA\n * 3. [] Slab\n * 4. [writable] Vault\n * 5. [writable] User ATA\n * 6. [] Vault authority\n * 7. [] Token program\n */\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\n}\n\n/**\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\n *\n * Instruction data: 1 byte (tag only)\n *\n * Accounts:\n * 0. [signer] Caller (anyone)\n * 1. [writable] Shared vault PDA\n */\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\nexport function encodeAdvanceEpoch(): Uint8Array {\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\n}\n\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\n\n// PERC-8110 ────────────────────────────────────────────────────────────────\n\n/**\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\n *\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\n *\n * - `threshold_bps = 0`: hard block disabled.\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\n *\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\n *\n * Accounts:\n * 0. [signer] admin\n * 1. [writable] slab\n *\n * @example\n * ```ts\n * const ix = new TransactionInstruction({\n * programId: PROGRAM_ID,\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\n * });\n * ```\n */\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\n}\n\n// ============================================================================\n// PERC-608 — Position NFT instructions (tags 64–69)\n// ============================================================================\n\n/**\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\n *\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\n *\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\n * program creates it, so the ATA can't be created in a preceding instruction.\n *\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\n *\n * Accounts (11):\n * 0. [signer, writable] payer\n * 1. [writable] slab\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\n * 5. [signer] owner (must match engine account owner)\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\n * 8. [] system_program\n * 9. [] rent sysvar\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\n */\nexport interface MintPositionNftArgs {\n userIdx: number;\n}\n\n/**\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\n */\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\n return removedInstruction(\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\n IX_TAG.MintPositionNft,\n \"percolator-nft program\",\n );\n}\n\n/**\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\n *\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\n * engine account's owner field. Requires `pending_settlement == 0`.\n *\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\n *\n * Accounts:\n * 0. [signer, writable] current_owner\n * 1. [writable] slab\n * 2. [writable] position_nft PDA\n * 3. [writable] nft_mint PDA\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\n * 6. [] new_owner\n * 7. [] token_2022_program\n */\nexport interface TransferPositionOwnershipArgs {\n userIdx: number;\n}\n\n/**\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\n */\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\n return removedInstruction(\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\n IX_TAG.TransferPositionOwnership,\n \"encodeTransferPortfolioOwnership() (tag 72)\",\n );\n}\n\n/**\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\n *\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\n * Can only be called after the position is fully closed (size == 0).\n *\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\n *\n * Accounts:\n * 0. [signer, writable] owner\n * 1. [writable] slab\n * 2. [writable] position_nft PDA (closed — rent to owner)\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\n * 5. [] vault_authority PDA\n * 6. [] token_2022_program\n */\nexport interface BurnPositionNftArgs {\n userIdx: number;\n}\n\n/**\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\n * NFT burn is handled by the standalone percolator-nft program in v17.\n */\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\n return removedInstruction(\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\n IX_TAG.BurnPositionNft,\n \"percolator-nft program\",\n );\n}\n\n/**\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\n *\n * Called by the keeper/admin before performing a funding settlement transfer.\n * Blocks NFT transfers until ClearPendingSettlement is called.\n * Admin-only (protected by GH#1475 keeper allowlist guard).\n *\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\n *\n * Accounts:\n * 0. [signer] keeper / admin\n * 1. [] slab (read — for PDA verification + admin check)\n * 2. [writable] position_nft PDA\n */\nexport interface SetPendingSettlementArgs {\n userIdx: number;\n}\n\n/**\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\n */\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\n return removedInstruction(\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\n IX_TAG.SetPendingSettlement,\n \"percolator-nft program\",\n );\n}\n\n/**\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\n *\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\n * Admin-only (protected by GH#1475 keeper allowlist guard).\n *\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\n *\n * Accounts:\n * 0. [signer] keeper / admin\n * 1. [] slab (read — for PDA verification + admin check)\n * 2. [writable] position_nft PDA\n */\nexport interface ClearPendingSettlementArgs {\n userIdx: number;\n}\n\n/**\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\n */\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\n return removedInstruction(\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\n IX_TAG.ClearPendingSettlement,\n \"percolator-nft program\",\n );\n}\n\n/**\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\n *\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\n * Updates the engine account's owner field to the new_owner public key.\n * NOT intended for direct external use — always called via Token-2022 CPI.\n *\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\n *\n * Accounts:\n * 0. [signer] nft TransferHook program (CPI caller)\n * 1. [writable] slab\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\n */\nexport interface TransferOwnershipCpiArgs {\n userIdx: number;\n newOwner: PublicKey | string;\n}\n\n/**\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\n */\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\n return removedInstruction(\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\n IX_TAG.TransferOwnershipCpi,\n \"percolator-nft transfer hook\",\n );\n}\n\n// ============================================================================\n// PERC-8111 — SetWalletCap (tag 70)\n// ============================================================================\n\n/**\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\n *\n * Limits the maximum absolute position size any single wallet may hold on this market.\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\n *\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\n * Phase 1 launch value: 1_000_000_000n ($1,000).\n *\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\n * (error code 58) is returned.\n *\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\n *\n * Accounts:\n * 0. [signer] admin\n * 1. [writable] slab\n *\n * @example\n * ```ts\n * // Set $1K per-wallet cap\n * const ix = new TransactionInstruction({\n * programId: PROGRAM_ID,\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\n * });\n *\n * // Disable cap\n * const disableIx = new TransactionInstruction({\n * programId: PROGRAM_ID,\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\n * });\n * ```\n */\nexport interface SetWalletCapArgs {\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\n capE6: bigint | string;\n}\n\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\n}\n\n// ============================================================================\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\n// ============================================================================\n\n/**\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\n *\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\n *\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\n * handler reads the LP portfolio's stored matcher config and verifies that:\n * cfg.matcher_program == matcherProg\n * cfg.matcher_context == matcherCtx\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\n *\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\n * check on the deployed binary. No client-side signer of the delegate is needed.\n *\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\n * [0] lp_owner signer (LP portfolio owner)\n * [1] market read-only (program-owned market slab)\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\n * [4] matcher_prog read-only, executable (the matcher program)\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\n *\n * @param args.kind 0=Passive, 1=vAMM\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\n * @param args.baseSpreadBps Base spread in bps (u32)\n * @param args.maxTotalBps Max total spread in bps (u32)\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\n *\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\n * this tag free.\n *\n * @example\n * ```ts\n * const data = encodeInitMatcherCtx({\n * kind: 0, // Passive\n * tradingFeeBps: 30,\n * baseSpreadBps: 50,\n * maxTotalBps: 200,\n * impactKBps: 0,\n * liquidityNotionalE6: 0n,\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\n * feeToInsuranceBps: 0,\n * skewSpreadMultBps: 0,\n * });\n * ```\n */\nexport interface InitMatcherCtxArgs {\n /**\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\n */\n lpIdx?: number;\n /** Matcher kind: 0=Passive, 1=vAMM. */\n kind: number;\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\n tradingFeeBps: number;\n /** Base spread in bps (u32). */\n baseSpreadBps: number;\n /** Max total spread in bps (u32). */\n maxTotalBps: number;\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\n impactKBps: number;\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\n liquidityNotionalE6: bigint | string;\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\n maxFillAbs: bigint | string;\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\n maxInventoryAbs: bigint | string;\n /** Fraction of fees routed to insurance fund in bps (u16). */\n feeToInsuranceBps: number;\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\n skewSpreadMultBps: number;\n}\n\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\n\n/**\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\n *\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\n *\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\n * @returns 70-byte Uint8Array\n */\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\n const data = concatBytes(\n encU8(83), // IX_TAG.InitMatcherCtx = 83\n encU8(args.kind),\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\n encU128(args.liquidityNotionalE6), // u128 LE\n encU128(args.maxFillAbs), // u128 LE\n encU128(args.maxInventoryAbs), // u128 LE\n encU16(args.feeToInsuranceBps), // u16 LE\n encU16(args.skewSpreadMultBps), // u16 LE\n );\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\n throw new Error(\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\n );\n }\n return data;\n}\n\n// ============================================================================\n// Missing encoders — corrected tag mappings (tags 22-74)\n// ============================================================================\n\n/**\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\n */\nexport interface SetInsuranceWithdrawPolicyArgs {\n authority: PublicKey | string;\n minWithdrawBase: bigint | string;\n maxWithdrawBps: number;\n cooldownSlots: bigint | string;\n}\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\n}\n\n/**\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\n */\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\n}\n\n/**\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\n */\nexport function encodeResolvePermissionless(): Uint8Array {\n return removedInstruction(\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\n IX_TAG.ResolvePermissionless,\n \"encodeResolveStalePermissionless()\",\n );\n}\n\n/**\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\n * This function throws at runtime to prevent silent on-chain mismatch.\n */\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\n return removedInstruction(\n \"ForceCloseResolved\",\n IX_TAG.ForceCloseResolved,\n \"encodeCloseResolved() for v17\",\n );\n}\n\n/**\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\n */\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\n return removedInstruction(\n \"encodeCreateLpVault (v12 format)\",\n IX_TAG.CreateLpVault,\n \"encodeCreateLpVaultV17()\",\n );\n}\n\n/**\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\n */\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\n return removedInstruction(\n \"encodeLpVaultDeposit (v12 format)\",\n IX_TAG.LpVaultDeposit,\n \"encodeDepositToLpVault()\",\n );\n}\n\n/**\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\n */\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\n return removedInstruction(\n \"ChallengeSettlement\",\n IX_TAG.ChallengeSettlement,\n undefined,\n );\n}\n\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\n}\n\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\n}\n\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\n}\n\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\n}\n\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\n}\n\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\nexport function encodeRescueOrphanVault(): Uint8Array {\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\n}\n\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\nexport function encodeCloseOrphanSlab(): Uint8Array {\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\n}\n\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\n}\n\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\nexport function encodeCreateInsuranceMint(): Uint8Array {\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\n}\n\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\n}\n\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\n}\n\n// ============================================================================\n// Phase B admin setters (tags 78-81) — added 2026-04-17\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\n// ============================================================================\n\n/**\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\n * This function throws at runtime to prevent silent on-chain mismatch.\n */\nexport interface SetMaxPnlCapArgs {\n cap: bigint | string;\n}\n\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\n return removedInstruction(\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\n IX_TAG.SetMaxPnlCap,\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\n );\n}\n\n/**\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\n */\nexport interface SetOiCapMultiplierArgs {\n packed: bigint | string;\n}\n\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\n return removedInstruction(\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\n IX_TAG.SetOiCapMultiplier,\n \"encodeSetLpVaultPaused() [if you meant v17]\",\n );\n}\n\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\n }\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\n }\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\n}\n\n/**\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\n */\nexport interface SetDisputeParamsArgs {\n windowSlots: bigint | string;\n bondAmount: bigint | string;\n}\n\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\n return removedInstruction(\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\n IX_TAG.SetDisputeParams,\n \"encodeCloseLpVault() [if you meant v17]\",\n );\n}\n\n/**\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\n */\nexport interface SetLpCollateralParamsArgs {\n enabled: number;\n ltvBps: number;\n}\n\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\n}\n\n/**\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\n */\nexport function encodeAcceptAdmin(): Uint8Array {\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\n}\n\n// ============================================================================\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\n// ============================================================================\n\n/**\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\n */\nexport interface ReclaimEmptyAccountArgs {\n userIdx: number;\n}\n\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\n}\n\n/**\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\n */\nexport interface SettleAccountArgs {\n userIdx: number;\n}\n\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\n}\n\n/**\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\n */\nexport interface DepositFeeCreditsArgs {\n userIdx: number;\n amount: bigint | string;\n}\n\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\n}\n\n/**\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\n * Owner only.\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\n * are identified by account key alone.\n *\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\n *\n * @param amount Amount of released PnL to convert (u128).\n *\n * @example\n * ```ts\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\n * ```\n */\nexport interface ConvertReleasedPnlArgs {\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\n userIdx?: number;\n amount: bigint | string;\n}\n\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.ConvertReleasedPnl),\n encU128(args.amount),\n );\n}\n\n// ============================================================================\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\n// ============================================================================\n\n/**\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\n *\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\n *\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\n * Burning marketauth to zero is rejected on-chain.\n *\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\n *\n * @example\n * ```ts\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\n * ```\n */\nexport interface UpdateAuthorityArgs {\n newPubkey: PublicKey | string;\n}\n\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateAuthority),\n encPubkey(args.newPubkey),\n );\n}\n\n// ============================================================================\n// v17 NEW — UpdateAssetAuthority (tag 65)\n// ============================================================================\n\n/**\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\n *\n * Exact mapping from v16_program.rs lines 5246-5250:\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\n * ASSET_AUTH_INSURANCE = 1 → Insurance\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\n * ASSET_AUTH_ORACLE = 4 → Oracle\n *\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\n * slot. Wrong values silently corrupt authority state:\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\n * corrupting the market-level admin key instead.\n *\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\n * the stake vault PDA into the asset_admin authority slot.\n */\nexport const ASSET_AUTH_KIND = {\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\n AssetAdmin: 0,\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\n Insurance: 1,\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\n InsuranceOperator: 2,\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\n BackingBucket: 3,\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\n Oracle: 4,\n} as const;\nObject.freeze(ASSET_AUTH_KIND);\n\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\n\n/**\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\n *\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\n *\n * Gated by the asset's own asset_admin (can rotate any) or by the current\n * holder of that authority (self-rotation). Isolated to the given asset_index.\n *\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\n * @param kind ASSET_AUTH_KIND.* constant.\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\n *\n * @example\n * ```ts\n * // Rotate insurance authority for asset 0\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\n * const data = encodeUpdateAssetAuthority({\n * assetIndex: 0,\n * kind: ASSET_AUTH_KIND.Insurance,\n * newPubkey: newInsuranceKey,\n * });\n * ```\n */\nexport interface UpdateAssetAuthorityArgs {\n assetIndex: number;\n kind: AssetAuthKind;\n newPubkey: PublicKey | string;\n}\n\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateAssetAuthority),\n encU16(args.assetIndex),\n encU8(args.kind),\n encPubkey(args.newPubkey),\n );\n}\n\n// ============================================================================\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\n// ============================================================================\n\n/**\n * One leg of a BatchTradeNoCpi instruction.\n */\nexport interface BatchTradeNoCpiLeg {\n assetIndex: number;\n sizeQ: bigint | string;\n execPrice: bigint | string;\n feeBps: bigint | string;\n}\n\n/**\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\n *\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\n *\n * @param legs Array of up to 255 trade legs.\n *\n * @example\n * ```ts\n * const data = encodeBatchTradeNoCpi({ legs: [\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\n * ]});\n * ```\n */\nexport interface BatchTradeNoCpiArgs {\n legs: BatchTradeNoCpiLeg[];\n}\n\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\n if (feeBps > 10_000n) {\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\n }\n}\n\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\n if (args.legs.length === 0) {\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\n }\n if (args.legs.length > 255) {\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\n }\n\n const parts: Uint8Array[] = [\n encU8(IX_TAG.BatchTradeNoCpi),\n encU8(args.legs.length),\n ];\n\n for (const leg of args.legs) {\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\n parts.push(encU16(leg.assetIndex));\n parts.push(encI128(leg.sizeQ));\n parts.push(encU64(leg.execPrice));\n parts.push(encU64(leg.feeBps));\n }\n\n return concatBytes(...parts);\n}\n/**\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\n *\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\n *\n * @param legs Array of up to 255 CPI trade legs.\n *\n * @example\n * ```ts\n * const data = encodeBatchTradeCpi({ legs: [\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\n * ]});\n * ```\n */\n\nexport interface BatchTradeCpiLeg {\n assetIndex: number;\n sizeQ: bigint | string;\n feeBps: bigint | string;\n limitPrice: bigint | string;\n}\n\nexport interface BatchTradeCpiArgs {\n legs: BatchTradeCpiLeg[];\n}\n\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\n if (args.legs.length === 0) {\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\n }\n if (args.legs.length > 255) {\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\n }\n\n const parts: Uint8Array[] = [\n encU8(IX_TAG.BatchTradeCpi),\n encU8(args.legs.length),\n ];\n\n for (const leg of args.legs) {\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\n parts.push(encU16(leg.assetIndex));\n parts.push(encI128(leg.sizeQ));\n parts.push(encU64(leg.feeBps));\n parts.push(encU64(leg.limitPrice));\n }\n\n return concatBytes(...parts);\n}\n\n// ============================================================================\n// v17 NEW — SetMatcherConfig (tag 68)\n// ============================================================================\n\n/**\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\n *\n * Wire: tag(1) + enabled(u8) = 2 bytes.\n *\n * @param enabled 1 = enabled, 0 = disabled.\n *\n * @example\n * ```ts\n * const data = encodeSetMatcherConfig({ enabled: 1 });\n * ```\n */\nexport interface SetMatcherConfigArgs {\n enabled: number;\n}\n\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\n if (args.enabled !== 0 && args.enabled !== 1) {\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\n }\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\n}\n\n// ============================================================================\n// v17 NEW — RestartAssetOracle (tag 69)\n// ============================================================================\n\n/**\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\n *\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\n *\n * Used to un-stick a stale or hung oracle. Anyone can call this.\n *\n * @param assetIndex Asset/domain index.\n * @param nowSlot Current slot.\n * @param initialPrice Initial mark price in e6 units.\n *\n * @example\n * ```ts\n * const data = encodeRestartAssetOracle({\n * assetIndex: 0,\n * nowSlot: currentSlot,\n * initialPrice: 50_000_000_000n,\n * });\n * ```\n */\nexport interface RestartAssetOracleArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n initialPrice: bigint | string;\n}\n\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.RestartAssetOracle),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encU64(args.initialPrice),\n );\n}\n\n// ============================================================================\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\n// ============================================================================\n\n/**\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\n *\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\n *\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\n * asset_index is u16 (domain u8→u16 migration in v17).\n *\n * @param assetIndex Asset/domain index (u16, not u8).\n * @param amount Amount to withdraw (u128).\n *\n * @example\n * ```ts\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\n * ```\n */\nexport interface WithdrawInsuranceAssetArgs {\n assetIndex: number;\n amount: bigint | string;\n}\n\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawInsuranceAsset),\n encU16(args.assetIndex),\n encU128(args.amount),\n );\n}\n\n// ============================================================================\n// v17 NEW — LP-vault renumbered tags (74-80)\n// ============================================================================\n\n/**\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\n *\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\n *\n * @param feeShareBps LP vault fee share in bps (0-10000).\n * @param redemptionCooldownSlots Slots between redemption requests.\n * @param oiReservationThresholdBps OI reservation threshold in bps.\n * @param domain Asset/domain index (u16 in v17).\n *\n * @example\n * ```ts\n * const data = encodeCreateLpVault({\n * feeShareBps: 5000,\n * redemptionCooldownSlots: 21600n,\n * oiReservationThresholdBps: 8000,\n * domain: 0,\n * });\n * ```\n */\nexport interface CreateLpVaultArgs {\n feeShareBps: number;\n redemptionCooldownSlots: bigint | string;\n oiReservationThresholdBps: number;\n domain: number;\n}\n\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.CreateLpVault),\n encU16(args.feeShareBps),\n encU64(args.redemptionCooldownSlots),\n encU16(args.oiReservationThresholdBps),\n encU16(args.domain),\n );\n}\n\n/**\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\n *\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\n *\n * `domain` selects which pot of the vault's asset receives the backing and MUST\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\n * NAV across both pots, so the depositor is indifferent to the choice; routing\n * exists so new money can reach whichever pot the house is drawing on.\n *\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\n * and mint the depositor free shares at existing holders' expense.\n *\n * @example\n * ```ts\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\n * ```\n */\nexport function encodeDepositToLpVault(args: {\n amount: bigint | string;\n domain: number;\n}): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.DepositToLpVault),\n encU128(args.amount),\n encU16(args.domain),\n );\n}\n\n/**\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\n *\n * Wire: tag(1) + shares(u128) = 17 bytes.\n *\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\n * v17 uses shares u128 and a two-step request/execute redemption flow.\n *\n * @example\n * ```ts\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\n * ```\n */\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\n}\n\n/**\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\n *\n * Wire: tag(1) + domain(u16) = 3 bytes.\n *\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\n * available-principal stay COMBINED across both pots, so this does not change\n * what the redeemer is owed — only where the atoms come from. A redemption draws\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\n * cover it; rebalance (tag 91) first.\n *\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\n *\n * @example\n * ```ts\n * const data = encodeExecuteRedemption({ domain: 2 });\n * ```\n */\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\n}\n\n/**\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\n *\n * Wire: tag(1) + domain(u16) = 3 bytes.\n *\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\n * choice cannot dilute; routing exists so fees can become backing in the pot\n * that needs it. The target ledger is created on first use.\n *\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\n * index 5 is the system program (needed to create a missing target ledger).\n *\n * @example\n * ```ts\n * const data = encodeLpVaultCrankFees({ domain: 2 });\n * ```\n */\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\n}\n\n/**\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\n * the LP vault's asset.\n *\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\n *\n * Permissionless: both pots belong to the same vault, so the move cannot extract\n * value, and the source-side gate refuses anything that would leave the source\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\n * open interest, already consumed, or impaired stays put.\n *\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\n * systemProgram]. The destination ledger is created on first arrival.\n *\n * @example\n * ```ts\n * const data = encodeRebalanceLpVaultBacking({\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\n * });\n * ```\n */\nexport function encodeRebalanceLpVaultBacking(args: {\n fromDomain: number;\n toDomain: number;\n amount: bigint | string;\n}): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.RebalanceLpVaultBacking),\n encU16(args.fromDomain),\n encU16(args.toDomain),\n encU128(args.amount),\n );\n}\n\n/**\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\n *\n * Wire: tag(1) + paused(u8) = 2 bytes.\n *\n * @param paused 1 = paused, 0 = active.\n *\n * @example\n * ```ts\n * const data = encodeSetLpVaultPaused({ paused: 1 });\n * ```\n */\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\n}\n\n/**\n * CloseLpVault (tag 80) — close an empty LP vault.\n *\n * Wire: tag(1) = 1 byte.\n *\n * @example\n * ```ts\n * const data = encodeCloseLpVault();\n * ```\n */\nexport function encodeCloseLpVault(): Uint8Array {\n return encU8(IX_TAG.CloseLpVault);\n}\n\n// ============================================================================\n// v17 NFT / B-3 (tags 72/73) — kept from v16\n// ============================================================================\n\n/**\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\n *\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\n *\n * @param newOwner New owner pubkey.\n * @param assetIndex Asset/domain index.\n *\n * @example\n * ```ts\n * const data = encodeTransferPortfolioOwnership({\n * newOwner: newOwnerKey,\n * assetIndex: 0,\n * });\n * ```\n */\nexport interface TransferPortfolioOwnershipArgs {\n newOwner: PublicKey | string;\n assetIndex: number;\n}\n\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.TransferPortfolioOwnership),\n encPubkey(args.newOwner),\n encU16(args.assetIndex),\n );\n}\n\n/**\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\n *\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\n *\n * @param nftProgramId Pubkey of the percolator-nft program.\n *\n * @example\n * ```ts\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\n * ```\n */\nexport interface SetNftProgramIdArgs {\n nftProgramId: PublicKey | string;\n}\n\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.SetNftProgramId),\n encPubkey(args.nftProgramId),\n );\n}\n\n// ============================================================================\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\n// ============================================================================\n\n/**\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\n *\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\n *\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\n *\n * Constraints (from v16_program.rs:10419-10435):\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\n * - hybrid_soft_stale_slots > 0\n * - invert ∈ {0, 1}\n * - Caller must be the asset's oracle_authority\n *\n * @param assetIndex Asset slot index (u16).\n * @param nowSlot Current on-chain slot (u64).\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\n * @param oracleLegCount Number of active oracle legs (1–3).\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\n * @param markMinFee Minimum fee charged per mark-price update.\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\n * @param unitScale Unit scaling factor (u32).\n * @param confFilterBps Confidence filter in basis points (u16).\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\n *\n * @example\n * ```ts\n * const data = encodeConfigureHybridOracle({\n * assetIndex: 1,\n * nowSlot: 300000000n,\n * nowUnixTs: 1700000000n,\n * oracleLegCount: 1,\n * oracleLegFlags: 0,\n * maxStalenessSecs: 60n,\n * hybridSoftStaleSlots: 100n,\n * markEwmaHalflifeSlots: 500n,\n * markMinFee: 0n,\n * invert: 0,\n * unitScale: 1000000,\n * confFilterBps: 200,\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\n * });\n * assert(data.length === 156);\n * ```\n */\nexport interface ConfigureHybridOracleArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n nowUnixTs: bigint | string;\n oracleLegCount: number;\n oracleLegFlags: number;\n maxStalenessSecs: bigint | string;\n hybridSoftStaleSlots: bigint | string;\n markEwmaHalflifeSlots: bigint | string;\n markMinFee: bigint | string;\n invert: number;\n unitScale: number;\n confFilterBps: number;\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\n}\n\nconst ORACLE_LEG_CAP = 3;\n\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\n }\n return concatBytes(\n encU8(IX_TAG.ConfigureHybridOracle),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encI64(args.nowUnixTs),\n encU8(args.oracleLegCount),\n encU8(args.oracleLegFlags),\n encU64(args.maxStalenessSecs),\n encU64(args.hybridSoftStaleSlots),\n encU64(args.markEwmaHalflifeSlots),\n encU64(args.markMinFee),\n encU8(args.invert),\n encU32(args.unitScale),\n encU16(args.confFilterBps),\n encPubkey(args.oracleLegFeeds[0]),\n encPubkey(args.oracleLegFeeds[1]),\n encPubkey(args.oracleLegFeeds[2]),\n );\n}\n\n/**\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\n *\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\n *\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\n *\n * Constraints (from v16_program.rs:10558-10563):\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\n * - mark_ewma_halflife_slots > 0\n * - Caller must be the asset's oracle_authority\n *\n * @param assetIndex Asset slot index (u16).\n * @param nowSlot Current on-chain slot (u64).\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\n * @param markMinFee Minimum fee charged per mark-price update (u64).\n *\n * @example\n * ```ts\n * const data = encodeConfigureEwmaMark({\n * assetIndex: 1,\n * nowSlot: 300000000n,\n * initialMarkE6: 50000000000n,\n * markEwmaHalflifeSlots: 500n,\n * markMinFee: 0n,\n * });\n * assert(data.length === 35);\n * ```\n */\nexport interface ConfigureEwmaMarkArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n initialMarkE6: bigint | string;\n markEwmaHalflifeSlots: bigint | string;\n markMinFee: bigint | string;\n}\n\nfunction requirePositiveU64(value: bigint | string, field: string): void {\n const n = typeof value === \"string\" ? BigInt(value) : value;\n if (n <= 0n) {\n throw new Error(`${field} must be > 0`);\n }\n}\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\n\n return concatBytes(\n encU8(IX_TAG.ConfigureEwmaMark),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encU64(args.initialMarkE6),\n encU64(args.markEwmaHalflifeSlots),\n encU64(args.markMinFee),\n );\n}\n\n/**\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\n *\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\n *\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\n *\n * Constraints (from v16_program.rs:10771):\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\n * - Caller must be the asset's oracle_authority\n * - now_slot ≥ last EWMA slot and current market slot\n *\n * @param assetIndex Asset slot index (u16).\n * @param nowSlot Current on-chain slot (u64).\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\n *\n * @example\n * ```ts\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\n * assert(data.length === 19);\n * ```\n */\nexport interface PushEwmaMarkArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n markE6: bigint | string;\n}\n\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\n requirePositiveU64(args.markE6, \"markE6\");\n\n return concatBytes(\n encU8(IX_TAG.PushEwmaMark),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encU64(args.markE6),\n );\n}\n\n/**\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\n *\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\n *\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\n *\n * Constraints (from v16_program.rs:10665):\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\n * - Caller must be the asset's oracle_authority\n *\n * @param assetIndex Asset slot index (u16).\n * @param nowSlot Current on-chain slot (u64).\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\n *\n * @example\n * ```ts\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\n * assert(data.length === 19);\n * ```\n */\nexport interface ConfigureAuthMarkArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n initialMarkE6: bigint | string;\n}\n\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\n\n return concatBytes(\n encU8(IX_TAG.ConfigureAuthMark),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encU64(args.initialMarkE6),\n );\n}\n\n/**\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\n *\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\n *\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\n *\n * Constraints (from v16_program.rs:10847):\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\n * - Caller must be the asset's oracle_authority\n * - now_slot ≥ last EWMA slot and current market slot\n *\n * @param assetIndex Asset slot index (u16).\n * @param nowSlot Current on-chain slot (u64).\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\n *\n * @example\n * ```ts\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\n * assert(data.length === 19);\n * ```\n */\nexport interface PushAuthMarkArgs {\n assetIndex: number;\n nowSlot: bigint | string;\n markE6: bigint | string;\n}\n\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\n requirePositiveU64(args.markE6, \"markE6\");\n\n return concatBytes(\n encU8(IX_TAG.PushAuthMark),\n encU16(args.assetIndex),\n encU64(args.nowSlot),\n encU64(args.markE6),\n );\n}\n\n// ============================================================================\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\n// ============================================================================\n\n/**\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\n * to initialize a passive LP matcher context.\n *\n * This is NOT a wrapper instruction. Program = matcher program address.\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\n *\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\n * [0] = 2 (opcode: passive-LP init)\n * [1] = 0 (reserved)\n * [2..10] = 0 (8 bytes reserved)\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\n * [14..34] = 0 (20 bytes reserved)\n * [34..50] = max_fill_abs (u128 LE)\n * [50..66] = 0 (16 bytes reserved)\n * Total = 66 bytes\n *\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\n *\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\n *\n * @example\n * ```ts\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\n * assert(data.length === 66);\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\n * ```\n */\nexport interface MatcherInitPassiveArgs {\n maxFillAbs: bigint | string;\n}\n\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\n const buf = new Uint8Array(66);\n buf[0] = 2;\n buf[1] = 0;\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\n const u32Bytes = encU32(100);\n buf.set(u32Bytes, 10);\n // [34..50] = max_fill_abs u128 LE\n const u128Bytes = encU128(args.maxFillAbs);\n buf.set(u128Bytes, 34);\n return buf;\n}\n\n// ============================================================================\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\n// handle_set_protocol_fee_authority.\n//\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\n//\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\n// all — sending this encoded data to it would be rejected or misinterpreted.\n// ============================================================================\n\n/**\n * WithdrawProtocolFee instruction data (tag 84).\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\n *\n * Pays out from the accrued-but-unwithdrawn protocol claim\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\n * WrapperConfigV17) to an external token account. Signer-gated on\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\n * clamped to what's actually available on-chain (engine surplus, vault\n * balance) and only the actually-transferred amount is marked withdrawn —\n * this never errors solely because the ledger raced ahead of availability.\n *\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\n * currently-available capacity.\n *\n * @example\n * ```ts\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\n * ```\n */\nexport interface WithdrawProtocolFeeArgs {\n amount: bigint | string;\n}\n\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawProtocolFee),\n encU128(args.amount),\n );\n}\n\n/**\n * SetProtocolFeeAuthority instruction data (tag 85).\n *\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\n *\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\n * marketauth/insurance_authority/any creator-facing gate) — see\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\n * a keeper script iterates markets for a mass rotation.\n *\n * @param newAuthority New protocol-fee-authority pubkey.\n *\n * @example\n * ```ts\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\n * ```\n */\nexport interface SetProtocolFeeAuthorityArgs {\n newAuthority: PublicKey;\n}\n\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.SetProtocolFeeAuthority),\n encPubkey(args.newAuthority),\n );\n}\n\n// ============================================================================\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\n// ============================================================================\n\n/**\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\n *\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\n * three stored shares below, which are bps *of T* and must sum to exactly\n * `FEE_SHARE_TOTAL_BPS`.\n *\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\n * above its ceiling necessarily drags another leg under its floor.\n *\n * Defaults are written unconditionally at InitMarket and are never instruction\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\n * legs correctly from its first trade.\n */\nexport const FEE_SPLIT = {\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\n PROTOCOL_FEE_BPS: 2000,\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\n FEE_SHARE_TOTAL_BPS: 8000,\n DEFAULT_CREATOR_SHARE_BPS: 1600,\n DEFAULT_LP_SHARE_BPS: 4800,\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\n MAX_CREATOR_SHARE_BPS: 3600,\n /** LP floor, bps of T (40% of the post-protocol remainder). */\n MIN_LP_SHARE_BPS: 3200,\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\n MIN_INSURANCE_SHARE_BPS: 1200,\n} as const;\nObject.freeze(FEE_SPLIT);\n\n/**\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\n * the split would be accepted on-chain, otherwise a human-readable reason.\n *\n * Provided so a wizard/UI can reject a bad split before paying for a\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\n * floors), so this is a convenience, never the security boundary.\n *\n * @param args The three candidate shares, in bps of T.\n * @returns `null` if valid, else a string describing the first violation.\n *\n * @example\n * ```ts\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\n * // => null (these are the on-chain defaults)\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\n * ```\n */\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\n }\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\n }\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\n }\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\n }\n return null;\n}\n\n/**\n * UpdateFeeSplit instruction data (tag 86).\n *\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\n * insurance_share_bps(u16 LE) = 7 bytes.\n *\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\n * {@link validateFeeSplit} to check before sending.\n *\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\n * top-level transaction and this tag is reachable only via the stake program's\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\n *\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\n * @returns 7-byte instruction data buffer.\n *\n * @example\n * ```ts\n * // Restore the on-chain defaults explicitly.\n * const data = encodeUpdateFeeSplit({\n * creatorShareBps: 1600,\n * lpShareBps: 4800,\n * insuranceShareBps: 1600,\n * });\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\n * ```\n */\nexport interface UpdateFeeSplitArgs {\n creatorShareBps: number;\n lpShareBps: number;\n insuranceShareBps: number;\n}\n\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateFeeSplit),\n encU16(args.creatorShareBps),\n encU16(args.lpShareBps),\n encU16(args.insuranceShareBps),\n );\n}\n\n/**\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\n *\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\n * clamped on-chain to engine-available surplus, and the destination is derived\n * rather than passed.\n *\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\n * PINNED stake program id, so there is nothing for a caller to redirect.\n *\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\n * resolution.\n *\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\n * stake deployment.\n *\n * @returns 1-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeWithdrawInsuranceReserveToStake();\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\n * ```\n */\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\n}\n\n/**\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\n *\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\n *\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\n * wrapper rejects the instruction outright.\n *\n * Gated on `cfg.marketauth`. The wrapper range-checks against\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\n * exceeded — the same bound InitMarket applies.\n *\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\n *\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\n * (maintenance fee disabled).\n * @returns 17-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\n * ```\n */\nexport interface UpdateMaintenanceFeePerSlotArgs {\n maintenanceFeePerSlot: bigint | string;\n}\n\nexport function encodeUpdateMaintenanceFeePerSlot(\n args: UpdateMaintenanceFeePerSlotArgs,\n): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\n encU128(args.maintenanceFeePerSlot),\n );\n}\n\n/**\n * UpdateTradeFeePolicy instruction data (tag 55).\n *\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\n *\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\n * (stake tag 28).\n *\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\n * with `read_u128`.\n *\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\n * which left stake tag 28's CPI target unrepresentable from the SDK.\n *\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\n * @returns 9-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\n * ```\n */\nexport interface UpdateTradeFeePolicyArgs {\n tradeFeeBaseBps: bigint | string;\n}\n\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.UpdateTradeFeePolicy),\n encU64(args.tradeFeeBaseBps),\n );\n}\n\n/**\n * ExpireBackingBucket instruction data (tag 89).\n *\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\n * domain: read_u16(&mut rest)? }`) followed by the shared\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\n *\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\n * authority to hold.\n *\n * ## Why this exists\n *\n * A realized loss reserves capital as counterparty backing, which opens the\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\n * END in all three directions, permanently:\n *\n * - settling a GAIN against it -> Custom(19) EngineStale\n * - reserving a further LOSS -> Custom(21) EngineLockActive\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\n *\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\n * no call site that reached the engine's own escape hatch\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\n * good. Tag 89 IS that missing call site.\n *\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\n *\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\n * once when the bucket opens and is never extended. Seeding a long horizon\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\n * incident-response tool: a keeper should scan live markets for domains whose\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\n * nobody cranks it, the first lapse silently bricks the domain and the failure\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\n * settlement.\n *\n * ## Safety\n *\n * Permissionless is not an authority hole. The engine refuses the transition\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\n * is read from the runtime `Clock` (via\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\n * — so no caller can force an early forfeiture. Moves no tokens.\n *\n * Expiry forfeits the lapsed principal to the junior pool. That is the\n * engine's documented expiry semantics, not a haircut invented by this\n * instruction; the alternative is the account never settling at all.\n *\n * ## Failure modes\n *\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\n * resolved/wound-down path reaches the transition through the engine's own\n * resolved-close sweep, so re-entering it from outside is refused.\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\n * speculatively on a healthy domain is safe (it just reverts).\n *\n * @param domain Backing-bucket domain index (2*assetIndex for long,\n * 2*assetIndex+1 for short), u16. Must be\n * `< 2 * max_market_slots`.\n * @returns 3-byte instruction data buffer.\n *\n * @example\n * ```ts\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\n * const data = encodeExpireBackingBucket({ domain: 0 });\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\n * // beyond the fee payer.\n * ```\n */\nexport interface ExpireBackingBucketArgs {\n domain: number;\n}\n\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.ExpireBackingBucket),\n encU16(args.domain),\n );\n}\n\n// ============================================================================\n// v17 CREATOR FEE CLAIM (tag 90)\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\n//\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\n// 576-byte config — see solana/slab.ts).\n// ============================================================================\n\n/**\n * WithdrawCreatorFee instruction data (tag 90).\n *\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\n * percolator-prog `src/v16_program.rs`:\n *\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\n * -> total length is EXACTLY 17; any trailing byte is rejected\n * encode arm: out.push(90); push_u128(&mut out, amount)\n *\n * Pays the market creator's accrued trade-fee share out of the market vault to\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\n * backstop): before this change the creator leg was credited INTO the backstop,\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\n * counter.\n *\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\n * `parseWrapperConfigV17` and pass that exact value.\n *\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\n * the whole instruction fails closed (EngineLockActive); retry with less.\n *\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\n * `cfg.marketauth`), so claiming still works on a staked market where\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\n *\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\n * u64, so anything above u64::MAX is an over-claim).\n *\n * @example\n * ```ts\n * const cfg = parseWrapperConfigV17(marketAccount.data);\n * // Drain the full claimable balance:\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\n * ```\n */\nexport interface WithdrawCreatorFeeArgs {\n amount: bigint | string;\n}\n\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\n return concatBytes(\n encU8(IX_TAG.WithdrawCreatorFee),\n encU128(args.amount),\n );\n}\n","import {\n PublicKey,\n AccountMeta,\n SYSVAR_CLOCK_PUBKEY,\n SYSVAR_RENT_PUBKEY,\n SystemProgram,\n} from \"@solana/web3.js\";\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\n\n/**\n * Account spec for building instruction account metas.\n * Each instruction has a fixed ordering that matches the Rust processor.\n */\nexport interface AccountSpec {\n name: string;\n signer: boolean;\n writable: boolean;\n}\n\n// ============================================================================\n// ACCOUNT ORDERINGS - Single source of truth\n// ============================================================================\n\n/**\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\n */\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"mint\", signer: false, writable: false },\n { name: \"vault\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n { name: \"rent\", signer: false, writable: false },\n { name: \"dummyAta\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * InitPortfolio (tag 2): 3 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\n * [0] owner signer, writable (portfolio owner; pays for alloc)\n * [1] market writable (market-group slab; must be program-owned)\n * [2] portfolio writable (portfolio PDA; must be program-owned)\n *\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\n * InitPortfolio does not transfer collateral and does not read the clock.\n */\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n] as const;\n\n/**\n * InitLP: 6 accounts\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\n * [0] user signer, writable (LP owner; pays fee)\n * [1] slab writable\n * [2] userAta writable (collateral source for fee)\n * [3] vault writable (collateral destination)\n * [4] tokenProgram read-only\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\n */\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"userAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * Deposit (tag 3): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_deposit):\n * [0] owner signer (portfolio owner)\n * [1] market writable (market-group slab; must be program-owned)\n * [2] portfolio writable (portfolio PDA; must be program-owned)\n * [3] sourceToken writable (owner's collateral ATA)\n * [4] vaultToken writable (program vault token account)\n * [5] tokenProgram read-only\n *\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\n */\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n { name: \"sourceToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * Withdraw (tag 4): 7 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw):\n * [0] owner signer (portfolio owner)\n * [1] market writable (market-group slab; must be program-owned)\n * [2] portfolio writable (portfolio PDA; must be program-owned)\n * [3] destToken writable (owner's collateral ATA — destination)\n * [4] vaultToken writable (program vault token account — source)\n * [5] vaultAuthority read-only (PDA that signs token CPI)\n * [6] tokenProgram read-only\n *\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\n */\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\n */\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\n { name: \"nftRegistry\", signer: false, writable: false },\n { name: \"positionNft\", signer: false, writable: false },\n { name: \"signerNftAta\", signer: false, writable: false },\n] as const;\n\n/**\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\n */\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\n}\n\n/**\n * KeeperCrank: 4 accounts\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\n */\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\n { name: \"caller\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\n/**\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\n *\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\n * [0] owner signer, writable (keeper key; receives liquidation reward)\n * [1] market writable (the market-group slab)\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\n *\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\n * the same program and have a different key from accounts[2].\n *\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\n * including oracle tail and optional keeper portfolio.\n */\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n] as const;\n\n/**\n * RestartAssetOracle (tag 69): 2 accounts.\n *\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\n * [0] authority signer (asset_admin for the target asset_index)\n * [1] market writable (the market-group slab)\n *\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\n * Permissionless in the sense that any holder of asset_admin can call it.\n */\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n\n/**\n * TradeNoCpi (tag 9): 5 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\n * [0] signerA signer, writable (party A — portfolio owner)\n * [1] signerB signer, writable (party B — portfolio owner)\n * [2] market writable (market-group slab; program-owned)\n * [3] accountA writable (portfolio A; program-owned)\n * [4] accountB writable (portfolio B; program-owned)\n *\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\n * signerB replaces lp (both portfolios must have live owner signers).\n */\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\n { name: \"signerA\", signer: true, writable: true },\n { name: \"signerB\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"accountA\", signer: false, writable: true },\n { name: \"accountB\", signer: false, writable: true },\n] as const;\n\n/**\n * LiquidateAtOracle: 4 accounts\n * Note: account[0] is unused but must be present\n */\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\n { name: \"unused\", signer: false, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\n/**\n * ClosePortfolio (tag 8): 3 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\n * [1] market writable (market-group slab; program-owned)\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\n *\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\n * portfolio and closes the account back to the market slab.\n */\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n] as const;\n\n/**\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\n *\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\n * [0] signer signer, writable (insurance authority for asset 0)\n * [1] market writable (market-group slab; program-owned)\n * [2] sourceToken writable (signer's collateral ATA — source)\n * [3] vaultToken writable (program vault token account — destination)\n * [4] tokenProgram read-only\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\n *\n * v12 stale accounts removed: clock sysvar (was at [5]).\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\n * per-authority deposit principals; omit for simple vault top-ups.\n */\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\n { name: \"signer\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"sourceToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\n *\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\n * [1] market writable (market-group slab; program-owned)\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\n * [3] vaultToken writable (program vault token account — destination)\n * [4] tokenProgram read-only\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\n * omit for a simple top-up with no ledger tracking)\n *\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\n */\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\n { name: \"signer\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"sourceToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\n * [1] market writable (market-group slab; program-owned)\n * [2] destToken writable (authority-OWNED token account — destination)\n * [3] vaultToken writable (program vault token account — source)\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\n * [5] tokenProgram read-only\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\n */\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\n *\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\n * so it stays callable by the creator wallet after the\n * launch flow rotates marketauth to the stake-pool PDA)\n * [1] market writable (market-group slab; program-owned)\n */\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\n * [1] market writable (market-group slab; program-owned)\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\n * unlike tag 50 where it is an optional tail)\n * [3] destToken writable (authority-OWNED token account — destination)\n * [4] vaultToken writable (program vault token account — source)\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\n * [6] tokenProgram read-only\n */\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"ledger\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\n *\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\n * [0] signerA signer (party A — portfolio owner)\n * [1] market writable (market-group slab; program-owned)\n * [2] accountA writable (portfolio A; program-owned)\n * [3] accountB writable (portfolio B; program-owned)\n * [4] matcherProg read-only, executable (matcher program)\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\n * [7+] tail additional accounts forwarded to matcher CPI\n *\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\n * market replaces slab name.\n */\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\n { name: \"signerA\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n { name: \"accountA\", signer: false, writable: true },\n { name: \"accountB\", signer: false, writable: true },\n { name: \"matcherProg\", signer: false, writable: false },\n { name: \"matcherCtx\", signer: false, writable: true },\n { name: \"matcherDelegate\", signer: false, writable: false },\n] as const;\n\n/**\n * SetRiskThreshold: 2 accounts\n */\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * UpdateAdmin: 2 accounts\n */\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * AcceptAdmin: 2 accounts (tag 82)\n * Second half of two-step admin transfer. The proposed new admin must sign to\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\n * [1] slab writable\n */\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\n { name: \"pendingAdmin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * CloseSlab: 6 accounts\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\n * [0] dest signer, writable (receives rent + drained vault tokens)\n * [1] slab writable\n * [2] vault writable (token account — drained)\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\n * [4] destAta writable (dest's token ATA receiving drained tokens)\n * [5] tokenProgram read-only\n */\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\n { name: \"dest\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"destAta\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\n * 3-account form: [admin(s+w), slab(w), clock].\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\n * needs to re-read price during config commit). Default to the 3-account form;\n * callers that need oracle re-reads should append the oracle account themselves.\n */\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * SetMaintenanceFee: 2 accounts\n */\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * SetOraclePriceCap: 3 accounts.\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\n * Layout: [admin(s+w), slab(w), clock].\n */\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * ResolveMarket (tag 19): 2 accounts.\n *\n * v17 wire account layout, VERIFIED against the deployed wrapper\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\n * `handle_resolve_market` at src/v16_program.rs:12269:\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\n *\n * The v12.19 4-account layout this constant previously documented\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\n * clock account, and never touches an oracle account at all.\n *\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\n * also admin-gated, market-level, no token movement — which is\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\n * when the program does not require it only widens the account's write lock.\n */\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\n * [0] authority signer, writable (insurance authority)\n * [1] market writable (market-group slab; program-owned)\n * [2] destToken writable (authority's collateral ATA — destination)\n * [3] vaultToken writable (program vault token account — source)\n * [4] vaultAuthority read-only (PDA that signs token CPI)\n * [5] tokenProgram read-only\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\n *\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\n */\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\n * the handler does a same-instruction accrue_market_to against the fresh\n * oracle price to prevent withdrawals against overstated insurance.\n * On resolved markets the oracle is frozen — 7 accounts suffice.\n */\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"authorityAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"vaultPda\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\n/**\n * PauseMarket: 2 accounts\n */\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * UnpauseMarket: 2 accounts\n */\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\n// (set_insurance_withdraw_policy), 6876 (update_authority).\n// ============================================================================\n\n/**\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\n * Wrapper: src/percolator.rs:10470.\n */\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * SettleAccount (tag 26): 3 accounts. Permissionless.\n * Wrapper: src/percolator.rs:10503.\n */\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\n/**\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\n */\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"userAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\n * Owner only. No token movement (internal PnL-bucket conversion within the\n * same portfolio).\n *\n * v17 wire account layout, VERIFIED against the deployed wrapper\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\n * at src/v16_program.rs:17469, which reads:\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\n * [1] market writable — `expect_writable` + `expect_owner`\n * [2] portfolio writable — `expect_writable` + `expect_owner`\n *\n * The v12.19 4-account layout this constant previously documented\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\n * is no clock account (the handler needs no slot) and no oracle account.\n *\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\n * portfolio rent — this instruction moves no lamports at all.\n *\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\n */\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n { name: \"portfolio\", signer: false, writable: true },\n] as const;\n\n/**\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\n * Wrapper: src/percolator.rs:9990.\n */\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\n * Wrapper: src/percolator.rs:6876.\n *\n * Both the current authority and the new authority must sign. For burn\n * (`new_pubkey == default()`) the new account is still passed but does\n * not need to sign per wrapper L7036 region.\n */\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\n { name: \"currentAuthority\", signer: true, writable: false },\n { name: \"newAuthority\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// ACCOUNT META BUILDERS\n// ============================================================================\n\n/**\n * Build AccountMeta array from spec and provided pubkeys.\n *\n * Accepts either:\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\n * - `Record` — named map keyed by account `name` (preferred form)\n *\n * Named-map form resolves accounts by spec name so callers don't have to\n * remember the positional order, and errors clearly on missing names.\n */\nexport function buildAccountMetas(\n spec: readonly AccountSpec[],\n keys: PublicKey[] | Record\n): AccountMeta[] {\n let keysArray: PublicKey[];\n\n if (Array.isArray(keys)) {\n keysArray = keys;\n } else {\n // Named map: resolve by spec name\n keysArray = spec.map((s) => {\n const key = (keys as Record)[s.name];\n if (!key) {\n throw new Error(\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\n );\n }\n return key;\n });\n }\n\n if (keysArray.length !== spec.length) {\n throw new Error(\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\n );\n }\n return spec.map((s, i) => ({\n pubkey: keysArray[i],\n isSigner: s.signer,\n isWritable: s.writable,\n }));\n}\n\n/**\n * CreateInsuranceMint: 9 accounts\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\n */\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: false },\n { name: \"insLpMint\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"collateralMint\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"rent\", signer: false, writable: false },\n { name: \"payer\", signer: true, writable: true },\n] as const;\n\n/**\n * DepositInsuranceLP: 8 accounts\n * Deposit collateral into insurance fund, receive LP tokens.\n */\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\n { name: \"depositor\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"depositorAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"insLpMint\", signer: false, writable: true },\n { name: \"depositorLpAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n] as const;\n\n/**\n * WithdrawInsuranceLP: 8 accounts\n * Burn LP tokens and withdraw proportional share of insurance fund.\n */\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\n { name: \"withdrawer\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"withdrawerAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"insLpMint\", signer: false, writable: true },\n { name: \"withdrawerLpAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\n// ============================================================================\n\n/**\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\n *\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\n *\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\n *\n * Accounts:\n * [0] withdrawer signer, read-only\n * [1] slab writable\n * [2] withdrawerAta writable (collateral destination)\n * [3] vault writable (collateral source)\n * [4] tokenProgram read-only\n * [5] lpVaultMint writable (LP tokens burned from here)\n * [6] withdrawerLpAta writable (LP tokens source)\n * [7] vaultAuthority read-only (PDA that signs token transfers)\n * [8] lpVaultState writable\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\n */\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\n { name: \"withdrawer\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"withdrawerAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"lpVaultMint\", signer: false, writable: true },\n { name: \"withdrawerLpAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"lpVaultState\", signer: false, writable: true },\n { name: \"creatorLockPda\", signer: false, writable: true },\n] as const;\n\n/**\n * FundMarketInsurance: 5 accounts (PERC-306)\n * Fund per-market isolated insurance balance.\n */\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"adminAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * SetInsuranceIsolation: 2 accounts (PERC-306)\n * Set max % of global fund this market can access.\n */\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\n// ============================================================================\n\n/**\n * QueueWithdrawal: 5 accounts (PERC-309)\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\n */\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"lpVaultState\", signer: false, writable: false },\n { name: \"withdrawQueue\", signer: false, writable: true },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\n * Burns LP tokens and releases one epoch tranche of SOL.\n */\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"withdrawQueue\", signer: false, writable: true },\n { name: \"lpVaultMint\", signer: false, writable: true },\n { name: \"userLpAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"userAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"lpVaultState\", signer: false, writable: true },\n] as const;\n\n/**\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\n */\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: false },\n { name: \"withdrawQueue\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\n// ============================================================================\n\n/**\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\n * Permissionless — surgically close/reduce the most profitable position\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\n * pass additional oracle accounts at accounts[4..].\n */\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\n { name: \"caller\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"ownerAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"ownerAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n { name: \"oracle\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\n// ============================================================================\n\n/**\n * CloseStaleSlabs: 2 accounts (tag 51)\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\n */\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\n { name: \"dest\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n/**\n * ReclaimSlabRent: 2 accounts (tag 52)\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\n */\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\n { name: \"dest\", signer: true, writable: true },\n { name: \"slab\", signer: true, writable: true },\n] as const;\n\n// ============================================================================\n// AuditCrank (tag 53) — Permissionless invariant check\n// ============================================================================\n\n/**\n * AuditCrank: 1 account (tag 53)\n * Permissionless. Verifies conservation invariants; pauses market on violation.\n */\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// PERC-622: AdvanceOraclePhase (permissionless)\n// ============================================================================\n\n/**\n * AdvanceOraclePhase: 1 account\n * Permissionless — no signer required beyond fee payer.\n */\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\n { name: \"slab\", signer: false, writable: true },\n { name: \"dexPool\", signer: false, writable: false },\n { name: \"clock\", signer: false, writable: false },\n] as const;\n\n/**\n * CreateLpVault (tag 74): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\n * [0] admin signer, writable (marketauth — pays for PDA creation)\n * [1] market read-only (market-group slab; program-owned)\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\n * [4] systemProgram read-only (required for create_account CPI)\n * [5] tokenProgram read-only\n *\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\n */\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"registry\", signer: false, writable: true },\n { name: \"lpMint\", signer: false, writable: true },\n { name: \"systemProgram\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * DepositToLpVault (tag 75): 10 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\n * [1] market writable (market-group slab; program-owned)\n * [2] registry writable (LpVaultRegistry PDA)\n * [3] lpMint writable (LP share mint PDA)\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\n * [5] sourceToken writable (depositor's collateral ATA — source)\n * [6] vaultToken writable (program vault token account — destination)\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\n * [8] tokenProgram read-only\n * [9] systemProgram read-only (required for ledger create_account CPI)\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\n *\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\n * and mints the depositor free shares at existing holders' expense. `ledger` at\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\n * which of the two actually receives the backing.\n *\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\n */\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\n { name: \"depositor\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"registry\", signer: false, writable: true },\n { name: \"lpMint\", signer: false, writable: true },\n { name: \"depositorLpAta\", signer: false, writable: true },\n { name: \"sourceToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"ledger\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n { name: \"siblingLedger\", signer: false, writable: true },\n] as const;\n\n/**\n * LpVaultCrankFees (tag 78): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\n * ledger must be created)\n * [1] market writable (market-group slab; program-owned)\n * [2] registry writable (LpVaultRegistry PDA)\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\n * [5] systemProgram read-only (required to create a missing target ledger)\n *\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\n * land in, and that pot's ledger is created on first use. Once deposits can be\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\n * so cranker had to become writable and the system program is now required.\n */\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\n { name: \"cranker\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"registry\", signer: false, writable: true },\n { name: \"ledger\", signer: false, writable: true },\n { name: \"siblingLedger\", signer: false, writable: true },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\n *\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\n * carrying ledger principal in lockstep. No tokens move.\n *\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\n * destination ledger must be created)\n * [1] market writable (market-group slab; program-owned)\n * [2] registry read-only (LpVaultRegistry PDA)\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\n * [5] systemProgram read-only\n */\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\n { name: \"cranker\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"registry\", signer: false, writable: false },\n { name: \"fromLedger\", signer: false, writable: true },\n { name: \"toLedger\", signer: false, writable: true },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\n { name: \"challenger\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"dispute\", signer: false, writable: true },\n { name: \"challengerAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"dispute\", signer: false, writable: true },\n { name: \"challengerAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"userLpAta\", signer: false, writable: true },\n { name: \"lpVaultMint\", signer: false, writable: false },\n { name: \"lpVaultState\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"lpEscrow\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\n { name: \"user\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"userLpAta\", signer: false, writable: true },\n { name: \"lpVaultMint\", signer: false, writable: false },\n { name: \"lpVaultState\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"lpEscrow\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slabA\", signer: false, writable: true },\n { name: \"slabB\", signer: false, writable: true },\n { name: \"pairPda\", signer: false, writable: true },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\n { name: \"payer\", signer: true, writable: true },\n { name: \"slabA\", signer: false, writable: true },\n { name: \"slabB\", signer: false, writable: true },\n { name: \"attestation\", signer: false, writable: true },\n { name: \"pairPda\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// PERC-8110: SetOiImbalanceHardBlock\n// ============================================================================\n\n/**\n * SetOiImbalanceHardBlock: 2 accounts\n * Sets the OI imbalance hard-block threshold (admin only)\n */\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// PERC-608: Position NFT Instructions (tags 64–69)\n// ============================================================================\n\n/**\n * MintPositionNft: 10 accounts\n * Creates a Token-2022 position NFT for an open position.\n */\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\n { name: \"payer\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"positionNftPda\", signer: false, writable: true },\n { name: \"nftMint\", signer: false, writable: true },\n { name: \"ownerAta\", signer: false, writable: true },\n { name: \"owner\", signer: true, writable: false },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"token2022Program\", signer: false, writable: false },\n { name: \"systemProgram\", signer: false, writable: false },\n { name: \"rent\", signer: false, writable: false },\n] as const;\n\n/**\n * TransferPositionOwnership: 8 accounts\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\n */\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\n { name: \"currentOwner\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"positionNftPda\", signer: false, writable: true },\n { name: \"nftMint\", signer: false, writable: true },\n { name: \"currentOwnerAta\", signer: false, writable: true },\n { name: \"newOwnerAta\", signer: false, writable: true },\n { name: \"newOwner\", signer: false, writable: false },\n { name: \"token2022Program\", signer: false, writable: false },\n] as const;\n\n/**\n * BurnPositionNft: 7 accounts\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\n */\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\n { name: \"owner\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"positionNftPda\", signer: false, writable: true },\n { name: \"nftMint\", signer: false, writable: true },\n { name: \"ownerAta\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"token2022Program\", signer: false, writable: false },\n] as const;\n\n/**\n * SetPendingSettlement: 3 accounts\n * Keeper/admin sets pending_settlement flag before funding transfer.\n * Protected by admin allowlist (GH#1475).\n */\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\n { name: \"keeper\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: false },\n { name: \"positionNftPda\", signer: false, writable: true },\n] as const;\n\n/**\n * ClearPendingSettlement: 3 accounts\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\n * Protected by admin allowlist (GH#1475).\n */\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\n { name: \"keeper\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: false },\n { name: \"positionNftPda\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\n { name: \"caller\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"nftProgram\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// PERC-8111: SetWalletCap\n// ============================================================================\n\n/**\n * SetWalletCap: 2 accounts\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\n */\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n] as const;\n\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"adminAta\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n { name: \"tokenProgram\", signer: false, writable: false },\n { name: \"vaultPda\", signer: false, writable: false },\n] as const;\n\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: true },\n { name: \"slab\", signer: false, writable: true },\n { name: \"vault\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// PERC-SetDexPool: SetDexPool (tag 74)\n// ============================================================================\n\n/**\n * SetDexPool: 3 accounts\n * Admin pins the approved DEX pool address for a HYPERP market.\n * After this call, UpdateHyperpMark rejects any pool that does not match.\n */\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"slab\", signer: false, writable: true },\n { name: \"poolAccount\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// InitMatcherCtx (tag 83) — v17 wire\n//\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\n// 83. The protocol-fee instructions below were renumbered to 84/85\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\n// ============================================================================\n\n/**\n * InitMatcherCtx (tag 83): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\n * [0] lpOwner signer (LP portfolio owner wallet)\n * [1] market read-only (program-owned market slab)\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\n * [4] matcherProg read-only, executable (the external matcher program)\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\n *\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\n * calling the matcher CPI.\n *\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\n */\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\n { name: \"lpOwner\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: false },\n { name: \"lpPortfolio\", signer: false, writable: false },\n { name: \"matcherCtx\", signer: false, writable: true },\n { name: \"matcherProg\", signer: false, writable: false },\n { name: \"matcherDelegate\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\n// ============================================================================\n\n/**\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\n *\n * Fixed accounts:\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\n * [1] market writable (program-owned market account)\n *\n * Dynamic accounts [2..2+oracle_leg_count]:\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\n *\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\n */\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\n { name: \"oracleAuthority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\n] as const;\n\n/**\n * ConfigureEwmaMark (tag 35): 2 accounts.\n *\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\n * [1] market writable (program-owned)\n *\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\n */\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\n { name: \"oracleAuthority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * PushEwmaMark (tag 36): 2 accounts.\n *\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\n * [1] market writable (program-owned)\n *\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\n */\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\n { name: \"oracleAuthority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * ConfigureAuthMark (tag 62): 2 accounts.\n *\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\n * [1] market writable (program-owned)\n *\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\n */\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\n { name: \"oracleAuthority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * PushAuthMark (tag 63): 2 accounts.\n *\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\n * [1] market writable (program-owned)\n *\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\n */\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\n { name: \"oracleAuthority\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// TASK B — SetMatcherConfig account spec (tag 68)\n// ============================================================================\n\n/**\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\n * 6 accounts when enabling (enabled=1).\n *\n * [0] lpOwner signer (portfolio owner)\n * [1] market read-only (program-owned; owner-check only)\n * [2] lpPortfolio writable (program-owned portfolio)\n * [3] matcherProg read-only, executable (required when enabled=1 only)\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\n *\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\n */\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\n { name: \"lpOwner\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: false },\n { name: \"lpPortfolio\", signer: false, writable: true },\n // When enabled=1, also pass:\n { name: \"matcherProg\", signer: false, writable: false },\n { name: \"matcherCtx\", signer: false, writable: false },\n { name: \"matcherDelegate\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\n//\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\n// ============================================================================\n\n/**\n * WithdrawProtocolFee (tag 84): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\n * [1] market writable (program-owned market-group slab)\n * [2] destToken writable (destination token account)\n * [3] vaultToken writable (program vault token account — source)\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\n * [5] tokenProgram read-only\n *\n * Pays out from the accrued-but-unwithdrawn protocol claim\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\n * in the instruction data means \"withdraw all currently-available capacity\".\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\n * domain budgets; the protocol's claim is a separate, non-domain balance).\n */\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\n * seeds [program_id])\n * [2] market writable (program-owned market-group slab)\n *\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\n * authority — NOT marketauth, NOT insurance_authority, NOT any\n * creator-facing gate. No global fan-out: call once per market.\n */\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\n { name: \"upgradeAuthority\", signer: true, writable: false },\n { name: \"programData\", signer: false, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\n// ============================================================================\n\n/**\n * UpdateFeeSplit (tag 86): 2 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\n * [1] market writable (program-owned market-group slab)\n *\n * Mirrors the neighbouring marketauth-gated single-field setters\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\n *\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\n */\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\n *\n * v17 wire account layout (v16_program.rs\n * handle_withdraw_insurance_reserve_to_stake):\n * [0] cranker signer (permissionless — any signer, pays fees only)\n * [1] market writable (program-owned market-group slab)\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\n * wrapper's PINNED stake program id; its owner is\n * asserted BEFORE any byte is read — the forgery gate)\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\n * [4] vaultToken writable (this market's collateral vault token acct)\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\n * [6] tokenProgram read-only\n *\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\n * destination; percolator-stake's own AccrueFees is what later credits it.\n *\n * Failure codes are deliberately distinct so a keeper can tell the cases\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\n */\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\n { name: \"cranker\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n { name: \"stakePool\", signer: false, writable: false },\n { name: \"stakeVault\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n/**\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\n *\n * v17 wire account layout (v16_program.rs\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\n * [0] admin signer (must match cfg.marketauth)\n * [1] market writable (program-owned market-group slab)\n *\n * ⚠ The instruction payload is a u128, not a u64. See\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\n *\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\n */\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\n { name: \"admin\", signer: true, writable: false },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\n * cfg.marketauth)\n * [1] market writable (program-owned market-group slab)\n *\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\n * than by StakeInitPool; proxy is stake tag 28.\n *\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\n * the authority normally also being the fee payer. The program itself only\n * calls `expect_signer(authority)` — it never writes to this account.\n */\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n/**\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\n *\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\n * [0] market writable (program-owned market-group slab)\n *\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\n * instruction moves no tokens. The transaction still needs a fee payer, but\n * that signer is not an account of this instruction and is not checked against\n * anything.\n *\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\n * only by an authority that may be a cold key or a stake-pool PDA. The\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\n * against the runtime `Clock`), not an authority check. See\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\n * Custom(19) bucket not `Fresh`-and-lapsed.\n */\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\n { name: \"market\", signer: false, writable: true },\n] as const;\n\n// ============================================================================\n// v17 CREATOR FEE CLAIM (tag 90)\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\n// ============================================================================\n\n/**\n * WithdrawCreatorFee (tag 90): 6 accounts.\n *\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\n * only the authority the program checks [0] against differs:\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\n * [1] market writable (program-owned market-group slab)\n * [2] destToken writable (destination token account, owned by [0])\n * [3] vaultToken writable (program vault token account — source)\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\n * [5] tokenProgram read-only\n *\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\n * reflects the authority normally also being the transaction fee payer; the\n * program itself only calls expect_signer on it.\n *\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\n * does NOT accept marketauth as an alternate the way\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\n * pool claim the creator's revenue. It also means claiming keeps working after\n * StakeInitPool, since staking never rotates insurance_operator.\n *\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\n * from the loss backstop, so backstop gating does not apply).\n */\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\n { name: \"authority\", signer: true, writable: true },\n { name: \"market\", signer: false, writable: true },\n { name: \"destToken\", signer: false, writable: true },\n { name: \"vaultToken\", signer: false, writable: true },\n { name: \"vaultAuthority\", signer: false, writable: false },\n { name: \"tokenProgram\", signer: false, writable: false },\n] as const;\n\n// ============================================================================\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\n// ============================================================================\n\nexport const WELL_KNOWN = {\n tokenProgram: TOKEN_PROGRAM_ID,\n clock: SYSVAR_CLOCK_PUBKEY,\n rent: SYSVAR_RENT_PUBKEY,\n systemProgram: SystemProgram.programId,\n} as const;\n","/**\n * Percolator v17 program error definitions.\n *\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\n *\n * Ordinals 0-61 read directly off the PercolatorError enum in\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\n * tentative\" TODO here is resolved.\n *\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\n *\n * v17 breaking changes vs v12.x:\n * - Errors 0-29 have completely different names and semantics from v12.\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\n * - Errors 42-46 are NFT/B-3 (new in v17).\n * - v12.x errors 28-65 are entirely removed.\n */\nexport interface ErrorInfo {\n name: string;\n hint: string;\n}\n\nexport const PERCOLATOR_ERRORS: Record = {\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\n 0: {\n name: \"InvalidMagic\",\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\n },\n 1: {\n name: \"InvalidVersion\",\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\n },\n 2: {\n name: \"AlreadyInitialized\",\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\n },\n 3: {\n name: \"NotInitialized\",\n hint: \"Account is not initialized. Run InitMarket first.\",\n },\n 4: {\n name: \"InvalidAccountKind\",\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\n },\n 5: {\n name: \"InvalidAccountLen\",\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\n },\n 6: {\n name: \"ExpectedSigner\",\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\n },\n 7: {\n name: \"ExpectedWritable\",\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\n },\n 8: {\n name: \"Unauthorized\",\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\n },\n 9: {\n name: \"InvalidInstruction\",\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\n },\n 10: {\n name: \"InvalidMint\",\n hint: \"Token mint does not match the market's collateral mint.\",\n },\n 11: {\n name: \"InvalidTokenAccount\",\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\n },\n 12: {\n name: \"InvalidVaultAccount\",\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\n },\n 13: {\n name: \"InvalidTokenProgram\",\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\n },\n 14: {\n name: \"EngineInvalidConfig\",\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\n },\n 15: {\n name: \"EngineArithmeticOverflow\",\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\n },\n 16: {\n name: \"EngineProvenanceMismatch\",\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\n },\n 17: {\n name: \"EngineHiddenLeg\",\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\n },\n 18: {\n name: \"EngineInvalidLeg\",\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\n },\n 19: {\n name: \"EngineStale\",\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\n },\n 20: {\n name: \"EngineBStale\",\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\n },\n 21: {\n name: \"EngineLockActive\",\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\n },\n 22: {\n name: \"EngineNonProgress\",\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\n },\n 23: {\n name: \"EngineRecoveryRequired\",\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\n },\n 24: {\n name: \"EngineCounterOverflow\",\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\n },\n 25: {\n name: \"EngineCounterUnderflow\",\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\n },\n 26: {\n name: \"OracleInvalid\",\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\n },\n 27: {\n name: \"OracleStale\",\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\n },\n 28: {\n name: \"OracleConfTooWide\",\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\n },\n 29: {\n name: \"InvalidOracleKey\",\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\n },\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\n 30: {\n name: \"LpVaultAlreadyExists\",\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\n },\n 31: {\n name: \"LpVaultNotFound\",\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\n },\n 32: {\n name: \"LpVaultPaused\",\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\n },\n 33: {\n name: \"LpVaultSharesOutstanding\",\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\n },\n 34: {\n name: \"LpVaultZeroAmount\",\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\n },\n 35: {\n name: \"LpVaultInsufficientShares\",\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\n },\n 36: {\n name: \"LpVaultCooldownActive\",\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\n },\n 37: {\n name: \"LpVaultOiReservationViolated\",\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\n },\n 38: {\n name: \"LpVaultNoFeesToCrank\",\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\n },\n 39: {\n name: \"LpVaultSupplyMismatch\",\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\n },\n 40: {\n name: \"LpVaultAuthorityMismatch\",\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\n },\n 41: {\n name: \"LpVaultZeroSharesMinted\",\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\n },\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\n 42: {\n name: \"NftRegistryNotFound\",\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\n },\n 43: {\n name: \"NftPortfolioNotTransferable\",\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\n },\n 44: {\n name: \"NftTransferSelfOrZero\",\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\n },\n 45: {\n name: \"NftInvalidMintAuthority\",\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\n },\n 46: {\n name: \"NftPortfolioProvenance\",\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\n },\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\n 47: {\n name: \"InsuranceWithdrawCooldownActive\",\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\n },\n 48: {\n name: \"InsuranceWithdrawCeilingExceeded\",\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\n },\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\n // initial-margin failure, previously collapsed into the opaque\n // EngineInvalidConfig=14.\n 49: {\n name: \"EngineInsufficientInitialMargin\",\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\n },\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\n // Source: v16_program.rs PercolatorError variant appended after\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\n 50: {\n name: \"LpVaultDepositBelowMinimumLiquidity\",\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\n },\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\n // Source: v16_program.rs PercolatorError variant appended after\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\n // a3cb4390).\n //\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\n // EXACTLY and with no tolerance, against the bps floors below.\n 51: {\n name: \"FeeSplitFloorViolation\",\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\n },\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\n // Source: v16_program.rs PercolatorError variants appended after\n // FeeSplitFloorViolation=51 on percolator-prog\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\n 52: {\n name: \"FeeSplitSumInvalid\",\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\n },\n 53: {\n name: \"NoInsuranceReserveToClaim\",\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\n },\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\n // Source: v16_program.rs, same branch. These seven previously ALL returned\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\n // destination-resolution now has its own code.\n //\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\n // removed. That variant existed only on an unmerged branch and was NEVER\n // deployed, so no on-chain consumer has ever observed the old meaning.\n 54: {\n name: \"StakePoolNotBound\",\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\n },\n 55: {\n name: \"StakePoolOwnerMismatch\",\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\n },\n 56: {\n name: \"StakePoolAuthorityMismatch\",\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\n },\n 57: {\n name: \"StakePoolMarketMismatch\",\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\n },\n 58: {\n name: \"StakePoolWrapperMismatch\",\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\n },\n 59: {\n name: \"StakePoolModeMismatch\",\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\n },\n 60: {\n name: \"StakeProgramNotPinned\",\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\n },\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\n // Source: v16_program.rs PercolatorError variant appended after\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\n 61: {\n name: \"AssetSlotAlreadyConfigured\",\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\n },\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\n // Source: v16_program.rs PercolatorError variant appended after\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\n // wrapper this code is unreachable.\n 62: {\n name: \"CreatorFeeOverClaim\",\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\n },\n\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\n // Source: v16_program.rs PercolatorError variant appended after\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\n // slot 490057417, verified byte-identical.\n 63: {\n name: \"LpVaultBackingBucketNotEmpty\",\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\n },\n};\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\nObject.freeze(PERCOLATOR_ERRORS);\n\n/**\n * Decode a custom program error code to its info.\n *\n * @param code Custom error code from `custom program error: 0x`.\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\n */\nexport function decodeError(code: number): ErrorInfo | undefined {\n return PERCOLATOR_ERRORS[code];\n}\n\n/**\n * Get error name from code.\n *\n * @param code Custom error code.\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\n */\nexport function getErrorName(code: number): string {\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\n}\n\n/**\n * Get actionable hint for error code.\n *\n * @param code Custom error code.\n * @returns Actionable hint string, or undefined if not recognized.\n */\nexport function getErrorHint(code: number): string | undefined {\n return PERCOLATOR_ERRORS[code]?.hint;\n}\n\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\n\n/**\n * Parse a custom program error from transaction logs.\n *\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\n * Returns null if no custom error is found.\n *\n * @param logs Array of transaction log strings from the RPC response.\n * @returns Parsed error with code, name, and hint — or null if not found.\n *\n * @example\n * ```ts\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\n * if (err) console.error(`${err.name}: ${err.hint}`);\n * ```\n */\nexport function parseErrorFromLogs(logs: string[]): {\n code: number;\n name: string;\n hint?: string;\n} | null {\n if (!Array.isArray(logs)) {\n return null;\n }\n const re = new RegExp(\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\n \"i\",\n );\n for (const log of logs) {\n if (typeof log !== \"string\") {\n continue;\n }\n const match = log.match(re);\n if (match) {\n const code = parseInt(match[1], 16);\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\n continue;\n }\n const info = decodeError(code);\n return {\n code,\n name: info?.name ?? `Unknown(${code})`,\n hint: info?.hint,\n };\n }\n }\n return null;\n}\n","/**\n * Standalone percolator-nft program SDK module.\n *\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\n * separate from the main Percolator program. It handles:\n * - MintPositionNft (tag 0)\n * - BurnPositionNft (tag 1)\n * - SettleFunding (tag 2)\n * - GetPositionValue (tag 3)\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\n * - EmergencyBurn (tag 5)\n *\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\n * PositionNft state : [\"position_nft\", portfolio_account, asset_index_u16_LE]\n * Mint authority : [\"mint_authority\"]\n */\n\nimport { PublicKey } from \"@solana/web3.js\";\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\nimport { safeEnv } from \"../config/program-ids.js\";\n\n// ---------------------------------------------------------------------------\n// Program ID\n// ---------------------------------------------------------------------------\n\n/** Allowlist of known NFT program addresses. */\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\n]);\n\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\n throw new Error(\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\n `Pass the programId argument explicitly to bypass env resolution.`,\n );\n}\n\n/**\n * The standalone percolator-nft program (TransferHook + mint authority).\n *\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\n * address while every other id in the SDK is devnet, so any consumer importing it built\n * transactions against a program that does not exist on devnet and failed late with\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\n * constant to work around it.\n */\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\n\nexport function getNftProgramId(): PublicKey {\n return NFT_PROGRAM_ID;\n}\n\n// ---------------------------------------------------------------------------\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\n// ---------------------------------------------------------------------------\n\nexport const NFT_IX_TAG = {\n MintPositionNft: 0,\n BurnPositionNft: 1,\n SettleFunding: 2,\n GetPositionValue: 3,\n ExecuteTransferHook: 4,\n EmergencyBurn: 5,\n RepairExtraMetas: 6,\n ReconcileBurnedNft: 7,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Instruction encoders\n// ---------------------------------------------------------------------------\n\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\nexport function encodeNftMint(assetIndex: number): Uint8Array {\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\n const buf = new Uint8Array(3);\n buf[0] = NFT_IX_TAG.MintPositionNft;\n buf.set(assetIndexBuf, 1);\n return buf;\n}\n\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\nexport function encodeNftBurn(): Uint8Array {\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\n}\n\n/** Encode SettleFunding (tag 2). Data: tag(1). */\nexport function encodeNftSettleFunding(): Uint8Array {\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\n}\n\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\nexport function encodeNftEmergencyBurn(): Uint8Array {\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\n}\n\n/**\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\n * released) back to the recorded last holder, then closes the PositionNft PDA.\n */\nexport function encodeNftReconcile(): Uint8Array {\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\n}\n\n// ---------------------------------------------------------------------------\n// Account meta templates\n// ---------------------------------------------------------------------------\n\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\n\n/**\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\n * `isSigner: undefined` and `isWritable: undefined` for every account\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\n * both to falsy, so EVERY account in the built instruction ends up\n * non-signer/read-only. The NFT program's own writable/signer checks then\n * reject the transaction (confirmed live against the deployed NFT program:\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\n * CPI — matching its `if !nft_pda.is_writable { return\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\n *\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\n * these arrays and working — the only prior working reference\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\n * bypassing the mismatch entirely.\n */\nexport function buildNftAccountMetas(\n spec: readonly AccountMeta[],\n keys: readonly PublicKey[],\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n if (keys.length !== spec.length) {\n throw new Error(\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\n );\n }\n return spec.map((code, i) => ({\n pubkey: keys[i],\n isSigner: code === \"s\" || code === \"sw\",\n isWritable: code === \"w\" || code === \"sw\",\n }));\n}\n\n/**\n * Account metas for MintPositionNft (tag 0). 12 accounts.\n *\n * 0. [signer, writable] payer / position owner\n * 1. [writable] PositionNft PDA (created)\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\n * 3. [writable] Owner's NFT ATA (created)\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\n * 5. [] Mint authority PDA\n * 6. [] Token-2022 program\n * 7. [] Associated token account program\n * 8. [] System program\n * 9. [writable] ExtraAccountMetaList PDA\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\n *\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\n * writable and #10/#11 are required.\n */\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\n];\n\n/**\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\n *\n * 0. [signer] NFT holder\n * 1. [writable] PositionNft PDA (closed)\n * 2. [writable] NFT mint (supply → 0)\n * 3. [writable] Holder's NFT ATA (closed)\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\n * 5. [] Mint authority PDA\n * 6. [] Token-2022 program\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\n *\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\n */\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\n \"s\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\n];\n\n/**\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\n *\n * 0. [signer] NFT holder\n * 1. [writable] PositionNft PDA (closed)\n * 2. [writable] NFT mint\n * 3. [writable] Holder's NFT ATA\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\n * 5. [] Mint authority PDA\n * 6. [] Token-2022 program\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\n */\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\n \"s\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\n];\n\n/**\n * Account metas for ReconcileBurnedNft (tag 7, #138). 7 accounts. Permissionless.\n *\n * 0. [writable] PositionNft PDA (closed)\n * 1. [] NFT mint (Token-2022 — supply must be 0)\n * 2. [writable] Portfolio account (escrow released to the last holder)\n * 3. [] Mint authority PDA (unwrap CPI signer)\n * 4. [] Per-market NftRegistry PDA\n * 5. [] Percolator wrapper program (unwrap CPI target)\n * 6. [writable] Recorded last-holder wallet (escrow + PDA-rent recipient)\n */\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\n \"w\", \"r\", \"w\", \"r\", \"r\", \"r\", \"w\",\n];\n\n// ---------------------------------------------------------------------------\n// PDA derivation\n// ---------------------------------------------------------------------------\n\nconst TEXT = new TextEncoder();\n\nfunction u16Buf(value: number, label: string): Uint8Array {\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\n throw new Error(`${label} must be a u16`);\n }\n const buf = new Uint8Array(2);\n new DataView(buf.buffer).setUint16(0, value, true);\n return buf;\n}\n\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\n const v = typeof value === \"bigint\" ? value : BigInt(value);\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\n throw new Error(`${label} must be a u64`);\n }\n const buf = new Uint8Array(8);\n new DataView(buf.buffer).setBigUint64(0, v, true);\n return buf;\n}\n\n/**\n * Derive the PositionNft state PDA.\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\n *\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\n * engine reuses across close/re-open of the same asset and which therefore\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\n * NFT's stored `marketIdAtMint` for any later op.\n */\nexport function deriveNftPda(\n portfolioAccount: PublicKey,\n marketId: bigint | number,\n programId: PublicKey = NFT_PROGRAM_ID,\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\n programId,\n );\n}\n\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\n\n/**\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\n */\nexport function deriveNftMint(\n _portfolioAccount: PublicKey,\n _assetIndex: number,\n _programId: PublicKey = NFT_PROGRAM_ID,\n): [PublicKey, number] {\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\n}\n\n/**\n * Derive the program-wide mint authority PDA.\n * Seeds: [\"mint_authority\"]\n */\nexport function deriveMintAuthority(\n programId: PublicKey = NFT_PROGRAM_ID,\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode(\"mint_authority\")],\n programId,\n );\n}\n\n/**\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\n * close it and refund its rent to the holder.\n */\nexport function deriveExtraAccountMetas(\n nftMint: PublicKey,\n programId: PublicKey = NFT_PROGRAM_ID,\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\n programId,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Account parser\n// ---------------------------------------------------------------------------\n\n/**\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\n *\n * [0..8] magic u64 (\"PERCNFT\\0\")\n * [8] version u8\n * [9] bump u8\n * [10..42] portfolio_account [u8; 32]\n * [42..74] nft_mint [u8; 32]\n * [74..78] asset_index u32 LE\n * [78] side_at_mint u8\n * [79..95] basis_pos_q_at_mint i128\n * [95..111] f_snap_at_mint i128\n * [111..119] market_id_at_mint u64\n * [119..127] epoch_snap_at_mint u64\n * [127..159] position_owner_at_mint [u8; 32]\n * [159..167] minted_at i64\n * [167..199] _reserved\n */\nexport const POSITION_NFT_STATE_LEN = 199;\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\nconst POSITION_NFT_VERSION = 2;\n\nexport interface PositionNftState {\n version: number;\n bump: number;\n portfolioAccount: PublicKey;\n nftMint: PublicKey;\n assetIndex: number;\n sideAtMint: number;\n basisPosQAtMint: bigint;\n fSnapAtMint: bigint;\n marketIdAtMint: bigint;\n epochSnapAtMint: bigint;\n positionOwnerAtMint: PublicKey;\n /** Backward-compatible alias for positionOwnerAtMint. */\n positionOwner: PublicKey;\n mintedAt: bigint;\n}\n\n/**\n * Read a little-endian signed i128 from a DataView at `offset`.\n *\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\n * value is set the result is negative and two's-complement sign extension is\n * applied explicitly.\n *\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\n * shifted high half collapses the sign bit into all high bits and corrupts the\n * result.\n *\n * @param view DataView wrapping the raw account bytes\n * @param offset Byte offset of the i128 field (little-endian)\n * @returns Signed BigInt in the range [-2^127, 2^127)\n */\nfunction readI128FromView(view: DataView, offset: number): bigint {\n const lo = view.getBigUint64(offset, true);\n const hi = view.getBigUint64(offset + 8, true);\n const unsigned = (hi << 64n) | lo;\n const SIGN_BIT = 1n << 127n;\n if (unsigned >= SIGN_BIT) {\n return unsigned - (1n << 128n);\n }\n return unsigned;\n}\n\n/**\n * Parse a PositionNft account from raw bytes.\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\n */\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\n if (data.length < POSITION_NFT_STATE_LEN) {\n throw new Error(\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\n );\n }\n\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const magic = view.getBigUint64(0, true);\n if (magic !== POSITION_NFT_MAGIC) {\n throw new Error(\"PositionNft account has invalid magic\");\n }\n if (data[8] !== POSITION_NFT_VERSION) {\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\n }\n\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\n\n return {\n version: data[8],\n bump: data[9],\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\n nftMint: new PublicKey(data.subarray(42, 74)),\n assetIndex: view.getUint32(74, true),\n sideAtMint: data[78],\n basisPosQAtMint: readI128FromView(view, 79),\n fSnapAtMint: readI128FromView(view, 95),\n marketIdAtMint: view.getBigUint64(111, true),\n epochSnapAtMint: view.getBigUint64(119, true),\n positionOwnerAtMint,\n positionOwner: positionOwnerAtMint,\n mintedAt: view.getBigInt64(159, true),\n };\n}\n","import { PublicKey } from \"@solana/web3.js\";\n\n/**\n * Read an environment variable safely. Returns `undefined` in browser\n * environments where `process` is not defined, avoiding a\n * `ReferenceError` crash at import time.\n */\nexport function safeEnv(key: string): string | undefined {\n try {\n return typeof process !== \"undefined\" && process?.env\n ? process.env[key]\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Centralized PROGRAM_ID configuration\n * \n * Default to environment variable, then fall back to network-specific defaults.\n * This prevents hard-coded program IDs scattered across the codebase.\n */\n\nexport const PROGRAM_IDS = {\n devnet: {\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\n },\n mainnet: {\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\n },\n} as const;\nObject.freeze(PROGRAM_IDS.devnet);\nObject.freeze(PROGRAM_IDS.mainnet);\nObject.freeze(PROGRAM_IDS);\n\n/**\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\n * and upgraded in place at the same address).\n *\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\n * markets — they were not migrated in place, so anything still pointed at them\n * (e.g. the percolator-launch playground config, which hardcodes its own program\n * ID rather than reading this module) keeps working against the old markets until\n * it is explicitly cut over to this fresh triple. That playground cutover is a\n * separate, later step — NOT performed by this change.\n */\nexport const PROGRAM_IDS_V17 = {\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\n} as const;\nObject.freeze(PROGRAM_IDS_V17);\n\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\n\nexport type Network = \"devnet\" | \"mainnet\";\n\n/** Allowlist of legitimate percolator program addresses (all networks). */\nconst KNOWN_PROGRAM_IDS = new Set([\n PROGRAM_IDS.devnet.percolator,\n PROGRAM_IDS.mainnet.percolator,\n PROGRAM_IDS_V17.percolator,\n]);\n\n/** Allowlist of legitimate matcher program addresses (all networks). */\nconst KNOWN_MATCHER_IDS = new Set([\n PROGRAM_IDS.devnet.matcher,\n PROGRAM_IDS.mainnet.matcher,\n]);\n\n/**\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\n * during pre-deploy / devnet testing — which the allowlist alone would break.\n */\nfunction programOverrideOptIn(): boolean {\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\n}\n\n/**\n * Get the Percolator program ID for the current network\n * \n * Priority:\n * 1. PROGRAM_ID env var (explicit override)\n * 2. Network-specific default (NETWORK env var)\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\n */\nexport function getProgramId(network?: Network): PublicKey {\n // #249: an explicit `network` argument is authoritative and must NOT be silently\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\n if (network === undefined) {\n const override = safeEnv(\"PROGRAM_ID\");\n if (override) {\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\n throw new Error(\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\n );\n }\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\n return new PublicKey(override);\n }\n }\n\n // Use provided network or detect from env — default to devnet (never mainnet silently)\n const detectedNetwork = getCurrentNetwork();\n const targetNetwork = network ?? detectedNetwork;\n const programId = PROGRAM_IDS[targetNetwork].percolator;\n\n return new PublicKey(programId);\n}\n\n/**\n * Get the Matcher program ID for the current network\n */\nexport function getMatcherProgramId(network?: Network): PublicKey {\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\n if (network === undefined) {\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\n if (override) {\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\n throw new Error(\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\n );\n }\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\n return new PublicKey(override);\n }\n }\n\n // Use provided network or detect from env — default to devnet (never mainnet silently)\n const detectedNetwork = getCurrentNetwork();\n const targetNetwork = network ?? detectedNetwork;\n const programId = PROGRAM_IDS[targetNetwork].matcher;\n\n if (!programId) {\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\n }\n\n return new PublicKey(programId);\n}\n\n/**\n * Get the current network from environment.\n *\n * SECURITY (PERC-697): Removed silent mainnet default.\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\n *\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\n * Production deployments always set NETWORK explicitly via Railway/env.\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\n * enforces FORCE_MAINNET=1.\n */\nexport function getCurrentNetwork(): Network {\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\n return \"mainnet\";\n }\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\n return \"devnet\";\n}\n","import { Connection, PublicKey } from \"@solana/web3.js\";\n\n// =============================================================================\n// Browser-compatible read helpers using DataView\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\n// =============================================================================\n\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\nfunction dv(data: Uint8Array): DataView {\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\n}\n/** Read a single unsigned byte at `off`. */\nfunction readU8(data: Uint8Array, off: number): number {\n if (off >= data.length) {\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\n }\n return data[off];\n}\n/** Read a little-endian u16 at `off`. */\nfunction readU16LE(data: Uint8Array, off: number): number {\n return dv(data).getUint16(off, true);\n}\n/** Read a little-endian u32 at `off`. */\nfunction readU32LE(data: Uint8Array, off: number): number {\n return dv(data).getUint32(off, true);\n}\n/** Read a little-endian u64 at `off` as a BigInt. */\nfunction readU64LE(data: Uint8Array, off: number): bigint {\n return dv(data).getBigUint64(off, true);\n}\n/** Read a little-endian signed i64 at `off` as a BigInt. */\nfunction readI64LE(data: Uint8Array, off: number): bigint {\n return dv(data).getBigInt64(off, true);\n}\n\n// =============================================================================\n// Helper: read signed/unsigned i128 from buffer\n// =============================================================================\n\n/**\n * Read a little-endian signed i128 at `offset`.\n * Composed from two u64 halves; sign-extends if the high bit is set.\n */\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\n const lo = readU64LE(buf, offset);\n const hi = readU64LE(buf, offset + 8);\n const unsigned = (hi << 64n) | lo;\n const SIGN_BIT = 1n << 127n;\n if (unsigned >= SIGN_BIT) {\n return unsigned - (1n << 128n);\n }\n return unsigned;\n}\n\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\n const lo = readU64LE(buf, offset);\n const hi = readU64LE(buf, offset + 8);\n return (hi << 64n) | lo;\n}\n\n// =============================================================================\n// Slab Layout Version Detection\n// =============================================================================\n// The deployed devnet program uses a different struct layout (V0) than the SDK\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\n// struct changes that have NOT been deployed to devnet yet.\n//\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\n// - RiskParams: 56 bytes (basic fields only)\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\n// - No partial liquidation field in Account (240 bytes)\n//\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\n// - InsuranceFund: expanded with isolation fields (72 bytes)\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\n// - Has mark_price, long_oi/short_oi, emergency fields\n// - Account has last_partial_liquidation_slot (248 bytes)\n// =============================================================================\n\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\n\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\nexport const SLAB_MAGIC = MAGIC;\n\n// Flag bits in header._padding[0] at offset 13\nconst FLAG_RESOLVED = 1 << 0;\n\n/**\n * Full slab layout descriptor. Returned by detectSlabLayout().\n * All engine field offsets are relative to engineOff.\n */\nexport interface SlabLayout {\n version: 0 | 1 | 2;\n headerLen: number;\n configOffset: number;\n configLen: number;\n reservedOff: number; // offset of _reserved in header\n engineOff: number;\n accountSize: number;\n maxAccounts: number;\n bitmapWords: number;\n accountsOff: number; // absolute offset of accounts array in slab\n\n // Engine field offsets (relative to engineOff)\n engineInsuranceOff: number;\n engineParamsOff: number;\n paramsSize: number;\n engineCurrentSlotOff: number;\n engineFundingIndexOff: number;\n engineLastFundingSlotOff: number;\n engineFundingRateBpsOff: number;\n engineMarkPriceOff: number; // -1 if not present (V0)\n engineLastCrankSlotOff: number;\n engineMaxCrankStalenessOff: number;\n engineTotalOiOff: number;\n engineLongOiOff: number; // -1 if not present (V0)\n engineShortOiOff: number; // -1 if not present (V0)\n engineCTotOff: number;\n enginePnlPosTotOff: number;\n engineLiqCursorOff: number;\n engineGcCursorOff: number;\n engineLastSweepStartOff: number;\n engineLastSweepCompleteOff: number;\n engineCrankCursorOff: number;\n engineSweepStartIdxOff: number;\n engineLifetimeLiquidationsOff: number;\n engineLifetimeForceClosesOff: number;\n engineNetLpPosOff: number;\n engineLpSumAbsOff: number;\n engineLpMaxAbsOff: number;\n engineLpMaxAbsSweepOff: number;\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\n engineBitmapOff: number; // relative to engineOff\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\n\n // Insurance fund layout\n hasInsuranceIsolation: boolean;\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\n\n // Optional fallback for engines without a stored mark_price field (v12.17+):\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\n // predate v12.17 and already expose a real engine.mark_price.\n configMarkEwmaOff?: number;\n}\n\n// ---- V0 layout constants (deployed devnet program) ----\nconst V0_HEADER_LEN = 72;\nconst V0_CONFIG_LEN = 408;\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\nconst V0_ACCOUNT_SIZE = 240;\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\n\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\n// V0 RiskParams: 56 bytes → runtime state at 104\nconst V0_ENGINE_PARAMS_OFF = 48;\nconst V0_PARAMS_SIZE = 56;\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\nconst V0_ENGINE_C_TOT_OFF = 176;\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\nconst V0_ENGINE_BITMAP_OFF = 320;\n\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\nconst V1_HEADER_LEN = 104;\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\nconst V1_ENGINE_OFF_LEGACY = 640;\nconst V1_ACCOUNT_SIZE = 248;\nconst V1_RESERVED_OFF = 80;\n\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\n// V1 RiskParams: 288 bytes → runtime state at 360\nconst V1_ENGINE_PARAMS_OFF = 72;\nconst V1_PARAMS_SIZE = 288;\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\nconst V1_ENGINE_LONG_OI_OFF = 456;\nconst V1_ENGINE_SHORT_OI_OFF = 472;\nconst V1_ENGINE_C_TOT_OFF = 488;\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\nconst V1_ENGINE_BITMAP_OFF = 656;\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\n// These corrected values must be used for actual byte-level parsing.\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\n\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\n// Key differences:\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\n// - Bitmap at engine+624 (not 656)\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\nconst V1D_CONFIG_LEN = 320;\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\nconst V1D_ACCOUNT_SIZE = 248;\n\n// V1D engine field offsets (relative to engineOff):\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\nconst V1D_ENGINE_INSURANCE_OFF = 16;\nconst V1D_ENGINE_PARAMS_OFF = 96;\nconst V1D_PARAMS_SIZE = 288;\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\nconst V1D_ENGINE_LONG_OI_OFF = 480;\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\nconst V1D_ENGINE_C_TOT_OFF = 512;\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\nconst V1D_ENGINE_BITMAP_OFF = 624;\n\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\nconst V2_HEADER_LEN = 104;\nconst V2_CONFIG_LEN = 496;\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\nconst V2_ACCOUNT_SIZE = 248;\nconst V2_ENGINE_BITMAP_OFF = 432;\n\n// V2 engine field offsets (relative to engineOff)\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\nconst V2_ENGINE_C_TOT_OFF = 424;\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\n\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\n//\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\n// Prior value of 1006 was an arithmetic transcription error.\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\n\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\n\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\nconst V_ADL_PARAMS_SIZE = 336;\n\n// V_ADL engine field offsets (relative to engineOff=624):\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\n// PERC-8270 new fields at 472-504:\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\n// ADL side state (PERC-8268, 224 bytes):\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\n// Then LP aggregates:\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\n// emergency fields:\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\n\n// V_ADL account field offsets (relative to account slot start):\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\n\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\n// dynamic fee tiers, fee splits).\n// Engine field ordering completely reorganized from V_ADL.\n// All values verified by cargo build-sbf compile-time assertions.\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\n// Those fields exist in percolator-core but NOT in the deployed binary.\n//\n// HOST constants below are for aarch64 test builds (percolator-core).\n// SBF constants are for the actual deployed program.\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\nconst V12_1_ENGINE_PARAMS_OFF = 96;\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\nconst V12_1_SBF_OFF_C_TOT = 248;\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\n// Bitmap (used field): 584\n// Fields NOT present in deployed program (return -1):\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\n//\n// HOST engine field offsets (percolator-core, for test builds):\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\nconst V12_1_ENGINE_C_TOT_OFF = 480;\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\n// HOST-only fields (percolator-core has these, deployed percolator does not):\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\n// V12_1 account field offsets (relative to account slot start):\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\n\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\n// SBF layout (u128 align=8):\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\n// → fees_earned_total(@272) = 288 bytes\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\n\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\n// explicitly sized, no pointer-derived alignment differences).\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\n// overflow_newest_present(u8@4384).\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\n// Field max_accounts moved to offset 24, insurance_floor at 144.\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\n\n// V12_15 account field offsets (relative to account slot start):\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\nconst V12_15_ACCT_PNL_OFF = 32; // i128\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\n\n// V12_15 RiskParams offsets (relative to params base):\n// sizeof(RiskParams) = 192\nconst V12_15_PARAMS_SIZE = 192;\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\n\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\nconst V12_15_ENGINE_BITMAP_OFF = 862;\n\n// V12_15 size map for layout detection\nconst V12_15_SIZES = new Map();\n\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\n// pending_present/remaining_q/horizon/created_slot.\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\n\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\n// _new_fields_pad, pending_admin[32]).\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\n// size_of::() = 512 (both native and SBF — u128 fields happen\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\n\n// Native (i128 align=16)\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\nconst V12_17_ACCOUNT_SIZE = 368;\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\nconst V12_17_RISK_BUF_LEN = 160;\n// Per-account generation table appended after RISK_BUF in percolator-prog.\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\nconst V12_17_GEN_TABLE_ENTRY = 8;\n\n// SBF (i128 align=8)\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\n\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\nconst V12_17_ACCT_KIND_OFF = 16; // u8\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\n\n// V12_17 RiskEngine field offsets (native, relative to engine start)\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\n\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\n\n// V12_17 size map for layout detection\nconst V12_17_SIZES = new Map();\n\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\nconst V1M_ACCOUNT_SIZE = 248;\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\n\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\n// min_nonzero_im_req(u128=16) = +48 total\nconst V1M_PARAMS_SIZE = 336;\n\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\nconst V1M_ENGINE_LONG_OI_OFF = 504;\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\nconst V1M_ENGINE_C_TOT_OFF = 536;\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\n// which is invalid for a [u64; N] array under #[repr(C)].\nconst V1M_ENGINE_BITMAP_OFF = 720;\n\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\n// New runtime fields inserted between fundingRateBps and markPrice:\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\n// +504: lastCrankSlot, +512: maxCrankStaleness\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\n\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\n// (used by reinit-slab and other scripts). These refer to V1 layout.\nexport const ENGINE_OFF = V1_ENGINE_OFF;\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\n\n// ---- Known slab sizes per version and tier ----\n\n/**\n * Compute the total byte size of a slab given its layout parameters.\n * Used to pre-populate the known-size lookup maps at module load time.\n */\nfunction computeSlabSize(\n engineOff: number,\n bitmapOff: number,\n accountSize: number,\n maxAccounts: number,\n // postBitmap bytes immediately after the free-slot bitmap:\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\n postBitmap = 18,\n): number {\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\n return engineOff + accountsOff + maxAccounts * accountSize;\n}\n\nconst TIERS = [64, 256, 1024, 4096] as const;\n\n// Pre-compute known slab sizes for fast lookup\nconst V0_SIZES = new Map();\nconst V1_SIZES = new Map();\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\nconst V1_SIZES_LEGACY = new Map();\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\nconst V1D_SIZES = new Map();\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\nconst V2_SIZES = new Map();\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\nconst V1M_SIZES = new Map();\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\nconst V_ADL_SIZES = new Map();\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\n// No disambiguation probe required — size-based detection works correctly.\nconst V1M2_SIZES = new Map();\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\nconst V_SETDEXPOOL_SIZES = new Map();\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\nconst V12_1_SIZES = new Map();\nconst V1D_SIZES_LEGACY = new Map();\nfor (const n of TIERS) {\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\n // Disambiguation requires peeking at the version field in the slab header.\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\n // e.g. n=4096 → 1288336 bytes.\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\n // Register BOTH host-computed and SBF-empirical sizes for detection.\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\n}\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\n\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\n// SBF: Account align=8 → accountsOff alignment is 8.\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\nconst V12_17_TIERS = [256, 1024, 4096] as const;\nfor (const n of V12_17_TIERS) {\n const bitmapWords = Math.ceil(n / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 4;\n const nextFreeBytes = n * 2;\n\n // Native (i128 align=16, Account align=16)\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\n V12_17_SIZES.set(nativeSize, n);\n\n // SBF (i128 align=8, Account align=8)\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\n V12_17_SIZES.set(sbfSize, n);\n}\n\n// ---- V12_19 layout constants ----\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\n// below comes from a Rust compile-error message that revealed the real SBF\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\n//\n// V12_19 vs V12_17 SBF differences:\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\n// - ENGINE_OFF: 584 -> 616\n// - ACCOUNT_SIZE: 352 -> 360\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\n// - RiskEngine grew substantially; accounts now inline within engine struct.\nconst V12_19_HEADER_LEN_SBF = 136;\nconst V12_19_CONFIG_LEN = 480;\nconst V12_19_ENGINE_OFF_SBF = 616;\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\nconst V12_19_SBF_RISK_BUF_LEN = 160;\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\n\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\n// MAX_ACCOUNTS; small (256) shown here.\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\n\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\n\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\n\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\n// + (8-byte align pad) + N*360 (accounts).\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\n// (mainnet probe-confirmed), medium=376432, large=1495024.\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\nconst V12_19_SIZES = new Map([\n [26872, 64], // --features micro (derived)\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\n [376432, 1024], // --features medium (derived)\n [1495024, 4096], // default features / large (derived)\n]);\n\n/**\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\n *\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\n * 736 area to same offset but the post-bitmap region now contains both\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\n * before the inline accounts.\n *\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\n * linearly with MAX_ACCOUNTS.\n */\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\n // Compute layout-dependent offsets for this tier.\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\n const freeHeadOff = numUsedOff + 2; // after num_used u16\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\n\n // Inherit Account-internal field offsets from V12_17 (they're the same since\n // the Account struct definition is identical between v12.17 and v12.19;\n // the +8 byte size diff is from trailing padding, not field reordering).\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\n\n return {\n ...base,\n headerLen: V12_19_HEADER_LEN_SBF,\n configLen: V12_19_CONFIG_LEN,\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\n engineOff: V12_19_ENGINE_OFF_SBF,\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\n accountsOff,\n bitmapWords,\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\n // V12_19-specific engine field offsets (probe-confirmed):\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\n // last_market_slot replaces V12_17 last_crank_slot semantics.\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\n };\n}\n\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\n// Bitmap at engine+584 (used field in RiskEngine).\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\nconst V12_1_SBF_ENGINE_OFF = 616;\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const bitmapBytes = Math.ceil(n / 64) * 8;\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\n V12_1_SIZES.set(total, n);\n}\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\nconst V12_1_EP_SIZES = new Map();\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const bitmapBytes = Math.ceil(n / 64) * 8;\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\n V12_1_EP_SIZES.set(total, n);\n}\n\n/**\n * V2 slab tier sizes (small and large) for discovery.\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\n */\nexport const SLAB_TIERS_V2 = Object.freeze({\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\n} as const);\n\n/**\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\n */\nexport const SLAB_TIERS_V1M: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\n}\nObject.freeze(SLAB_TIERS_V1M);\n\n/**\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\n */\nexport const SLAB_TIERS_V1M2: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\n}\nObject.freeze(SLAB_TIERS_V1M2);\n\n/**\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\n */\nexport const SLAB_TIERS_V_ADL: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\n}\nObject.freeze(SLAB_TIERS_V_ADL);\n\n/**\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\n */\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\n const isV0 = version === 0;\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version,\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\n engineBitmapOff: actualBitmapOff,\n postBitmap: 18,\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\n\n hasInsuranceIsolation: !isV0,\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\n };\n}\n\n/**\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\n * Uses correct field offsets derived from on-chain probing.\n *\n * @param maxAccounts - Number of account slots in the slab\n * @param postBitmap - Bytes after the bitmap before next_free array.\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\n */\n/**\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\n */\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\n const engineOff = V1D_ENGINE_OFF;\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\n const accountSize = V1D_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V1_HEADER_LEN,\n configOffset: V1_HEADER_LEN,\n configLen: V1D_CONFIG_LEN,\n reservedOff: V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\n paramsSize: V1D_PARAMS_SIZE,\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\n engineLpMaxAbsOff: -1, // not present in deployed V1\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\n engineEmergencyOiModeOff: -1, // not present in deployed V1\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\n engineLastBreakerSlotOff: -1, // not present in deployed V1\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\n postBitmap,\n acctOwnerOff: ACCT_OWNER_OFF,\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\n };\n}\n\n/**\n * Build a SlabLayout for V2 (BPF intermediate layout).\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\n */\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\n const engineOff = V2_ENGINE_OFF;\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\n const accountSize = V2_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 2,\n headerLen: V2_HEADER_LEN,\n configOffset: V2_HEADER_LEN,\n configLen: V2_CONFIG_LEN,\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: -1, // V2 has no mark_price\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: -1, // V2 has no long_oi\n engineShortOiOff: -1, // V2 has no short_oi\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\n engineEmergencyStartSlotOff: -1,\n engineLastBreakerSlotOff: -1,\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\n postBitmap: 18,\n acctOwnerOff: ACCT_OWNER_OFF,\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48,\n engineInsuranceIsolationBpsOff: 64,\n };\n}\n\n/**\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\n * and trade_twap runtime fields push the bitmap to offset 726.\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\n */\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\n const engineOff = V1M_ENGINE_OFF;\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\n const accountSize = V1M_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V1_HEADER_LEN,\n configOffset: V1_HEADER_LEN,\n configLen: V1M_CONFIG_LEN,\n reservedOff: V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\n paramsSize: V1M_PARAMS_SIZE,\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\n postBitmap: 18,\n acctOwnerOff: ACCT_OWNER_OFF,\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48,\n engineInsuranceIsolationBpsOff: 64,\n };\n}\n\n/**\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\n */\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\n const engineOff = V1M2_ENGINE_OFF;\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\n const accountSize = V1M2_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V1_HEADER_LEN,\n configOffset: V1_HEADER_LEN,\n configLen: V1M2_CONFIG_LEN,\n reservedOff: V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\n postBitmap: 18,\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48,\n engineInsuranceIsolationBpsOff: 64,\n };\n}\n\n/**\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\n *\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\n * large (4096 accounts): 1288320 bytes\n * medium (1024 accounts): 323320 bytes\n * small (256 accounts): 82064 bytes\n */\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\n const engineOff = V_ADL_ENGINE_OFF;\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\n const accountSize = V_ADL_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\n configOffset: V1_HEADER_LEN,\n configLen: V_ADL_CONFIG_LEN, // 520\n reservedOff: V1_RESERVED_OFF, // 80\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\n paramsSize: V_ADL_PARAMS_SIZE, // 336\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\n postBitmap: 18,\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48,\n engineInsuranceIsolationBpsOff: 64,\n };\n}\n\n/**\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\n * e.g. large (4096 accts) = 1288336 bytes.\n */\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\n}\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\n\n/**\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\n * Verified by cargo build-sbf compile-time assertions.\n */\nexport const SLAB_TIERS_V12_1: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\n}\nObject.freeze(SLAB_TIERS_V12_1);\n\n/**\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\n * Account layout completely redesigned with reserve cohort arrays.\n */\nexport const SLAB_TIERS_V12_15: Record = {};\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\n}\nObject.freeze(SLAB_TIERS_V12_15);\n\n/**\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\n * Uses SBF sizes (on-chain layout) for the dataSize values.\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\n * RISK_BUF_LEN=160 appended after engine.\n * Supported tiers: small(256), medium(1024), large(4096).\n */\nexport const SLAB_TIERS_V12_17: Record = {};\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\n const bitmapBytes = Math.ceil(n / 64) * 8;\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\n const accountsOff = Math.ceil(preAcc / 8) * 8;\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\n}\nObject.freeze(SLAB_TIERS_V12_17);\n\n/**\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\n * fall through to the memcmp fallback path with no layout hint.\n *\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\n * exports consumed by discovery.ts.\n */\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\n});\n\n/**\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\n * All engine and account field offsets are identical to V_ADL.\n */\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\n const accountSize = V_ADL_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V1_HEADER_LEN,\n configOffset: V1_HEADER_LEN,\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\n reservedOff: V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\n paramsSize: V_ADL_PARAMS_SIZE,\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\n postBitmap: 18,\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\n\n hasInsuranceIsolation: true,\n engineInsuranceIsolatedOff: 48,\n engineInsuranceIsolationBpsOff: 64,\n };\n}\n\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\n // SBF vs host detection via size comparison.\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: V0_HEADER_LEN, // 72\n configOffset: V0_HEADER_LEN, // 72\n configLen: isSbf ? 544 : 576,\n reservedOff: V1_RESERVED_OFF,\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\n // Fields that don't exist in the deployed program are set to -1 on SBF.\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\n engineBitmapOff: bitmapOff,\n postBitmap: 18,\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\n\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\n // No isolated_balance or insurance_isolation_bps fields.\n hasInsuranceIsolation: !isSbf,\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\n };\n}\n\n/**\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\n */\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 1,\n headerLen: 72,\n configOffset: 72,\n configLen: 544,\n reservedOff: 80, // V1_RESERVED_OFF\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\n // Engine offsets identical to V12_1 SBF\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\n engineFundingIndexOff: -1,\n engineLastFundingSlotOff: -1,\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\n engineLifetimeForceClosesOff: -1,\n engineNetLpPosOff: -1,\n engineLpSumAbsOff: -1,\n engineLpMaxAbsOff: -1,\n engineLpMaxAbsSweepOff: -1,\n engineEmergencyOiModeOff: -1,\n engineEmergencyStartSlotOff: -1,\n engineLastBreakerSlotOff: -1,\n engineBitmapOff: bitmapOff,\n postBitmap: 18,\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\n hasInsuranceIsolation: false,\n engineInsuranceIsolatedOff: -1,\n engineInsuranceIsolationBpsOff: -1,\n };\n}\n\n/**\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\n *\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\n */\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\n const isSbf = dataLen === 237512;\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\n // SBF small has different bitmap/accounts offsets due to u128 align=8\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\n\n return {\n version: 2,\n headerLen: V0_HEADER_LEN, // 72\n configOffset: V0_HEADER_LEN, // 72\n configLen: 552, // SBF CONFIG_LEN for v12.15\n reservedOff: V1_RESERVED_OFF, // 80\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\n engineMarkPriceOff: -1, // not present in v12.15\n engineLastCrankSlotOff: -1, // not yet mapped\n engineMaxCrankStalenessOff: -1, // not yet mapped\n engineTotalOiOff: -1, // not present in v12.15 engine\n engineLongOiOff: -1, // not present in v12.15 engine\n engineShortOiOff: -1, // not present in v12.15 engine\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\n engineLiqCursorOff: -1, // not yet mapped\n engineGcCursorOff: -1, // not yet mapped\n engineLastSweepStartOff: -1, // not yet mapped\n engineLastSweepCompleteOff: -1, // not yet mapped\n engineCrankCursorOff: -1, // not yet mapped\n engineSweepStartIdxOff: -1, // not yet mapped\n engineLifetimeLiquidationsOff: -1, // not yet mapped\n engineLifetimeForceClosesOff: -1, // not present in v12.15\n engineNetLpPosOff: -1, // not present in v12.15\n engineLpSumAbsOff: -1, // not present in v12.15\n engineLpMaxAbsOff: -1, // not present in v12.15\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\n engineEmergencyOiModeOff: -1, // not present in v12.15\n engineEmergencyStartSlotOff: -1, // not present in v12.15\n engineLastBreakerSlotOff: -1, // not present in v12.15\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\n postBitmap,\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\n\n hasInsuranceIsolation: false,\n engineInsuranceIsolatedOff: -1,\n engineInsuranceIsolationBpsOff: -1,\n };\n}\n\n/**\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\n * RISK_BUF_LEN=160 appended after engine.\n */\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\n // Detect SBF vs native from account size and engine offset.\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\n const isSbf = (() => {\n // Compute expected native size for this tier\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\n return dataLen !== nativeSize;\n })();\n\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const bitmapBytes = bitmapWords * 8;\n const postBitmap = 4;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\n const acctAlign = isSbf ? 8 : 16;\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\n\n return {\n version: 2,\n headerLen: V0_HEADER_LEN, // 72\n configOffset: V0_HEADER_LEN, // 72\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\n configLen: 512,\n reservedOff: V1_RESERVED_OFF, // 80\n engineOff,\n accountSize,\n maxAccounts,\n bitmapWords,\n accountsOff: engineOff + accountsOffRel,\n\n engineInsuranceOff: 16,\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\n paramsSize: isSbf ? 184 : 192,\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\n engineLastFundingSlotOff: -1,\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\n engineMaxCrankStalenessOff: -1,\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\n engineLiqCursorOff: -1, // removed in v12.17\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\n engineLastSweepStartOff: -1,\n engineLastSweepCompleteOff: -1,\n engineCrankCursorOff: -1,\n engineSweepStartIdxOff: -1,\n engineLifetimeLiquidationsOff: -1,\n engineLifetimeForceClosesOff: -1,\n engineNetLpPosOff: -1,\n engineLpSumAbsOff: -1,\n engineLpMaxAbsOff: -1,\n engineLpMaxAbsSweepOff: -1,\n engineEmergencyOiModeOff: -1,\n engineEmergencyStartSlotOff: -1,\n engineLastBreakerSlotOff: -1,\n engineBitmapOff: bitmapOff,\n postBitmap,\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\n\n hasInsuranceIsolation: false,\n engineInsuranceIsolatedOff: -1,\n engineInsuranceIsolationBpsOff: -1,\n\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\n // so absolute offset in the slab is 72 + 304 = 376.\n configMarkEwmaOff: V0_HEADER_LEN + 304,\n };\n}\n\n/**\n * Detect the slab layout version from the raw account data length.\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\n *\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\n * V2 slabs have version===2 at offset 8 (u32 LE).\n *\n * @param dataLen - The slab account data length in bytes\n * @param data - Optional raw slab data for version-field disambiguation\n */\n/**\n * Assert that a built SlabLayout is internally consistent.\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\n * Used by layout builders to catch offset arithmetic bugs early.\n *\n * @param layout - Layout descriptor to validate.\n * @param dataLen - Actual byte length of the slab data buffer.\n * @returns The validated layout (identity function for chaining).\n */\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\n if (layout.accountsOff > dataLen) {\n throw new Error(\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\n );\n }\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\n if (bitmapEnd > dataLen) {\n throw new Error(\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\n );\n }\n return layout;\n}\n\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\n // deployed program only emits v12.19 going forward, so this priority\n // is correct for live mainnet reads.\n const v1219n = V12_19_SIZES.get(dataLen);\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\n\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\n const v1217n = V12_17_SIZES.get(dataLen);\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\n\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\n // Vastly larger account size — no collision with any earlier layout possible.\n const v1215n = V12_15_SIZES.get(dataLen);\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\n\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\n const v121epn = V12_1_EP_SIZES.get(dataLen);\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\n\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\n const v121n = V12_1_SIZES.get(dataLen);\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\n\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\n\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\n // works directly — no data-probe disambiguation required.\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\n const v1m2n = V1M2_SIZES.get(dataLen);\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\n\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\n const vadln = V_ADL_SIZES.get(dataLen);\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\n\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\n const v1mn = V1M_SIZES.get(dataLen);\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\n\n // Check V0 sizes (deployed devnet V0 program)\n const v0n = V0_SIZES.get(dataLen);\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\n\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\n // When data is available, peek at the version field to disambiguate.\n const v1dn = V1D_SIZES.get(dataLen);\n if (v1dn !== undefined) {\n if (data && data.length >= 12) {\n const version = readU32LE(data, 8);\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\n }\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\n }\n\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\n\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\n const v1n = V1_SIZES.get(dataLen);\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\n\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\n\n return null;\n}\n\n/**\n * Legacy detectLayout for backward compat.\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\n *\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\n */\nexport function detectLayout(dataLen: number) {\n const layout = detectSlabLayout(dataLen);\n if (!layout) return null;\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\n}\n\n// =============================================================================\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\n// =============================================================================\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\nconst PARAMS_TRADING_FEE_OFF = 24;\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\n// riskReductionThreshold and liquidationBufferBps fields).\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\n\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\n\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\n// InitMarket wire payload for policy fields such as new_account_fee and\n// insurance_floor, but those fields are not stored inside engine RiskParams.\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\nconst V12_19_PARAMS_H_MIN_OFF = 104;\nconst V12_19_PARAMS_H_MAX_OFF = 112;\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\n\n// =============================================================================\n// Account Layout (240/248 bytes)\n// The first 240 bytes are identical in V0 and V1.\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\n// =============================================================================\nconst ACCT_ACCOUNT_ID_OFF = 0;\nconst ACCT_CAPITAL_OFF = 8;\nconst ACCT_KIND_OFF = 24;\nconst ACCT_PNL_OFF = 32;\nconst ACCT_RESERVED_PNL_OFF = 48;\nconst ACCT_WARMUP_STARTED_OFF = 56;\nconst ACCT_WARMUP_SLOPE_OFF = 64;\nconst ACCT_POSITION_SIZE_OFF = 80;\nconst ACCT_ENTRY_PRICE_OFF = 96;\nconst ACCT_FUNDING_INDEX_OFF = 104;\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\nconst ACCT_OWNER_OFF = 184;\nconst ACCT_FEE_CREDITS_OFF = 216;\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\n\n// =============================================================================\n// Interfaces\n// =============================================================================\n\nexport interface SlabHeader {\n magic: bigint;\n version: number;\n bump: number;\n flags: number;\n resolved: boolean;\n paused: boolean;\n admin: PublicKey;\n nonce: bigint;\n lastThrUpdateSlot: bigint;\n}\n\nexport interface MarketConfig {\n collateralMint: PublicKey;\n vaultPubkey: PublicKey;\n indexFeedId: PublicKey;\n maxStalenessSlots: bigint;\n confFilterBps: number;\n vaultAuthorityBump: number;\n invert: number;\n unitScale: number;\n fundingHorizonSlots: bigint;\n fundingKBps: bigint;\n fundingInvScaleNotionalE6: bigint;\n fundingMaxPremiumBps: bigint;\n fundingMaxBpsPerSlot: bigint;\n threshFloor: bigint;\n threshRiskBps: bigint;\n threshUpdateIntervalSlots: bigint;\n threshStepBps: bigint;\n threshAlphaBps: bigint;\n threshMin: bigint;\n threshMax: bigint;\n threshMinStep: bigint;\n oracleAuthority: PublicKey;\n authorityPriceE6: bigint;\n authorityTimestamp: bigint;\n oraclePriceCapE2bps: bigint;\n lastEffectivePriceE6: bigint;\n oiCapMultiplierBps: bigint;\n maxPnlCap: bigint;\n adaptiveFundingEnabled: boolean;\n adaptiveScaleBps: number;\n adaptiveMaxFundingBps: bigint;\n marketCreatedSlot: bigint;\n oiRampSlots: bigint;\n /**\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\n * Do not use for market-resolution logic until a parser is wired.\n */\n resolvedSlot: bigint;\n insuranceIsolationBps: number;\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\n oraclePhase: number;\n /** PERC-622: Cumulative trade volume in e6 format */\n cumulativeVolumeE6: bigint;\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\n phase2DeltaSlots: number;\n /**\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\n * SetDexPool has never been called (all-zero pubkey).\n * Non-null means the program will reject any UpdateHyperpMark that passes\n * a different pool account.\n */\n dexPool: PublicKey | null;\n}\n\nexport interface InsuranceFund {\n balance: bigint;\n feeRevenue: bigint;\n isolatedBalance: bigint;\n isolationBps: number;\n}\n\nexport interface RiskParams {\n /**\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\n */\n warmupPeriodSlots: bigint;\n maintenanceMarginBps: bigint;\n initialMarginBps: bigint;\n tradingFeeBps: bigint;\n maxAccounts: bigint;\n newAccountFee: bigint;\n riskReductionThreshold: bigint;\n maintenanceFeePerSlot: bigint;\n maxCrankStalenessSlots: bigint;\n liquidationFeeBps: bigint;\n liquidationFeeCap: bigint;\n liquidationBufferBps: bigint;\n minLiquidationAbs: bigint;\n /** Minimum initial deposit to open an account (V12_1+ only) */\n minInitialDeposit: bigint;\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\n minNonzeroMmReq: bigint;\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\n minNonzeroImReq: bigint;\n /** Insurance fund floor (V12_1+ only) */\n insuranceFloor: bigint;\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\n hMin: bigint;\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\n hMax: bigint;\n}\n\nexport interface EngineState {\n vault: bigint;\n insuranceFund: InsuranceFund;\n currentSlot: bigint;\n fundingIndexQpbE6: bigint;\n lastFundingSlot: bigint;\n /**\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\n */\n fundingRateBpsPerSlotLast: bigint;\n /**\n * Funding rate in e9 units (i128). v12.15+ only.\n * 0n on pre-v12.15 slabs.\n */\n fundingRateE9: bigint;\n /**\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\n */\n marketMode: 0 | 1 | null;\n lastCrankSlot: bigint;\n maxCrankStalenessSlots: bigint;\n totalOpenInterest: bigint;\n longOi: bigint;\n shortOi: bigint;\n cTot: bigint;\n pnlPosTot: bigint;\n /**\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\n */\n pnlMaturedPosTot: bigint;\n liqCursor: number;\n gcCursor: number;\n lastSweepStartSlot: bigint;\n lastSweepCompleteSlot: bigint;\n crankCursor: number;\n sweepStartIdx: number;\n lifetimeLiquidations: bigint;\n lifetimeForceCloses: bigint;\n netLpPos: bigint;\n lpSumAbs: bigint;\n lpMaxAbs: bigint;\n lpMaxAbsSweep: bigint;\n emergencyOiMode: boolean;\n emergencyStartSlot: bigint;\n lastBreakerSlot: bigint;\n numUsedAccounts: number;\n nextAccountId: bigint;\n markPriceE6: bigint;\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\n oraclePriceE6: bigint;\n\n // ---- V12_17 engine fields ----\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\n fLongNum: bigint;\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\n fShortNum: bigint;\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\n negPnlAccountCount: bigint;\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\n fundPxLast: bigint;\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\n resolvedKLongTerminalDelta: bigint;\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\n resolvedKShortTerminalDelta: bigint;\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\n resolvedLivePrice: bigint;\n}\n\nexport enum AccountKind {\n User = 0,\n LP = 1,\n}\n\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\nexport type ReserveCohortBytes = Uint8Array;\n\nexport interface Account {\n kind: AccountKind;\n accountId: bigint;\n capital: bigint;\n pnl: bigint;\n reservedPnl: bigint;\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\n warmupStartedAtSlot: bigint;\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\n warmupSlopePerStep: bigint;\n positionSize: bigint;\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\n entryPrice: bigint;\n fundingIndex: bigint;\n matcherProgram: PublicKey;\n matcherContext: PublicKey;\n owner: PublicKey;\n feeCredits: bigint;\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\n lastFeeSlot: bigint;\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\n feesEarnedTotal: bigint;\n /**\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\n */\n exactReserveCohorts: ReserveCohortBytes[] | null;\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\n exactCohortCount: number | null;\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\n overflowOlder: ReserveCohortBytes | null;\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\n overflowOlderPresent: boolean | null;\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\n overflowNewest: ReserveCohortBytes | null;\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\n overflowNewestPresent: boolean | null;\n\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\n fSnap: bigint;\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\n adlABasis: bigint;\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\n adlKSnap: bigint;\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\n adlEpochSnap: bigint;\n\n // Scheduled reserve bucket (older, matures linearly)\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\n schedPresent: boolean | null;\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\n schedRemainingQ: bigint | null;\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\n schedAnchorQ: bigint | null;\n /** Start slot for scheduled bucket. null on pre-v12.17. */\n schedStartSlot: bigint | null;\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\n schedHorizon: bigint | null;\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\n schedReleaseQ: bigint | null;\n\n // Pending reserve bucket (newest, does not mature while pending)\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\n pendingPresent: boolean | null;\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\n pendingRemainingQ: bigint | null;\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\n pendingHorizon: bigint | null;\n /** Creation slot for pending bucket. null on pre-v12.17. */\n pendingCreatedSlot: bigint | null;\n}\n\n// =============================================================================\n// Fetch\n// =============================================================================\n\nexport async function fetchSlab(\n connection: Connection,\n slabPubkey: PublicKey,\n expectedOwner?: PublicKey\n): Promise {\n const info = await connection.getAccountInfo(slabPubkey);\n if (!info) {\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\n }\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\n throw new Error(\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\n );\n }\n return new Uint8Array(info.data);\n}\n\n// =============================================================================\n// PERC-302: Market Maturity OI Ramp\n// =============================================================================\n\nexport const RAMP_START_BPS = 1000n;\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\n\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\n const target = config.oiCapMultiplierBps;\n if (target === 0n) return 0n;\n if (config.oiRampSlots === 0n) return target;\n if (target <= RAMP_START_BPS) return target;\n const elapsed = currentSlot > config.marketCreatedSlot\n ? currentSlot - config.marketCreatedSlot\n : 0n;\n if (elapsed >= config.oiRampSlots) return target;\n const range = target - RAMP_START_BPS;\n const rampAdd = (range * elapsed) / config.oiRampSlots;\n const result = RAMP_START_BPS + rampAdd;\n return result < target ? result : target;\n}\n\n// =============================================================================\n// Header helpers\n// =============================================================================\n\nexport function readNonce(data: Uint8Array): bigint {\n const layout = detectSlabLayout(data.length, data);\n if (!layout) {\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\n }\n const roff = layout.reservedOff;\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\n return readU64LE(data, roff);\n}\n\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\n const layout = detectSlabLayout(data.length, data);\n if (!layout) {\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\n }\n const roff = layout.reservedOff;\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\n return readU64LE(data, roff + 8);\n}\n\n// =============================================================================\n// Parsing Functions\n// =============================================================================\n\n/**\n * Parse slab header (first 72 bytes — layout-independent).\n */\nexport function parseHeader(data: Uint8Array): SlabHeader {\n if (data.length < V0_HEADER_LEN) {\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\n }\n\n const magic = readU64LE(data, 0);\n if (magic !== MAGIC) {\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\n }\n\n const version = readU32LE(data, 8);\n const bump = readU8(data, 12);\n const flags = readU8(data, 13);\n const admin = new PublicKey(data.subarray(16, 48));\n\n // Reserved field location depends on layout\n const layout = detectSlabLayout(data.length, data);\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\n const nonce = readU64LE(data, roff);\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\n\n return {\n magic,\n version,\n bump,\n flags,\n resolved: (flags & FLAG_RESOLVED) !== 0,\n paused: (flags & 0x02) !== 0,\n admin,\n nonce,\n lastThrUpdateSlot,\n };\n}\n\n/**\n * Parse market config. Layout-version aware.\n * For V0 slabs, fields beyond the basic config are read if present in the data,\n * otherwise defaults are returned.\n *\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\n */\n/**\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\n * SBF layout (u128 align=8, total size 512 bytes):\n * 0 collateral_mint [32]\n * 32 vault_pubkey [32]\n * 64 index_feed_id [32]\n * 96 max_staleness_secs u64\n * 104 conf_filter_bps u16\n * 106 vault_authority_bump u8\n * 107 invert u8\n * 108 unit_scale u32\n * 112 funding_horizon_slots u64\n * 120 funding_k_bps u64\n * 128 funding_max_premium_bps i64\n * 136 funding_max_bps_per_slot i64\n * 144 oracle_authority [32]\n * 176 authority_price_e6 u64\n * 184 authority_timestamp i64\n * 192 oracle_price_cap_e2bps u64\n * 200 last_effective_price_e6 u64\n * 208 max_insurance_floor u128\n * 224 min_oracle_price_cap_e2bps u64\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\n * 240 insurance_withdraw_cooldown_slots u64\n * 248 _iw_padding2 [u64;2]\n * 264 last_hyperp_index_slot u64\n * 272 last_mark_push_slot u128\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\n * 304 mark_ewma_e6 u64\n * 312 mark_ewma_last_slot u64\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\n * 336 permissionless_resolve_stale_slots u64\n * 344 last_good_oracle_slot u64\n * 352 maintenance_fee_per_slot u128\n * 368 last_fee_charge_slot u64 (+ 8 pad)\n * 384 mark_min_fee u64\n * 392 force_close_delay_slots u64\n * 400 dex_pool [32]\n * 432 max_pnl_cap u64\n * 440 last_audit_pause_slot u64\n * 448 oi_cap_multiplier_bps u64\n * 456 dispute_window_slots u64\n * 464 dispute_bond_amount u64\n * 472 lp_collateral_enabled u8\n * 473 _pad u8\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\n * 480 pending_admin [32]\n * 512 end\n */\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\n const MIN_V12_17_BYTES = 512;\n if (data.length < configOff + MIN_V12_17_BYTES) {\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\n }\n\n const b = configOff;\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\n const maxStalenessSlots = readU64LE(data, b + 96);\n const confFilterBps = readU16LE(data, b + 104);\n const vaultAuthorityBump = readU8(data, b + 106);\n const invert = readU8(data, b + 107);\n const unitScale = readU32LE(data, b + 108);\n const fundingHorizonSlots = readU64LE(data, b + 112);\n const fundingKBps = readU64LE(data, b + 120);\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\n const authorityPriceE6 = readU64LE(data, b + 176);\n const authorityTimestamp = readI64LE(data, b + 184);\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\n // currently surfaced by the MarketConfig type; read them when/if callers\n // need them. Only dex_pool is consumed downstream.\n\n const dexPoolBytes = data.subarray(b + 400, b + 432);\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\n\n return {\n collateralMint,\n vaultPubkey,\n indexFeedId,\n maxStalenessSlots,\n confFilterBps,\n vaultAuthorityBump,\n invert,\n unitScale,\n fundingHorizonSlots,\n fundingKBps,\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\n fundingMaxPremiumBps,\n fundingMaxBpsPerSlot,\n threshFloor: 0n, // removed in v12.17\n threshRiskBps: 0n,\n threshUpdateIntervalSlots: 0n,\n threshStepBps: 0n,\n threshAlphaBps: 0n,\n threshMin: 0n,\n threshMax: 0n,\n threshMinStep: 0n,\n oracleAuthority,\n authorityPriceE6,\n authorityTimestamp,\n oraclePriceCapE2bps,\n lastEffectivePriceE6,\n oiCapMultiplierBps: readU64LE(data, b + 448),\n maxPnlCap: readU64LE(data, b + 432),\n adaptiveFundingEnabled: false, // removed in v12.17\n adaptiveScaleBps: 0,\n adaptiveMaxFundingBps: 0n,\n marketCreatedSlot: 0n,\n oiRampSlots: 0n,\n resolvedSlot: 0n,\n insuranceIsolationBps: 0,\n oraclePhase: 0,\n cumulativeVolumeE6: 0n,\n phase2DeltaSlots: 0,\n dexPool,\n };\n}\n\n/**\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\n * --features small) on 2026-04-28.\n *\n * 0 collateral_mint [32]\n * 32 vault_pubkey [32]\n * 64 index_feed_id [32]\n * 96 max_staleness_secs u64\n * 104 conf_filter_bps u16\n * 106 vault_authority_bump u8\n * 107 invert u8\n * 108 unit_scale u32\n * 112 funding_horizon_slots u64\n * 120 funding_k_bps u64\n * 128 funding_max_premium_bps i64\n * 136 funding_max_e9_per_slot i64\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\n * 176 hyperp_mark_e6 u64 ← v12.19 only\n * 184 last_oracle_publish_time i64\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\n * 200 insurance_withdraw_max_bps u16\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\n * 204 _iw_padding [u8;4]\n * 208 insurance_withdraw_cooldown_slots u64\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\n * 224 min_oracle_price_cap_e2bps u64\n * 232 last_hyperp_index_slot u64\n * 240 last_mark_push_slot u128\n * 256 last_insurance_withdraw_slot u64\n * 264 _pad u64\n * 272 mark_ewma_e6 u64\n * 280 mark_ewma_last_slot u64\n * 288 mark_ewma_halflife_slots u64\n * 296 init_restart_slot u64\n * 304 permissionless_resolve_stale_slots u64\n * 312 last_good_oracle_slot u64\n * 320 maintenance_fee_per_slot u128\n * 336 fee_sweep_cursor_word u64\n * 344 fee_sweep_cursor_bit u64\n * 352 mark_min_fee u64\n * 360 force_close_delay_slots u64\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\n * 408 last_audit_pause_slot u64\n * 416 oi_cap_multiplier_bps u64\n * 424 dispute_window_slots u64\n * 432 dispute_bond_amount u64\n * 440 lp_collateral_enabled u8\n * 441 _pad u8\n * 442 lp_collateral_ltv_bps u16\n * 444 _pad [u8;4]\n * 448 pending_admin [32]\n * 480 end\n */\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\n const MIN_V12_19_BYTES = 480;\n if (data.length < configOff + MIN_V12_19_BYTES) {\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\n }\n\n const b = configOff;\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\n const maxStalenessSlots = readU64LE(data, b + 96);\n const confFilterBps = readU16LE(data, b + 104);\n const vaultAuthorityBump = readU8(data, b + 106);\n const invert = readU8(data, b + 107);\n const unitScale = readU32LE(data, b + 108);\n const fundingHorizonSlots = readU64LE(data, b + 112);\n const fundingKBps = readU64LE(data, b + 120);\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\n const authorityPriceE6 = readU64LE(data, b + 176);\n const authorityTimestamp = readI64LE(data, b + 184);\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\n\n const dexPoolBytes = data.subarray(b + 368, b + 400);\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\n\n return {\n collateralMint,\n vaultPubkey,\n indexFeedId,\n maxStalenessSlots,\n confFilterBps,\n vaultAuthorityBump,\n invert,\n unitScale,\n fundingHorizonSlots,\n fundingKBps,\n fundingInvScaleNotionalE6: 0n,\n fundingMaxPremiumBps,\n fundingMaxBpsPerSlot,\n threshFloor: 0n,\n threshRiskBps: 0n,\n threshUpdateIntervalSlots: 0n,\n threshStepBps: 0n,\n threshAlphaBps: 0n,\n threshMin: 0n,\n threshMax: 0n,\n threshMinStep: 0n,\n oracleAuthority,\n authorityPriceE6,\n authorityTimestamp,\n oraclePriceCapE2bps,\n lastEffectivePriceE6,\n oiCapMultiplierBps: readU64LE(data, b + 416),\n maxPnlCap: readU64LE(data, b + 400),\n adaptiveFundingEnabled: false,\n adaptiveScaleBps: 0,\n adaptiveMaxFundingBps: 0n,\n marketCreatedSlot: 0n,\n oiRampSlots: 0n,\n resolvedSlot: 0n,\n insuranceIsolationBps: 0,\n oraclePhase: 0,\n cumulativeVolumeE6: 0n,\n phase2DeltaSlots: 0,\n dexPool,\n };\n}\n\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\n throw new Error('parseConfig: invalid slab magic');\n }\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\n\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\n if (isV12_19) {\n return parseConfigV12_19(data, configOff);\n }\n\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\n // sequential code below covers pre-v12.17 layouts.\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\n if (isV12_17) {\n return parseConfigV12_17(data, configOff);\n }\n\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\n // V1 extended fields are optional and guarded by their own `remaining` checks.\n const MIN_CONFIG_BYTES = 376;\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\n if (data.length < minLen) {\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\n }\n\n let off = configOff;\n\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\n off += 32;\n\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\n off += 32;\n\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\n off += 32;\n\n const maxStalenessSlots = readU64LE(data, off);\n off += 8;\n\n const confFilterBps = readU16LE(data, off);\n off += 2;\n\n const vaultAuthorityBump = readU8(data, off);\n off += 1;\n\n const invert = readU8(data, off);\n off += 1;\n\n const unitScale = readU32LE(data, off);\n off += 4;\n\n // Funding rate parameters\n const fundingHorizonSlots = readU64LE(data, off);\n off += 8;\n\n const fundingKBps = readU64LE(data, off);\n off += 8;\n\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\n off += 16;\n\n const fundingMaxPremiumBps = readI64LE(data, off);\n off += 8;\n\n const fundingMaxBpsPerSlot = readI64LE(data, off);\n off += 8;\n\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\n\n // Threshold parameters\n const threshFloor = readU128LE(data, off);\n off += 16;\n\n const threshRiskBps = readU64LE(data, off);\n off += 8;\n\n const threshUpdateIntervalSlots = readU64LE(data, off);\n off += 8;\n\n const threshStepBps = readU64LE(data, off);\n off += 8;\n\n const threshAlphaBps = readU64LE(data, off);\n off += 8;\n\n const threshMin = readU128LE(data, off);\n off += 16;\n\n const threshMax = readU128LE(data, off);\n off += 16;\n\n const threshMinStep = readU128LE(data, off);\n off += 16;\n\n // Oracle authority fields\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\n off += 32;\n\n const authorityPriceE6 = readU64LE(data, off);\n off += 8;\n\n const authorityTimestamp = readI64LE(data, off);\n off += 8;\n\n // Oracle price circuit breaker\n const oraclePriceCapE2bps = readU64LE(data, off);\n off += 8;\n\n const lastEffectivePriceE6 = readU64LE(data, off);\n off += 8;\n\n // OI cap\n const oiCapMultiplierBps = readU64LE(data, off);\n off += 8;\n\n const maxPnlCap = readU64LE(data, off);\n off += 8;\n\n // Check if we have enough data for V1-only fields\n const remaining = configOff + configLen - off;\n\n let adaptiveFundingEnabled = false;\n let adaptiveScaleBps = 0;\n let adaptiveMaxFundingBps = 0n;\n let marketCreatedSlot = 0n;\n let oiRampSlots = 0n;\n let resolvedSlot = 0n;\n let insuranceIsolationBps = 0;\n let oraclePhase = 0;\n let cumulativeVolumeE6 = 0n;\n let phase2DeltaSlots = 0;\n\n if (remaining >= 40) {\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\n // market_created_slot(u64), oi_ramp_slots(u64),\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\n // _pad2(u32), adaptive_max_funding_bps(u64),\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\n marketCreatedSlot = readU64LE(data, off);\n off += 8;\n\n oiRampSlots = readU64LE(data, off);\n off += 8;\n\n adaptiveFundingEnabled = readU8(data, off) !== 0;\n off += 1;\n off += 1; // _adaptive_pad\n adaptiveScaleBps = readU16LE(data, off);\n off += 2;\n off += 4; // _adaptive_pad2\n adaptiveMaxFundingBps = readU64LE(data, off);\n off += 8;\n\n if (remaining >= 42) {\n insuranceIsolationBps = readU16LE(data, off);\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\n if (remaining >= 56) { // 42 + 14 bytes padding\n const padOff = off + 2;\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\n // phase2_delta_slots is u24 LE (3 bytes)\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\n }\n }\n }\n\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\n // All-zero pubkey means SetDexPool was never called.\n let dexPool: PublicKey | null = null;\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\n // Return null if all-zero (SetDexPool never called)\n if (dexPoolBytes.some(b => b !== 0)) {\n dexPool = new PublicKey(dexPoolBytes);\n }\n }\n\n return {\n collateralMint,\n vaultPubkey,\n indexFeedId,\n maxStalenessSlots,\n confFilterBps,\n vaultAuthorityBump,\n invert,\n unitScale,\n fundingHorizonSlots,\n fundingKBps,\n fundingInvScaleNotionalE6,\n fundingMaxPremiumBps,\n fundingMaxBpsPerSlot,\n threshFloor,\n threshRiskBps,\n threshUpdateIntervalSlots,\n threshStepBps,\n threshAlphaBps,\n threshMin,\n threshMax,\n threshMinStep,\n oracleAuthority,\n authorityPriceE6,\n authorityTimestamp,\n oraclePriceCapE2bps,\n lastEffectivePriceE6,\n oiCapMultiplierBps,\n maxPnlCap,\n adaptiveFundingEnabled,\n adaptiveScaleBps,\n adaptiveMaxFundingBps,\n marketCreatedSlot,\n oiRampSlots,\n resolvedSlot,\n insuranceIsolationBps,\n oraclePhase,\n cumulativeVolumeE6,\n phase2DeltaSlots,\n dexPool,\n };\n}\n\n/**\n * Parse RiskParams from engine data. Layout-version aware.\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\n * not present on-chain, so defaults (0) are returned.\n *\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\n */\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\n const base = engineOff + paramsOff;\n\n // Validate we have enough data for the fields we'll actually read.\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\n if (data.length < base + MIN_PARAMS_BYTES) {\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\n }\n\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\n const isV12_19Params = layout !== null && layout !== undefined &&\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\n\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\n\n // Basic params present in all layouts (offsets 0-55 are identical)\n const result: RiskParams = {\n warmupPeriodSlots: isV12_19Params\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\n : isV12_15Params\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\n maintenanceMarginBps: isV12_19Params\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\n : isV12_15Params\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\n initialMarginBps: isV12_19Params\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\n : isV12_15Params\n ? readU64LE(data, base + 8)\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\n tradingFeeBps: isV12_19Params\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\n : isV12_15Params\n ? readU64LE(data, base + 16)\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\n maxAccounts: isV12_19Params\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\n : isV12_15Params\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\n newAccountFee: isV12_19Params\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\n : isV12_15Params\n ? readU128LE(data, base + 32) // offset 32 in v12.15\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\n // Extended params: defaults; overwritten below if layout supports them\n riskReductionThreshold: 0n,\n maintenanceFeePerSlot: 0n,\n maxCrankStalenessSlots: 0n,\n liquidationFeeBps: 0n,\n liquidationFeeCap: 0n,\n liquidationBufferBps: 0n,\n minLiquidationAbs: 0n,\n minInitialDeposit: 0n,\n minNonzeroMmReq: 0n,\n minNonzeroImReq: 0n,\n insuranceFloor: 0n,\n hMin: 0n,\n hMax: 0n,\n };\n\n if (isV12_19Params) {\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\n result.riskReductionThreshold = 0n;\n result.maintenanceFeePerSlot = 0n;\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\n result.minInitialDeposit = 0n;\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\n result.insuranceFloor = 0n;\n } else if (isV12_15Params) {\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\n result.riskReductionThreshold = 0n; // removed in v12.15\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\n result.liquidationFeeBps = readU64LE(data, base + 56);\n result.liquidationFeeCap = readU128LE(data, base + 64);\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\n result.minLiquidationAbs = readU128LE(data, base + 80);\n result.minInitialDeposit = readU128LE(data, base + 96);\n result.minNonzeroMmReq = readU128LE(data, base + 112);\n result.minNonzeroImReq = readU128LE(data, base + 128);\n } else if (isV12_1Sbf) {\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\n result.hMin = result.warmupPeriodSlots;\n result.hMax = result.warmupPeriodSlots;\n } else if (paramsSize >= 144) {\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\n result.hMin = result.warmupPeriodSlots;\n result.hMax = result.warmupPeriodSlots;\n }\n\n return result;\n}\n\n/**\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\n */\nexport function parseEngine(data: Uint8Array): EngineState {\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\n throw new Error('parseEngine: invalid slab magic');\n }\n const layout = detectSlabLayout(data.length, data);\n if (!layout) {\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\n }\n if (data.length < layout.accountsOff) {\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\n }\n\n const base = layout.engineOff;\n\n // Detect layout versions\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\n\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\n if (isV12_17 || isV12_19) {\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\n\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\n // resolved_k offsets: native 304/320, SBF 288/304\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\n const resolvedKLongOff = isV12_19 ? 288\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\n const resolvedKShortOff = isV12_19 ? 304\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\n\n const longOi = readU128LE(data, base + oiEffLongOff);\n const shortOi = readU128LE(data, base + oiEffShortOff);\n\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\n\n return {\n vault: readU128LE(data, base),\n insuranceFund: {\n balance: readU128LE(data, base + 16),\n feeRevenue: 0n,\n isolatedBalance: 0n,\n isolationBps: 0,\n },\n currentSlot: readU64LE(data, base + currentSlotOff),\n fundingIndexQpbE6: 0n, // replaced by per-side funding\n lastFundingSlot: 0n,\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\n fundingRateE9: 0n, // no stored funding rate in v12.17\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\n maxCrankStalenessSlots: 0n,\n totalOpenInterest: longOi + shortOi,\n longOi,\n shortOi,\n cTot: readU128LE(data, base + cTotOff),\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\n liqCursor: 0,\n gcCursor: readU16LE(data, base + gcCursorOff),\n lastSweepStartSlot: 0n,\n lastSweepCompleteSlot: 0n,\n crankCursor: 0,\n sweepStartIdx: 0,\n lifetimeLiquidations: 0n,\n lifetimeForceCloses: 0n,\n netLpPos: 0n,\n lpSumAbs: 0n,\n lpMaxAbs: 0n,\n lpMaxAbsSweep: 0n,\n emergencyOiMode: false,\n emergencyStartSlot: 0n,\n lastBreakerSlot: 0n,\n markPriceE6: 0n,\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\n\n // V12_17 fields\n fLongNum: readI128LE(data, base + fLongNumOff),\n fShortNum: readI128LE(data, base + fShortNumOff),\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\n fundPxLast: readU64LE(data, base + fundPxLastOff),\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\n };\n }\n\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\n const fundingRateBpsPerSlotLast = isV12_15\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\n\n return {\n vault: readU128LE(data, base),\n insuranceFund: {\n balance: readU128LE(data, base + layout.engineInsuranceOff),\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\n feeRevenue: layout.hasInsuranceIsolation\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\n : 0n,\n isolatedBalance: layout.hasInsuranceIsolation\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\n : 0n,\n isolationBps: layout.hasInsuranceIsolation\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\n : 0,\n },\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\n : readI128LE(data, base + layout.engineFundingIndexOff))\n : 0n,\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\n fundingRateBpsPerSlotLast,\n fundingRateE9: isV12_15\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\n : 0n,\n marketMode: isV12_15\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\n : null,\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\n totalOpenInterest: layout.engineTotalOiOff >= 0\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\n longOi: layout.engineLongOiOff >= 0\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\n shortOi: layout.engineShortOiOff >= 0\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\n cTot: readU128LE(data, base + layout.engineCTotOff),\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\n pnlMaturedPosTot: isV12_15\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\n : 0n,\n liqCursor: layout.engineLiqCursorOff >= 0\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\n gcCursor: layout.engineGcCursorOff >= 0\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\n crankCursor: layout.engineCrankCursorOff >= 0\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\n netLpPos: layout.engineNetLpPosOff >= 0\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\n lpSumAbs: layout.engineLpSumAbsOff >= 0\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\n : false,\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\n markPriceE6: layout.engineMarkPriceOff >= 0\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\n oraclePriceE6: isV12_15\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\n : 0n,\n numUsedAccounts: (() => {\n if (layout.postBitmap < 18) return 0;\n const bw = layout.bitmapWords;\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\n })(),\n nextAccountId: (() => {\n if (layout.postBitmap < 18) return 0n;\n const bw = layout.bitmapWords;\n const numUsedOff = layout.engineBitmapOff + bw * 8;\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\n })(),\n\n // V12_17 fields (not present in pre-v12.17)\n fLongNum: 0n,\n fShortNum: 0n,\n negPnlAccountCount: 0n,\n fundPxLast: 0n,\n resolvedKLongTerminalDelta: 0n,\n resolvedKShortTerminalDelta: 0n,\n resolvedLivePrice: 0n,\n };\n}\n\n/**\n * Read bitmap to get list of used account indices.\n */\n/**\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\n */\nexport function parseUsedIndices(data: Uint8Array): number[] {\n const layout = detectSlabLayout(data.length, data);\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\n\n const base = layout.engineOff + layout.engineBitmapOff;\n if (data.length < base + layout.bitmapWords * 8) {\n throw new Error(\"Slab data too short for bitmap\");\n }\n\n const used: number[] = [];\n for (let word = 0; word < layout.bitmapWords; word++) {\n const bits = readU64LE(data, base + word * 8);\n if (bits === 0n) continue;\n for (let bit = 0; bit < 64; bit++) {\n if ((bits >> BigInt(bit)) & 1n) {\n used.push(word * 64 + bit);\n }\n }\n }\n return used;\n}\n\n/**\n * Check if a specific account index is used.\n */\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\n const layout = detectSlabLayout(data.length, data);\n if (!layout) return false;\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\n const base = layout.engineOff + layout.engineBitmapOff;\n const word = Math.floor(idx / 64);\n const bit = idx % 64;\n const bits = readU64LE(data, base + word * 8);\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\n}\n\n/**\n * Calculate the maximum valid account index for a given slab size.\n */\nexport function maxAccountIndex(dataLen: number): number {\n const layout = detectSlabLayout(dataLen);\n if (!layout) return 0;\n const accountsEnd = dataLen - layout.accountsOff;\n if (accountsEnd <= 0) return 0;\n return Math.floor(accountsEnd / layout.accountSize);\n}\n\n/**\n * Parse a single account by index.\n */\nexport function parseAccount(data: Uint8Array, idx: number): Account {\n const layout = detectSlabLayout(data.length, data);\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\n\n const maxIdx = maxAccountIndex(data.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\n }\n\n const base = layout.accountsOff + idx * layout.accountSize;\n if (data.length < base + layout.accountSize) {\n throw new Error(\"Slab data too short for account\");\n }\n\n // Select layout-dependent account field offsets.\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\n // Pre-ADL (account_size<312): original offsets.\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\n\n if (isV12_17) {\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\n //\n // SBF vs native alignment delta:\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\n\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\n\n return {\n kind,\n accountId: 0n, // removed in v12.17\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\n warmupStartedAtSlot: 0n, // removed\n warmupSlopePerStep: 0n, // removed\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\n lastFeeSlot: 0n, // removed\n feesEarnedTotal: 0n, // removed in v12.17\n exactReserveCohorts: null, // replaced by two-bucket warmup\n exactCohortCount: null,\n overflowOlder: null,\n overflowOlderPresent: null,\n overflowNewest: null,\n overflowNewestPresent: null,\n\n // V12_17 fields\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\n };\n }\n\n if (isV12_15) {\n // V12_15 fast path: fixed offsets, all fields explicit.\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\n\n // Parse the 62 reserve cohorts\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\n const exactReserveCohorts: ReserveCohortBytes[] = [];\n for (let i = 0; i < 62; i++) {\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\n }\n\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\n\n return {\n kind,\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\n warmupStartedAtSlot: 0n, // removed in v12.15\n warmupSlopePerStep: 0n, // removed in v12.15\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\n fundingIndex: 0n, // not present in v12.15 account struct\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\n lastFeeSlot: 0n, // removed in v12.15\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\n exactReserveCohorts,\n exactCohortCount: cohortCount,\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\n overflowOlderPresent,\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\n overflowNewestPresent,\n\n // v12.17 fields (not present in v12.15)\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\n };\n }\n\n // Pre-v12.15 path\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\n 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));\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\n 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));\n 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));\n 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));\n 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));\n\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\n\n return {\n kind,\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\n positionSize: readI128LE(data, base + positionSizeOff),\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\n // V12_1/V12_1_EP: funding_index not present in SBF layout\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\n feeCredits: readI128LE(data, base + feeCreditsOff),\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\n exactCohortCount: null,\n overflowOlder: null,\n overflowOlderPresent: null,\n overflowNewest: null,\n overflowNewestPresent: null,\n\n // v12.17 fields (not present in pre-v12.17)\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\n };\n}\n\n// =============================================================================\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\n//\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\n// is a full account-layout break — every v16-version market account is\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\n// =============================================================================\n\n/**\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\n * Stored at bytes [0..8] of every v17 percolator-owned account.\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\n */\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\n\n/**\n * v17 account version (u16 at offset 8).\n *\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\n */\nexport const V17_EXPECTED_VERSION = 17;\n\n/**\n * v17 account-kind byte (offset 10 of the 16-byte header).\n *\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\n * discovery — every other kind shares the same magic+version and would falsely\n * pass the looser {@link isV17Account} check (#264).\n */\nexport const V17_KIND_MARKET = 1;\n\n/** Byte offset of the v17 account-kind discriminator within the header. */\nexport const V17_KIND_OFF = 10;\n\n/**\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\n *\n * Growth history, each stage purely additive at the tail with all earlier\n * offsets UNCHANGED:\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\n * @432, `protocol_fee_accrued_atoms` u128 @464,\n * `protocol_fee_withdrawn_atoms` u128 @480.\n * 496 -> 576 fee-collection split (percolator-prog\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\n * @496/512/528/544, three u16 shares @560/562/564, then\n * `_padding_split` [u8;10] @566.\n *\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\n * it is u128-aligned; placing the u16 shares first would push the u128s to\n * offset 502 and force the compiler to insert implicit padding, failing the\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\n * padding out to the 16-byte alignment boundary.\n *\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\n * at line 1159.\n *\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\n * still carries the 496-byte layout. Reading a market created by that build\n * with this decoder will throw \"data too short\"; a 576-byte read against a\n * 496-byte account is a length error, not a silent misparse.\n */\nexport const V17_WRAPPER_CONFIG_LEN = 576;\n\n/**\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\n *\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\n * `_padding_split` tail at the only 8-aligned slot inside it, so\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\n * 592, and NO pre-existing offset moves. Growing the config instead would have\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\n * markets — a repeat of the 496→576 incident. If you ever find yourself\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\n *\n * Source of truth: percolator-prog `src/v16_program.rs` struct\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\n */\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\n\n/** v17 AssetOracleProfileV16 length (400 bytes). */\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\n\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\nexport const V17_HEADER_LEN = 16;\n\n/**\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\n * downstream offset in this file chains off it.\n */\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\n\n/**\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\n * verified against percolator-prog `cargo run --example dump_layout`.\n */\nexport const V17_MARKET_GROUP_LEN = 758;\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\n\n/**\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\n */\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\n }\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\n}\n\n/**\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\n */\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\n\n/**\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\n *\n * Field offsets follow SBF alignment (u128 align=8, not 16).\n * Full offset table (verified against v17 wrapper source v16_program.rs,\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\n * 0 marketauth [32]\n * 32 collateral_mint [32]\n * 64 secondary_collateral_mint [32]\n * 96 maintenance_fee_per_slot u128\n * 112 permissionless_market_init_fee u128\n * 128 trade_fee_base_bps u64\n * 136 permissionless_resolve_stale_slots u64\n * 144 force_close_delay_slots u64\n * 152 last_good_oracle_slot u64\n * 160 insurance_withdraw_deposit_remaining u128\n * 176 insurance_withdraw_max_bps u16\n * 178 liquidation_cranker_fee_share_bps u16\n * 180 maintenance_cranker_fee_share_bps u16\n * 182 backing_trade_fee_bps_long u16\n * 184 unit_scale u32\n * 188 conf_filter_bps u16\n * 190 backing_trade_fee_bps_short u16\n * 192 insurance_withdraw_deposits_only u8\n * 193 oracle_mode u8\n * 194 oracle_leg_count u8\n * 195 oracle_leg_flags u8\n * 196 invert u8\n * 197 _padding0 u8\n * 198 free_market_slot_count u16\n * 200 insurance_withdraw_cooldown_slots u64\n * 208 last_insurance_withdraw_slot u64\n * 216 max_staleness_secs u64\n * 224 hybrid_soft_stale_slots u64\n * 232 mark_ewma_e6 u64\n * 240 mark_ewma_last_slot u64\n * 248 mark_ewma_halflife_slots u64\n * 256 mark_min_fee u64\n * 264 oracle_target_price_e6 u64\n * 272 oracle_target_publish_time i64\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\n * 400 oracle_leg_publish_times [i64;3] (24B)\n * 424 backing_trade_fee_policy_count u16\n * 426 backing_trade_fee_insurance_share_bps_long u16\n * 428 backing_trade_fee_insurance_share_bps_short u16\n * 430 fee_redirect_to_market_0_bps u16\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\n * 432 protocol_fee_authority [32]\n * 464 protocol_fee_accrued_atoms u128\n * 480 protocol_fee_withdrawn_atoms u128\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\n * 496 lp_fee_accrued_atoms u128\n * 512 lp_fee_withdrawn_atoms u128\n * 528 insurance_reserve_accrued_atoms u128\n * 544 insurance_reserve_withdrawn_atoms u128\n * 560 creator_share_bps u16\n * 562 lp_share_bps u16\n * 564 insurance_share_bps u16\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\n * Total: 576\n */\nexport interface WrapperConfigV17 {\n marketauth: PublicKey;\n collateralMint: PublicKey;\n secondaryCollateralMint: PublicKey;\n maintenanceFeePerSlot: bigint;\n permissionlessMarketInitFee: bigint;\n tradeFeeBps: bigint;\n permissionlessResolveStaleSlots: bigint;\n forceCloseDelaySlots: bigint;\n lastGoodOracleSlot: bigint;\n insuranceWithdrawDepositRemaining: bigint;\n insuranceWithdrawMaxBps: number;\n liquidationCrankerFeeShareBps: number;\n maintenanceCrankerFeeShareBps: number;\n backingTradeFeeBpsLong: number;\n unitScale: number;\n confFilterBps: number;\n backingTradeFeeBpsShort: number;\n insuranceWithdrawDepositsOnly: number;\n oracleMode: number;\n oracleLegCount: number;\n oracleLegFlags: number;\n invert: number;\n freeMarketSlotCount: number;\n insuranceWithdrawCooldownSlots: bigint;\n lastInsuranceWithdrawSlot: bigint;\n maxStalenessSecs: bigint;\n hybridSoftStaleSlots: bigint;\n markEwmaE6: bigint;\n markEwmaLastSlot: bigint;\n markEwmaHalflifeSlots: bigint;\n markMinFee: bigint;\n oracleTargetPriceE6: bigint;\n oracleTargetPublishTime: bigint;\n oracleLegFeeds: PublicKey[];\n oracleLegPricesE6: bigint[];\n oracleLegPublishTimes: bigint[];\n backingTradeFeePolicyCount: number;\n backingTradeFeeInsuranceShareBpsLong: number;\n backingTradeFeeInsuranceShareBpsShort: number;\n feeRedirectToMarket0Bps: number;\n /**\n * Destination pubkey for the protocol's accrued fee share. Set to a\n * hardcoded program-level constant at InitMarket; rotatable only via\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\n * by marketauth/insurance_authority/any creator-facing gate.\n */\n protocolFeeAuthority: PublicKey;\n /**\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\n * itself credited into any domain's insurance budget — tracks an\n * unbudgeted slice of header.insurance no insurance_operator can reach.\n */\n protocolFeeAccruedAtoms: bigint;\n /**\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\n */\n protocolFeeWithdrawnAtoms: bigint;\n /**\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\n * principal.\n *\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\n * it can be impaired by backing losses between crank and redemption.\n *\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\n * can never be cranked. Outstanding = accrued - withdrawn.\n */\n lpFeeAccruedAtoms: bigint;\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\n lpFeeWithdrawnAtoms: bigint;\n /**\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\n * bound stake pool's vault.\n *\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\n * unbudgeted by construction. Keepers should crank before resolution.\n */\n insuranceReserveAccruedAtoms: bigint;\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\n insuranceReserveWithdrawnAtoms: bigint;\n /**\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\n * (3600). Lands in insurance_domain_budget; claimed via\n * WithdrawInsuranceAsset (tag 57).\n */\n creatorShareBps: number;\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\n lpShareBps: number;\n /**\n * Insurance/staker share of T in bps. Default 1600, floor\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\n * split_trade_fee computes this leg as the remainder.\n */\n insuranceShareBps: number;\n /**\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\n *\n * This is the honest claimable balance a creator-claim UI should display.\n * Before the creator-fee-claim change the creator leg was credited into the\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\n * had no on-chain representation at all and a claim button was really a\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\n * alone.\n *\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\n * / insurance legs above, this is a single live balance: trades add to it and\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\n * claimable right now. (Forced by the 10-byte pad budget; see\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\n *\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\n * were explicit padding, so the value is well-defined rather than garbage,\n * and the counter simply accrues fresh after an in-place upgrade.\n */\n creatorFeeClaimableAtoms: bigint;\n}\n\n/**\n * Parse a v17 WrapperConfigV16 block from raw account data.\n *\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\n *\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\n * This function reads the 496-byte wrapper config block directly. It does NOT\n * validate the account header magic or version — callers must do that separately.\n *\n * @param data Raw bytes of the market group account.\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\n * @returns Parsed WrapperConfigV17 object.\n *\n * @example\n * ```ts\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\n * if (!accountInfo) throw new Error(\"account not found\");\n * const magic = readU64FromBytes(accountInfo.data, 0);\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\n * const config = parseWrapperConfigV17(accountInfo.data);\n * console.log(config.collateralMint.toBase58());\n * ```\n */\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\n if (data.length < MIN_LEN) {\n throw new Error(\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\n );\n }\n\n const b = configOff;\n\n // Offsets from the WrapperConfigV16 offset table above\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\n const tradeFeeBps = readU64LE(data, b + 128);\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\n const forceCloseDelaySlots = readU64LE(data, b + 144);\n const lastGoodOracleSlot = readU64LE(data, b + 152);\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\n const unitScale = readU32LE(data, b + 184);\n const confFilterBps = readU16LE(data, b + 188);\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\n const oracleMode = readU8(data, b + 193);\n const oracleLegCount = readU8(data, b + 194);\n const oracleLegFlags = readU8(data, b + 195);\n const invert = readU8(data, b + 196);\n // _padding0 at b+197\n const freeMarketSlotCount = readU16LE(data, b + 198);\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\n const maxStalenessSecs = readU64LE(data, b + 216);\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\n const markEwmaE6 = readU64LE(data, b + 232);\n const markEwmaLastSlot = readU64LE(data, b + 240);\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\n const markMinFee = readU64LE(data, b + 256);\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\n\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\n const ORACLE_LEG_CAP = 3;\n const oracleLegFeeds: PublicKey[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\n }\n\n // oracle_leg_prices_e6: [u64;3] at b+376\n const oracleLegPricesE6: bigint[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\n }\n\n // oracle_leg_publish_times: [i64;3] at b+400\n const oracleLegPublishTimes: bigint[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\n }\n\n // Tail policy fields at b+424\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\n\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\n\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\n const creatorShareBps = readU16LE(data, b + 560);\n const lpShareBps = readU16LE(data, b + 562);\n const insuranceShareBps = readU16LE(data, b + 564);\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\n\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\n\n return {\n marketauth,\n collateralMint,\n secondaryCollateralMint,\n maintenanceFeePerSlot,\n permissionlessMarketInitFee,\n tradeFeeBps,\n permissionlessResolveStaleSlots,\n forceCloseDelaySlots,\n lastGoodOracleSlot,\n insuranceWithdrawDepositRemaining,\n insuranceWithdrawMaxBps,\n liquidationCrankerFeeShareBps,\n maintenanceCrankerFeeShareBps,\n backingTradeFeeBpsLong,\n unitScale,\n confFilterBps,\n backingTradeFeeBpsShort,\n insuranceWithdrawDepositsOnly,\n oracleMode,\n oracleLegCount,\n oracleLegFlags,\n invert,\n freeMarketSlotCount,\n insuranceWithdrawCooldownSlots,\n lastInsuranceWithdrawSlot,\n maxStalenessSecs,\n hybridSoftStaleSlots,\n markEwmaE6,\n markEwmaLastSlot,\n markEwmaHalflifeSlots,\n markMinFee,\n oracleTargetPriceE6,\n oracleTargetPublishTime,\n oracleLegFeeds,\n oracleLegPricesE6,\n oracleLegPublishTimes,\n backingTradeFeePolicyCount,\n backingTradeFeeInsuranceShareBpsLong,\n backingTradeFeeInsuranceShareBpsShort,\n feeRedirectToMarket0Bps,\n protocolFeeAuthority,\n protocolFeeAccruedAtoms,\n protocolFeeWithdrawnAtoms,\n lpFeeAccruedAtoms,\n lpFeeWithdrawnAtoms,\n insuranceReserveAccruedAtoms,\n insuranceReserveWithdrawnAtoms,\n creatorShareBps,\n lpShareBps,\n insuranceShareBps,\n creatorFeeClaimableAtoms,\n };\n}\n\n/**\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\n *\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\n * 0 oracle_mode u8\n * 1 oracle_leg_count u8\n * 2 oracle_leg_flags u8\n * 3 invert u8\n * 4 unit_scale u32\n * 8 conf_filter_bps u16\n * 10 backing_trade_fee_bps_long u16\n * 12 backing_trade_fee_bps_short u16\n * 14 backing_trade_fee_insurance_share_bps_long u16\n * 16 backing_trade_fee_insurance_share_bps_short u16\n * 18 _padding0 [u8;6]\n * 24 insurance_authority [32]\n * 56 insurance_operator [32]\n * 88 backing_bucket_authority [32]\n * 120 oracle_authority [32]\n * 152 max_staleness_secs u64\n * 160 hybrid_soft_stale_slots u64\n * 168 mark_ewma_e6 u64\n * 176 mark_ewma_last_slot u64\n * 184 mark_ewma_halflife_slots u64\n * 192 mark_min_fee u64\n * 200 oracle_target_price_e6 u64\n * 208 oracle_target_publish_time i64\n * 216 last_good_oracle_slot u64\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\n * 344 oracle_leg_publish_times [i64;3] (24B)\n * 368 asset_admin [32] ← v17 NEW\n * Total: 400\n */\nexport interface AssetOracleProfileV17 {\n oracleMode: number;\n oracleLegCount: number;\n oracleLegFlags: number;\n invert: number;\n unitScale: number;\n confFilterBps: number;\n backingTradeFeeBpsLong: number;\n backingTradeFeeBpsShort: number;\n backingTradeFeeInsuranceShareBpsLong: number;\n backingTradeFeeInsuranceShareBpsShort: number;\n insuranceAuthority: PublicKey;\n insuranceOperator: PublicKey;\n backingBucketAuthority: PublicKey;\n oracleAuthority: PublicKey;\n maxStalenessSecs: bigint;\n hybridSoftStaleSlots: bigint;\n markEwmaE6: bigint;\n markEwmaLastSlot: bigint;\n markEwmaHalflifeSlots: bigint;\n markMinFee: bigint;\n oracleTargetPriceE6: bigint;\n oracleTargetPublishTime: bigint;\n lastGoodOracleSlot: bigint;\n oracleLegFeeds: PublicKey[];\n oracleLegPricesE6: bigint[];\n oracleLegPublishTimes: bigint[];\n /** v17 NEW: asset_admin pubkey at offset 368. */\n assetAdmin: PublicKey;\n}\n\n/**\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\n *\n * @param data Raw bytes containing the profile block.\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\n * @returns Parsed AssetOracleProfileV17 object.\n */\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\n if (data.length < MIN_LEN) {\n throw new Error(\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\n );\n }\n\n const b = profileOff;\n const ORACLE_LEG_CAP = 3;\n\n const oracleLegFeeds: PublicKey[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\n }\n\n const oracleLegPricesE6: bigint[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\n }\n\n const oracleLegPublishTimes: bigint[] = [];\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\n }\n\n return {\n oracleMode: readU8(data, b + 0),\n oracleLegCount: readU8(data, b + 1),\n oracleLegFlags: readU8(data, b + 2),\n invert: readU8(data, b + 3),\n unitScale: readU32LE(data, b + 4),\n confFilterBps: readU16LE(data, b + 8),\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\n maxStalenessSecs: readU64LE(data, b + 152),\n hybridSoftStaleSlots: readU64LE(data, b + 160),\n markEwmaE6: readU64LE(data, b + 168),\n markEwmaLastSlot: readU64LE(data, b + 176),\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\n markMinFee: readU64LE(data, b + 192),\n oracleTargetPriceE6: readU64LE(data, b + 200),\n oracleTargetPublishTime: readI64LE(data, b + 208),\n lastGoodOracleSlot: readU64LE(data, b + 216),\n oracleLegFeeds,\n oracleLegPricesE6,\n oracleLegPublishTimes,\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\n };\n}\n\n/**\n * Check if a raw account buffer contains a v17 percolator account.\n *\n * @param data Raw account bytes.\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\n */\nexport function isV17Account(data: Uint8Array): boolean {\n if (data.length < 10) return false;\n const magic = readU64LE(data, 0);\n const version = readU16LE(data, 8);\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\n}\n\n/**\n * Check if a raw account buffer is a v17 percolator MARKET account.\n *\n * Stricter than {@link isV17Account}: requires both that the account is a valid\n * v17 account (magic + version) AND that the kind byte at offset 10 is\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\n *\n * @param data Raw account bytes.\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\n */\nexport function isV17MarketAccount(data: Uint8Array): boolean {\n if (data.length < V17_KIND_OFF + 1) return false;\n if (!isV17Account(data)) return false;\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\n}\n\n// =============================================================================\n// V17 OI parser\n// =============================================================================\n\n/**\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\n */\nconst V17_HEADER_INSURANCE_OFF = 301;\n\n/**\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\n */\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\n\n/**\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\n * oi_eff_short_q follows at 273 + 16 = 289\n */\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\n\n/**\n * Aggregated open-interest parsed from a v17 market group account.\n *\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\n * slots in the account and also returns per-asset breakdown.\n *\n * All quantities are in token micro-units (raw, not scaled by decimals).\n */\nexport interface V17MarketGroupOI {\n /** Group-level insurance reserve (u128, micro-units) */\n insuranceBalance: bigint;\n /** Sum of oi_eff_long_q across all asset slots */\n totalLongOiQ: bigint;\n /** Sum of oi_eff_short_q across all asset slots */\n totalShortOiQ: bigint;\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\n assets: Array<{\n assetIndex: number;\n oiEffLongQ: bigint;\n oiEffShortQ: bigint;\n }>;\n}\n\n/**\n * Parse open-interest fields from a v17 market group account.\n *\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\n * which follows the 512-byte wrapper T at the start of each slot).\n *\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\n * (which forbids implicit padding), so these are exact byte offsets.\n *\n * The absolute offsets below follow from the CURRENT wrapper layout —\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\n * - insurance: 592 + 301 = 893\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\n *\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\n * giving insurance @ 813. The CODE was always correct — it composes the named\n * constants — but the stated numbers were stale. Verified against the first real\n * v17 market on the new devnet deployment.)\n *\n * @param data Raw bytes of the v17 market group account.\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\n * @throws Error if the buffer is not a valid v17 market account or is too short.\n *\n * @example\n * ```ts\n * const info = await connection.getAccountInfo(marketGroupPk);\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\n * ```\n */\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\n if (data.length < MIN_LEN) {\n throw new Error(\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\n );\n }\n if (!isV17MarketAccount(data)) {\n throw new Error(\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\n );\n }\n\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\n const insuranceBalance = readU128LE(data, insuranceOff);\n\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\n const numSlots = Math.floor(\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\n );\n\n let totalLongOiQ = 0n;\n let totalShortOiQ = 0n;\n const assets: V17MarketGroupOI[\"assets\"] = [];\n\n for (let i = 0; i < numSlots; i++) {\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\n const longOff =\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\n const shortOff =\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\n\n // Guard against a truncated buffer (should not happen on well-formed accounts).\n if (shortOff + 16 > data.length) break;\n\n const oiEffLongQ = readU128LE(data, longOff);\n const oiEffShortQ = readU128LE(data, shortOff);\n\n totalLongOiQ += oiEffLongQ;\n totalShortOiQ += oiEffShortQ;\n\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\n }\n }\n\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\n}\n\n// =============================================================================\n// V17 account decoders (DESYNC fixes — new standalone account types)\n// =============================================================================\n\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\nconst V17_ACCOUNT_HEADER_LEN = 16;\nconst V17_KIND_PORTFOLIO = 2;\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\nconst V17_KIND_LP_REDEMPTION = 6;\n\nfunction assertV17StandaloneHeader(\n data: Uint8Array,\n parserName: string,\n expectedKind: number,\n): void {\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\n }\n const magic = readU64LE(data, 0);\n if (magic !== V17_MAGIC) {\n throw new Error(`${parserName}: invalid v17 magic`);\n }\n const version = readU16LE(data, 8);\n if (version !== V17_EXPECTED_VERSION) {\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\n }\n const kind = readU8(data, 10);\n if (kind !== expectedKind) {\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\n }\n}\n\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\n// PortfolioLegV16Account (144 bytes each):\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\nconst PF_LEG_SIZE = 144;\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\nconst PF_LEGS_COUNT = 16;\n// PortfolioSourceDomainV16Account (196 bytes each):\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\nconst PF_SOURCE_DOMAIN_SIZE = 196;\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\n// HealthCertV16Account (121 bytes):\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\n// CloseProgressLedgerV16Account (188 bytes):\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\n// ResolvedPayoutReceiptV16Account (66 bytes):\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\n\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\n// noted above (188) does not even match its own field breakdown (sums to 184; see\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\n// the same anchor-from-the-end offset).\nconst PF_MATCHER_CONFIG_LEN = 104;\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\n\n/** Per-leg decoded data returned by parsePortfolioV17. */\nexport interface PortfolioLegV17 {\n active: boolean;\n assetIndex: number;\n marketId: bigint;\n /** 0 = long, 1 = short */\n side: number;\n basisPosQ: bigint;\n aBasis: bigint;\n kSnap: bigint;\n fSnap: bigint;\n epochSnap: bigint;\n lossWeight: bigint;\n bSnap: bigint;\n bRem: bigint;\n bEpochSnap: bigint;\n bStale: boolean;\n stale: boolean;\n}\n\n/** Per source-domain slot returned by parsePortfolioV17. */\nexport interface PortfolioSourceDomainV17 {\n domain: number;\n sourceClaimMarketId: bigint;\n sourceClaimBoundNum: bigint;\n sourceClaimLienedNum: bigint;\n sourceClaimCounterpartyLienedNum: bigint;\n sourceClaimInsuranceLienedNum: bigint;\n sourceLienEffectiveReserved: bigint;\n sourceLienCounterpartyBackingNum: bigint;\n sourceLienInsuranceBackingNum: bigint;\n sourceLienFeeLastSlot: bigint;\n sourceClaimImpairedNum: bigint;\n sourceLienImpairedEffectiveReserved: bigint;\n sourceLienCapitalAtRiskFeeRevenue: bigint;\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\n}\n\n/** Decoded v17 PortfolioAccountV16Account. */\nexport interface PortfolioV17 {\n /** Market group this portfolio belongs to. */\n marketGroupId: PublicKey;\n /** Portfolio account identity pubkey (immutable PDA). */\n portfolioAccountId: PublicKey;\n /** Owner wallet pubkey from the provenance header. */\n provenanceOwner: PublicKey;\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\n owner: PublicKey;\n /** Collateral capital in atoms (u128). */\n capital: bigint;\n /** Unrealised P&L in atoms (i128). */\n pnl: bigint;\n /** Capital reserved for pending payout (u128). */\n reservedPnl: bigint;\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\n residualCrystallizedLossAtomsTotal: bigint;\n /** Genesis farming: cumulative spent principal atoms (u128). */\n residualSpentPrincipalAtomsTotal: bigint;\n /** Genesis farming: cumulative received atoms (u128). */\n residualReceivedAtomsTotal: bigint;\n /** Fee credits (i128, can be negative). */\n feeCredits: bigint;\n /** Cancel-deposit escrow holding (u128). */\n cancelDepositEscrow: bigint;\n /** Slot when fees were last accrued. */\n lastFeeSlot: bigint;\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\n activeBitmap: bigint;\n /** All 16 position leg slots (active or empty). */\n legs: PortfolioLegV17[];\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\n sourceDomains: PortfolioSourceDomainV17[];\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\n matcherProgram: PublicKey;\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\n matcherContext: PublicKey;\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\n matcherDelegate: PublicKey;\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\n matcherEnabled: boolean;\n}\n\n/**\n * Parse a v17 PortfolioAccountV16Account from raw account data.\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\n *\n * @param data - Raw account bytes from `connection.getAccountInfo`.\n * @returns Decoded portfolio state.\n * @throws If data is too short or magic does not match.\n *\n * @example\n * ```typescript\n * const info = await connection.getAccountInfo(portfolioPubkey);\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\n * console.log('capital:', portfolio.capital);\n * ```\n */\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\n if (data.length < MIN_PORTFOLIO_BYTES) {\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\n }\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\n\n // Provenance header\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\n\n // Body fields\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\n const capital = readU128LE(data, PF_CAPITAL_OFF);\n const pnl = readI128LE(data, PF_PNL_OFF);\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\n\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\n\n // Legs\n const legs: PortfolioLegV17[] = [];\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\n if (data.length < b + PF_LEG_SIZE) break;\n legs.push({\n active: data[b] !== 0,\n assetIndex: readU32LE(data, b + 1),\n marketId: readU64LE(data, b + 5),\n side: data[b + 13],\n basisPosQ: readI128LE(data, b + 14),\n aBasis: readU128LE(data, b + 30),\n kSnap: readI128LE(data, b + 46),\n fSnap: readI128LE(data, b + 62),\n epochSnap: readU64LE(data, b + 78),\n lossWeight: readU128LE(data, b + 86),\n bSnap: readU128LE(data, b + 102),\n bRem: readU128LE(data, b + 118),\n bEpochSnap: readU64LE(data, b + 134),\n bStale: data[b + 142] !== 0,\n stale: data[b + 143] !== 0,\n });\n }\n\n // Source domains\n const sourceDomains: PortfolioSourceDomainV17[] = [];\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\n sourceDomains.push({\n domain: readU32LE(data, b + 0),\n sourceClaimMarketId: readU64LE(data, b + 4),\n sourceClaimBoundNum: readU128LE(data, b + 12),\n sourceClaimLienedNum: readU128LE(data, b + 28),\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\n sourceClaimImpairedNum: readU128LE(data, b + 132),\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\n });\n }\n\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\n : PublicKey.default;\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\n : PublicKey.default;\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\n : PublicKey.default;\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\n // for an account the program itself would refuse to operate on.\n let matcherEnabled = false;\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\n if (rawEnabled > 1n) {\n throw new Error(\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\n );\n }\n matcherEnabled = rawEnabled === 1n;\n }\n\n return {\n marketGroupId,\n portfolioAccountId,\n provenanceOwner,\n owner,\n capital,\n pnl,\n reservedPnl,\n residualCrystallizedLossAtomsTotal,\n residualSpentPrincipalAtomsTotal,\n residualReceivedAtomsTotal,\n feeCredits,\n cancelDepositEscrow,\n lastFeeSlot,\n activeBitmap,\n legs,\n sourceDomains,\n matcherProgram,\n matcherContext,\n matcherDelegate,\n matcherEnabled,\n };\n}\n\n// =============================================================================\n// LpVaultRegistryV16 decoder\n// =============================================================================\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\n// _padding[6]+_reserved[16] = 160 bytes.\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\n\n/** Decoded v17 LpVaultRegistryV16 account. */\nexport interface LpVaultRegistryV17 {\n marketGroup: PublicKey;\n lpMint: PublicKey;\n totalLpSharesOutstanding: bigint;\n insuranceFeeSnapshotAtoms: bigint;\n feeDistributionTotalAtoms: bigint;\n epoch: bigint;\n redemptionCooldownSlots: bigint;\n feeShareBps: number;\n oiReservationThresholdBps: number;\n domain: number;\n paused: boolean;\n version: number;\n bump: number;\n mintBump: number;\n}\n\n/**\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\n *\n * @param data - Raw account bytes.\n * @returns Decoded LP vault registry state.\n * @throws If data is shorter than 176 bytes.\n *\n * @example\n * ```typescript\n * const info = await connection.getAccountInfo(registryPubkey);\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\n * ```\n */\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\n throw new Error(\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\n );\n }\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\n return {\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\n totalLpSharesOutstanding: readU128LE(data, b + 64),\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\n epoch: readU64LE(data, b + 112),\n redemptionCooldownSlots: readU64LE(data, b + 120),\n feeShareBps: readU16LE(data, b + 128),\n oiReservationThresholdBps: readU16LE(data, b + 130),\n domain: readU16LE(data, b + 132),\n paused: data[b + 134] !== 0,\n version: data[b + 135],\n bump: data[b + 136],\n mintBump: data[b + 137],\n };\n}\n\n// =============================================================================\n// LpRedemptionV16 decoder\n// =============================================================================\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\n\n/** Decoded v17 LpRedemptionV16 account. */\nexport interface LpRedemptionV17 {\n registry: PublicKey;\n redeemer: PublicKey;\n /** LP shares requested for redemption (u128). */\n shares: bigint;\n /** Slot when RequestRedeemLpShares was called. */\n requestSlot: bigint;\n version: number;\n bump: number;\n}\n\n/**\n * Parse a v17 LpRedemptionV16 account from raw bytes.\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\n *\n * @param data - Raw account bytes.\n * @returns Decoded LP redemption request state.\n * @throws If data is shorter than 112 bytes.\n *\n * @example\n * ```typescript\n * const info = await connection.getAccountInfo(redemptionPubkey);\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\n * ```\n */\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\n if (data.length < LP_REDEMPTION_TOTAL) {\n throw new Error(\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\n );\n }\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\n return {\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\n shares: readU128LE(data, b + 64),\n requestSlot: readU64LE(data, b + 80),\n version: data[b + 88],\n bump: data[b + 89],\n };\n}\n\n/**\n * Parse all used accounts.\n */\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\n const indices = parseUsedIndices(data);\n const maxIdx = maxAccountIndex(data.length);\n const validIndices = indices.filter(idx => idx < maxIdx);\n const droppedCount = indices.length - validIndices.length;\n if (droppedCount > 0) {\n console.warn(\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\n );\n }\n return validIndices.map(idx => ({\n idx,\n account: parseAccount(data, idx),\n }));\n}\n","import { PublicKey } from \"@solana/web3.js\";\n\nconst textEncoder = new TextEncoder();\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Encode a u16 as a 2-byte little-endian buffer.\n * Used for PDA seed segments that include a domain/index as u16 LE.\n */\nfunction u16LE(value: number): Uint8Array {\n if (\n typeof value !== \"number\" ||\n !Number.isInteger(value) ||\n value < 0 ||\n value > 0xffff\n ) {\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\n }\n const buf = new Uint8Array(2);\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\n return buf;\n}\n\n/**\n * Derive vault authority PDA.\n * Seeds: [\"vault\", slab_key]\n *\n * Mirrors `derive_vault_authority(program_id, market_key)` in\n * `percolator-prog/src/v16_program.rs:17339-17341`.\n */\nexport function deriveVaultAuthority(\n programId: PublicKey,\n slab: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"vault\"), slab.toBytes()],\n programId\n );\n}\n\n// ---------------------------------------------------------------------------\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\n// ---------------------------------------------------------------------------\n\n/**\n * SPL Associated Token Account program.\n *\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\n */\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n);\n\n/**\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\n *\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\n * ATA's middle seed is always this program id.\n */\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\n);\n\n/**\n * Derive the CANONICAL vault token account for a market + collateral mint.\n *\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\n *\n * ```text\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\n * ```\n *\n * Mirrors `canonical_vault_address(vault_authority, mint)`\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\n * without it an attacker could route deposits to a second `vault_authority`-owned account\n * and strand honest withdrawals against the canonical one.\n *\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\n * address with a detected token program would produce a key the program rejects with\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\n *\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\n * token path.\n *\n * @param programId - The Percolator wrapper program ID (the market's owner).\n * @param market - The v17 market group (slab) public key.\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\n *\n * @example\n * ```ts\n * const cfg = parseWrapperConfigV17(marketData);\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\n * ```\n */\nexport function deriveCanonicalVault(\n programId: PublicKey,\n market: PublicKey,\n mint: PublicKey\n): [PublicKey, number] {\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\n}\n\n/**\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\n *\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\n *\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\n * @param mint - The market's collateral mint.\n * @returns `[vaultTokenAccount, bump]`\n *\n * @example\n * ```ts\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\n * ```\n */\nexport function deriveCanonicalVaultForAuthority(\n vaultAuthority: PublicKey,\n mint: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [\n vaultAuthority.toBytes(),\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\n mint.toBytes(),\n ],\n ASSOCIATED_TOKEN_PROGRAM_ID\n );\n}\n\n/** Both halves of a market's vault, as required by tags 84 and 87. */\nexport interface MarketVaultAccounts {\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\n vaultAuthority: PublicKey;\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\n vaultAuthorityBump: number;\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\n vaultToken: PublicKey;\n /** Bump for `vaultToken`. */\n vaultTokenBump: number;\n /** The token program that must be passed alongside — always legacy SPL Token. */\n tokenProgram: PublicKey;\n}\n\n/**\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\n *\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\n * the vault token account, the vault authority PDA and the token program as three separate\n * accounts that must agree with one another; deriving them together makes disagreement\n * impossible.\n *\n * Account positions:\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\n *\n * @param programId - The Percolator wrapper program ID.\n * @param market - The v17 market group (slab) public key.\n * @param mint - The market's collateral mint.\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\n *\n * @example\n * ```ts\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\n * const keys = [\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\n * { pubkey: marketPk, isSigner: false, isWritable: true },\n * { pubkey: destToken, isSigner: false, isWritable: true },\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\n * ];\n * ```\n */\nexport function deriveMarketVaultAccounts(\n programId: PublicKey,\n market: PublicKey,\n mint: PublicKey\n): MarketVaultAccounts {\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\n vaultAuthority,\n mint\n );\n return {\n vaultAuthority,\n vaultAuthorityBump,\n vaultToken,\n vaultTokenBump,\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\n };\n}\n\n/**\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\n * Seeds: [\"lp_vault_mint\", slab_key]\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\n */\nexport function deriveInsuranceLpMint(\n programId: PublicKey,\n slab: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\n programId\n );\n}\n\nconst LP_INDEX_U16_MAX = 0xffff;\n\n/**\n * Derive LP PDA for TradeCpi.\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\n */\nexport function deriveLpPda(\n programId: PublicKey,\n slab: PublicKey,\n lpIdx: number\n): [PublicKey, number] {\n if (\n typeof lpIdx !== \"number\" ||\n !Number.isInteger(lpIdx) ||\n lpIdx < 0 ||\n lpIdx > LP_INDEX_U16_MAX\n ) {\n throw new Error(\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\n );\n }\n const idxBuf = new Uint8Array(2);\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\n programId\n );\n}\n\n// ---------------------------------------------------------------------------\n// DEX Program IDs\n// ---------------------------------------------------------------------------\n\n/** PumpSwap AMM program ID. */\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\n);\n\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\n);\n\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\n);\n\n// ---------------------------------------------------------------------------\n// Pyth Push Oracle\n// ---------------------------------------------------------------------------\n\n/** Pyth Push Oracle program on mainnet. */\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\n);\n\n// ---------------------------------------------------------------------------\n// Creator Lock PDA (PERC-627)\n// ---------------------------------------------------------------------------\n\n/**\n * Seed used to derive the creator lock PDA.\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\n */\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\n\n/**\n * Derive the creator lock PDA for a given slab.\n * Seeds: [\"creator_lock\", slab_key]\n *\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\n *\n * @param programId - The percolator program ID.\n * @param slab - The slab (market) public key.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\n * ```\n */\nexport function deriveCreatorLockPda(\n programId: PublicKey,\n slab: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\n programId\n );\n}\n\n// ---------------------------------------------------------------------------\n// LP Vault PDAs (v17 — tags 74-80)\n// ---------------------------------------------------------------------------\n\n/**\n * Derive the LP Vault registry PDA.\n * Seeds: [\"lp_vault\", marketGroup]\n *\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\n *\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\n *\n * @param programId - The Percolator program ID.\n * @param marketGroup - The market group (slab) public key.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\n * ```\n */\nexport function deriveLpVaultRegistry(\n programId: PublicKey,\n marketGroup: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\n programId\n );\n}\n\n/**\n * Derive the LP redemption ticket PDA for a specific redeemer.\n * Seeds: [\"lp_redemption\", registry, redeemer]\n *\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\n *\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\n *\n * @param programId - The Percolator program ID.\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\n * @param redeemer - The wallet public key of the redeemer.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\n * ```\n */\nexport function deriveLpRedemption(\n programId: PublicKey,\n registry: PublicKey,\n redeemer: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [\n textEncoder.encode(\"lp_redemption\"),\n registry.toBytes(),\n redeemer.toBytes(),\n ],\n programId\n );\n}\n\n/**\n * Derive the LP backing-domain ledger PDA.\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\n *\n * Required by: DepositToLpVault (tag 75) at accounts[7],\n * LpVaultCrankFees (tag 78) at accounts[3].\n *\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\n * (line 3127) — domain is encoded as 2-byte little-endian.\n *\n * @param programId - The Percolator program ID.\n * @param marketGroup - The market group (slab) public key.\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\n * ```\n */\nexport function deriveLpBackingLedger(\n programId: PublicKey,\n marketGroup: PublicKey,\n domainIdx: number\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [\n textEncoder.encode(\"lp_backing_ledger\"),\n marketGroup.toBytes(),\n u16LE(domainIdx),\n ],\n programId\n );\n}\n\n/**\n * Derive the LP escrow SPL token account PDA.\n * Seeds: [\"lp_escrow\", marketGroup]\n *\n * The escrow is owned by the registry PDA and holds LP tokens during the\n * redemption window. Required by ExecuteRedemption (tag 77).\n *\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\n *\n * @param programId - The Percolator program ID.\n * @param marketGroup - The market group (slab) public key.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\n * ```\n */\nexport function deriveLpEscrow(\n programId: PublicKey,\n marketGroup: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\n programId\n );\n}\n\n// ---------------------------------------------------------------------------\n// NFT Registry PDA (v17 — tag 73)\n// ---------------------------------------------------------------------------\n\n/**\n * Derive the per-market NFT program-id registry PDA.\n * Seeds: [\"nft_registry\", marketGroup]\n *\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\n * (TransferPortfolioOwnership, tag 72).\n *\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\n *\n * @param programId - The Percolator program ID.\n * @param marketGroup - The market group (slab) public key.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\n * ```\n */\nexport function deriveNftRegistry(\n programId: PublicKey,\n marketGroup: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\n programId\n );\n}\n\n// ---------------------------------------------------------------------------\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\n// ---------------------------------------------------------------------------\n\n/**\n * Derive the matcher delegate PDA.\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\n * (all six seed segments are 32-byte public keys)\n *\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\n * The program signs CPI calls to the external matcher program using this PDA.\n *\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\n *\n * @param programId - The Percolator program ID.\n * @param market - The market (slab) public key.\n * @param accountB - The maker/LP portfolio account public key.\n * @param accountBOwner - The owner of accountB.\n * @param matcherProg - The external matcher program public key.\n * @param matcherCtx - The matcher context account public key.\n * @returns [pda, bump]\n *\n * @example\n * ```ts\n * const [delegatePda] = deriveMatcherDelegate(\n * PROGRAM_ID,\n * marketKey,\n * accountBKey,\n * accountBOwnerKey,\n * matcherProgKey,\n * matcherCtxKey,\n * );\n * ```\n */\nexport function deriveMatcherDelegate(\n programId: PublicKey,\n market: PublicKey,\n accountB: PublicKey,\n accountBOwner: PublicKey,\n matcherProg: PublicKey,\n matcherCtx: PublicKey\n): [PublicKey, number] {\n return PublicKey.findProgramAddressSync(\n [\n textEncoder.encode(\"matcher\"),\n market.toBytes(),\n accountB.toBytes(),\n accountBOwner.toBytes(),\n matcherProg.toBytes(),\n matcherCtx.toBytes(),\n ],\n programId\n );\n}\n\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\nconst PYTH_FEED_ID_HEX_LEN = 64;\n\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\n let s = feedIdHex.trim();\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\n s = s.slice(2);\n }\n return s;\n}\n\n/**\n * Derive the Pyth Push Oracle PDA for a given feed ID.\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\n */\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\n\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\n const normalized = normalizePythFeedIdHex(feedIdHex);\n if (!FEED_HEX_RE.test(normalized)) {\n throw new Error(\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\n }\n const feedId = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\n }\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\n return PublicKey.findProgramAddressSync(\n [shardBuf, feedId],\n PYTH_PUSH_ORACLE_PROGRAM_ID,\n );\n}\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport {\n getAssociatedTokenAddress,\n getAssociatedTokenAddressSync,\n getAccount,\n Account,\n TOKEN_PROGRAM_ID,\n} from \"@solana/spl-token\";\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\n\n/**\n * Get the associated token address for an owner and mint.\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\n */\nexport async function getAta(\n owner: PublicKey,\n mint: PublicKey,\n allowOwnerOffCurve = false,\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n): Promise {\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\n}\n\n/**\n * Synchronous version of getAta.\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\n */\nexport function getAtaSync(\n owner: PublicKey,\n mint: PublicKey,\n allowOwnerOffCurve = false,\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n): PublicKey {\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\n}\n\n/**\n * Fetch token account info.\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\n * Throws if account doesn't exist.\n */\nexport async function fetchTokenAccount(\n connection: Connection,\n address: PublicKey,\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n): Promise {\n return getAccount(connection, address, undefined, tokenProgramId);\n}\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport {\n parseHeader,\n parseConfig,\n parseParams,\n detectSlabLayout,\n isV17MarketAccount,\n parseWrapperConfigV17,\n SLAB_TIERS_V1M,\n SLAB_TIERS_V1M2,\n SLAB_TIERS_V2,\n SLAB_TIERS_V_ADL,\n SLAB_TIERS_V12_1,\n SLAB_TIERS_V12_15,\n SLAB_TIERS_V12_17,\n SLAB_TIERS_V12_19,\n SLAB_TIERS_V_SETDEXPOOL,\n type SlabHeader,\n type MarketConfig,\n type EngineState,\n type RiskParams,\n type SlabLayout,\n type WrapperConfigV17,\n} from \"./slab.js\";\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\nimport { type Network } from \"../config/program-ids.js\";\n\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\n/** V0 bitmap offset within engine struct (deployed devnet program) */\nconst ENGINE_BITMAP_OFF_V0 = 320;\n\n/**\n * A discovered Percolator market from on-chain program accounts.\n */\nexport interface DiscoveredMarket {\n slabAddress: PublicKey;\n /** The program that owns this slab account */\n programId: PublicKey;\n /**\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\n */\n header: SlabHeader;\n /**\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\n */\n config: MarketConfig;\n /**\n * v12.x engine state (bitmap, account counts).\n * Present for v12 slab accounts. Absent for v17 accounts.\n */\n engine: EngineState;\n /**\n * v12.x risk parameters.\n * Present for v12 slab accounts. Absent for v17 accounts.\n */\n params: RiskParams;\n /**\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\n * Absent for v12 slab accounts.\n *\n * Use `isV17Market(m)` to narrow the type:\n * ```ts\n * if (m.configV17) {\n * console.log(m.configV17.collateralMint.toBase58());\n * }\n * ```\n */\n configV17?: WrapperConfigV17;\n}\n\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\n\n/**\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\n * These are the first 8 bytes of every v17 percolator-owned market group account.\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\n */\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\n\n/**\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\n *\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\n *\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\n *\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\n * See GH #1109, GH #1112.\n *\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\n */\n/**\n * Default slab tiers for the current mainnet program (v12.17).\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\n */\nexport const SLAB_TIERS = {\n small: SLAB_TIERS_V12_17[\"small\"],\n medium: SLAB_TIERS_V12_17[\"medium\"],\n large: SLAB_TIERS_V12_17[\"large\"],\n} as const;\n\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\nexport const SLAB_TIERS_V0 = {\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\n} as const;\n\n/**\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\n *\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\n * micro = 17,064 (64 slots)\n * small = 65,088 (256 slots)\n * medium = 257,184 (1,024 slots)\n * large = 1,025,568 (4,096 slots)\n */\nexport const SLAB_TIERS_V1D = {\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\n} as const;\n\n/**\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\n *\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\n * micro = 17,080 (64 slots)\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\n * medium = 257,200 (1,024 slots)\n * large = 1,025,584 (4,096 slots)\n */\nexport const SLAB_TIERS_V1D_LEGACY = {\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\n} as const;\n\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\n\n/**\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\n * New account layout adds ADL tracking fields (+64 bytes/account).\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\n */\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\n\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\n\n/** Calculate slab data size for arbitrary account count.\n *\n * Layout (SBF, u128 align = 8):\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\n * + bitmap: ceil(N/64)*8\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\n * + next_free: N*2\n * + pad to 8-byte alignment for Account array\n * + accounts: N*248\n *\n * Must match the on-chain program's SLAB_LEN exactly.\n */\nexport function slabDataSize(maxAccounts: number): number {\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\n const ENGINE_OFF_V0 = 480;\n const ENGINE_BITMAP_OFF_V0 = 320;\n const ACCOUNT_SIZE_V0 = 240;\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\n}\n\n/**\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\n *\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\n * difference at high account counts or a post-PERC-118 struct addition in the\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\n * verified on-chain) over this formula for production use.\n */\nexport function slabDataSizeV1(maxAccounts: number): number {\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\n const ENGINE_BITMAP_OFF_V1 = 656;\n const ACCOUNT_SIZE_V1 = 248;\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\n const postBitmap = 18;\n const nextFreeBytes = maxAccounts * 2;\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\n}\n\n/**\n * Validate that a slab data size matches one of the known tier sizes.\n * Use this to catch tier↔program mismatches early (PERC-277).\n *\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\n * @returns true if sizes match, false if there's a mismatch\n */\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\n return dataSize === programSlabLen;\n}\n\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\nconst ALL_SLAB_SIZES = [\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\n];\n\n/** Legacy constant for backward compat */\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\n\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\nconst HEADER_SLICE_LENGTH = 1940;\n\nfunction dv(data: Uint8Array): DataView {\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\n}\nfunction readU16LE(data: Uint8Array, off: number): number {\n return dv(data).getUint16(off, true);\n}\nfunction readU64LE(data: Uint8Array, off: number): bigint {\n return dv(data).getBigUint64(off, true);\n}\nfunction readI64LE(data: Uint8Array, off: number): bigint {\n return dv(data).getBigInt64(off, true);\n}\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\n const lo = readU64LE(buf, offset);\n const hi = readU64LE(buf, offset + 8);\n return (hi << 64n) | lo;\n}\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\n const lo = readU64LE(buf, offset);\n const hi = readU64LE(buf, offset + 8);\n const unsigned = (hi << 64n) | lo;\n const SIGN_BIT = 1n << 127n;\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\n return unsigned;\n}\n\n/**\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\n *\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\n */\nexport function parseEngineLight(\n data: Uint8Array,\n layout: SlabLayout | null,\n maxAccounts: number = 4096,\n): EngineState {\n const isV0 = !layout || layout.version === 0;\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\n\n const minLen = base + bitmapOff;\n if (data.length < minLen) {\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\n }\n\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\n const bitmapWords = Math.ceil(maxAccounts / 64);\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\n\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\n\n if (isV0) {\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\n return {\n vault: readU128LE(data, base + 0),\n insuranceFund: {\n balance: readU128LE(data, base + 16),\n feeRevenue: readU128LE(data, base + 32),\n isolatedBalance: 0n,\n isolationBps: 0,\n },\n currentSlot: readU64LE(data, base + 104),\n fundingIndexQpbE6: readI128LE(data, base + 112),\n lastFundingSlot: readU64LE(data, base + 128),\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\n fundingRateE9: 0n,\n marketMode: null,\n lastCrankSlot: readU64LE(data, base + 144),\n maxCrankStalenessSlots: readU64LE(data, base + 152),\n totalOpenInterest: readU128LE(data, base + 160),\n longOi: 0n,\n shortOi: 0n,\n cTot: readU128LE(data, base + 176),\n pnlPosTot: readU128LE(data, base + 192),\n pnlMaturedPosTot: 0n,\n liqCursor: readU16LE(data, base + 208),\n gcCursor: readU16LE(data, base + 210),\n lastSweepStartSlot: readU64LE(data, base + 216),\n lastSweepCompleteSlot: readU64LE(data, base + 224),\n crankCursor: readU16LE(data, base + 232),\n sweepStartIdx: readU16LE(data, base + 234),\n lifetimeLiquidations: readU64LE(data, base + 240),\n lifetimeForceCloses: readU64LE(data, base + 248),\n netLpPos: readI128LE(data, base + 256),\n lpSumAbs: readU128LE(data, base + 272),\n lpMaxAbs: readU128LE(data, base + 288),\n lpMaxAbsSweep: 0n,\n emergencyOiMode: false,\n emergencyStartSlot: 0n,\n lastBreakerSlot: 0n,\n markPriceE6: 0n, // V0 engine has no mark_price field\n oraclePriceE6: 0n,\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\n };\n }\n\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\n // (the currently-deployed mainnet tier line) were being routed through this branch's\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\n // per the layout-driven branch's own comment below, which already documents that it\n // covers V12_15/17/19 — that was the intended path all along.\n\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\n // that share engineOff=640 but have different internal struct sizes.\n if (layout !== null) {\n const l = layout;\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\n // struct for that tier has no such field, and `base + (-1)` would read\n // garbage straddling the byte before the engine region rather than failing.\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\n // below goes through these instead of reading the offset directly.\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\n return {\n vault: readU128LE(data, base + 0),\n insuranceFund: {\n balance: readU128LE(data, base + l.engineInsuranceOff),\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\n },\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\n : readI128LE(data, base + l.engineFundingIndexOff))\n : 0n,\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\n fundingRateE9: 0n,\n marketMode: null,\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\n totalOpenInterest: u128At(l.engineTotalOiOff),\n longOi: u128At(l.engineLongOiOff),\n shortOi: u128At(l.engineShortOiOff),\n cTot: readU128LE(data, base + l.engineCTotOff),\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\n pnlMaturedPosTot: 0n,\n liqCursor: u16At(l.engineLiqCursorOff),\n gcCursor: u16At(l.engineGcCursorOff),\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\n crankCursor: u16At(l.engineCrankCursorOff),\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\n netLpPos: i128At(l.engineNetLpPosOff),\n lpSumAbs: u128At(l.engineLpSumAbsOff),\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\n markPriceE6: u64At(l.engineMarkPriceOff),\n oraclePriceE6: 0n,\n fLongNum: 0n,\n fShortNum: 0n,\n negPnlAccountCount: 0n,\n fundPxLast: 0n,\n resolvedKLongTerminalDelta: 0n,\n resolvedKShortTerminalDelta: 0n,\n resolvedLivePrice: 0n,\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\n };\n }\n\n // layout === null: unrecognized slab format — callers should have skipped via the\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\n}\n\n/** Options for `discoverMarkets`. */\nexport interface DiscoverMarketsOptions {\n /**\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\n * Default: false (preserves original parallel behaviour).\n *\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\n */\n sequential?: boolean;\n /**\n * Delay in ms between sequential tier queries (only used when sequential=true).\n * Default: 200 ms.\n */\n interTierDelayMs?: number;\n /**\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\n */\n rateLimitBackoffMs?: number[];\n\n /**\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\n * at once to avoid accidental RPC storms from client code.\n *\n * Default: 6\n */\n maxParallelTiers?: number;\n\n /**\n * Hard cap on how many tier dataSize queries are attempted.\n * Default: all known tiers.\n */\n maxTierQueries?: number;\n\n /**\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\n *\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\n * mainnet RPCs that reject `getProgramAccounts`).\n *\n * The API returns slab addresses which are then fetched on-chain via\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\n *\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\n *\n * @example\n * ```ts\n * const markets = await discoverMarkets(connection, programId, {\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\n * });\n * ```\n */\n apiBaseUrl?: string;\n\n /**\n * Timeout in ms for the API fallback HTTP request.\n * Only used when `apiBaseUrl` is set.\n * Default: 10_000 (10 seconds).\n */\n apiTimeoutMs?: number;\n\n /**\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\n *\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\n * `discoverMarkets` will fall back to a bundled static list of known slab\n * addresses for the specified network. The addresses are fetched on-chain\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\n *\n * If not set, tier-3 fallback is disabled.\n *\n * The static list can be extended at runtime via `registerStaticMarkets()`.\n *\n * @see {@link registerStaticMarkets} to add addresses at runtime\n * @see {@link getStaticMarkets} to inspect the current static list\n *\n * @example\n * ```ts\n * const markets = await discoverMarkets(connection, programId, {\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\n * network: \"mainnet\", // enables tier-3 static fallback\n * });\n * ```\n */\n network?: Network;\n}\n\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\nfunction isRateLimitError(err: unknown): boolean {\n if (!err) return false;\n const msg = err instanceof Error ? err.message : String(err);\n return (\n msg.includes(\"429\") ||\n msg.toLowerCase().includes(\"rate limit\") ||\n msg.toLowerCase().includes(\"too many requests\")\n );\n}\n\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\nfunction withJitter(delayMs: number): number {\n const half = Math.floor(delayMs / 2);\n return half + Math.floor(Math.random() * (delayMs - half + 1));\n}\n\n/**\n * Discover all Percolator markets owned by the given program.\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\n *\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\n */\nexport async function discoverMarkets(\n connection: Connection,\n programId: PublicKey,\n options: DiscoverMarketsOptions = {},\n): Promise {\n const {\n sequential = false,\n interTierDelayMs = 200,\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\n maxParallelTiers = 6,\n } = options;\n\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\n //\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\n const ALL_TIERS_RAW = [\n ...Object.values(SLAB_TIERS), // v12.17 (default)\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\n ...Object.values(SLAB_TIERS_V0),\n ...Object.values(SLAB_TIERS_V1D),\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\n ...Object.values(SLAB_TIERS_V2),\n ...Object.values(SLAB_TIERS_V1M),\n ...Object.values(SLAB_TIERS_V1M2),\n ...Object.values(SLAB_TIERS_V_ADL),\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\n ];\n const tierBySize = new Map();\n for (const tier of ALL_TIERS_RAW) {\n const existing = tierBySize.get(tier.dataSize);\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\n tierBySize.set(tier.dataSize, tier);\n }\n }\n const ALL_TIERS = [...tierBySize.values()];\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\n let rawAccounts: RawEntry[] = [];\n\n /**\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\n */\n async function fetchTierWithRetry(\n tier: { dataSize: number; maxAccounts: number },\n ): Promise {\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\n try {\n const results = await connection.getProgramAccounts(programId, {\n filters: [{ dataSize: tier.dataSize }],\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\n });\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\n } catch (err) {\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\n const delay = withJitter(rateLimitBackoffMs[attempt]);\n console.warn(\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\n );\n await new Promise(r => setTimeout(r, delay));\n continue;\n }\n // Non-429 or exhausted retries\n console.warn(\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\n err instanceof Error ? err.message : err,\n );\n return [];\n }\n }\n return [];\n }\n\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\n\n // Avoid accidental `0`/negative or NaN causing infinite loops.\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\n\n try {\n if (sequential) {\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\n for (let i = 0; i < tiersToQuery.length; i++) {\n const tier = tiersToQuery[i];\n const entries = await fetchTierWithRetry(tier);\n rawAccounts.push(...entries);\n if (i < tiersToQuery.length - 1) {\n await new Promise(r => setTimeout(r, interTierDelayMs));\n }\n }\n } else {\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\n // getProgramAccounts calls at once from a single client call.\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\n const queries = chunk.map(tier =>\n connection.getProgramAccounts(programId, {\n filters: [{ dataSize: tier.dataSize }],\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\n }).then(results =>\n results.map(entry => ({\n ...entry,\n maxAccounts: tier.maxAccounts,\n dataSize: tier.dataSize,\n })),\n ),\n );\n\n const results = await Promise.allSettled(queries);\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n for (const entry of result.value) {\n rawAccounts.push(entry as RawEntry);\n }\n } else {\n console.warn(\n \"[discoverMarkets] Tier query rejected:\",\n result.reason instanceof Error ? result.reason.message : result.reason,\n );\n }\n }\n }\n }\n\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\n try {\n const v17Results = await connection.getProgramAccounts(programId, {\n filters: [\n {\n memcmp: {\n offset: 0,\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\n encoding: \"base64\",\n },\n },\n ],\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\n });\n for (const e of v17Results) {\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\n }\n } catch {\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\n }\n\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\n // account size changed; RPC returns no error, so we must fallback on empty results too.\n if (rawAccounts.length === 0) {\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\n const fallback = await connection.getProgramAccounts(programId, {\n filters: [\n {\n memcmp: {\n offset: 0,\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\n },\n },\n ],\n });\n rawAccounts = [...fallback].map(e => {\n const len = e.account.data.length;\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\n }) as RawEntry[];\n }\n } catch (err) {\n console.warn(\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\n err instanceof Error ? err.message : err,\n );\n try {\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\n const fallback = await connection.getProgramAccounts(programId, {\n filters: [\n {\n memcmp: {\n offset: 0,\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\n },\n },\n ],\n });\n rawAccounts = [...fallback].map(e => {\n const len = e.account.data.length;\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\n }) as RawEntry[];\n } catch (memcmpErr) {\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\n console.warn(\n \"[discoverMarkets] memcmp fallback also failed:\",\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\n );\n }\n }\n\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\n // rejects it) and an API base URL is configured, fall back to the REST API to\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\n console.warn(\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\n );\n try {\n const apiResult = await discoverMarketsViaApi(\n connection,\n programId,\n options.apiBaseUrl,\n { timeoutMs: options.apiTimeoutMs },\n );\n if (apiResult.length > 0) {\n return apiResult;\n }\n // API returned 0 markets — fall through to tier 3\n console.warn(\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\n );\n } catch (apiErr) {\n console.warn(\n \"[discoverMarkets] API fallback also failed:\",\n apiErr instanceof Error ? apiErr.message : apiErr,\n );\n // Fall through to tier 3\n }\n }\n\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\n // the REST API failed (or returned 0 results) and a network hint is provided,\n // use the bundled static market list as a last-resort address directory.\n if (rawAccounts.length === 0 && options.network) {\n const staticEntries = getStaticMarkets(options.network);\n if (staticEntries.length > 0) {\n console.warn(\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\n );\n try {\n return await discoverMarketsViaStaticBundle(\n connection,\n programId,\n staticEntries,\n );\n } catch (staticErr) {\n console.warn(\n \"[discoverMarkets] Static bundle fallback also failed:\",\n staticErr instanceof Error ? staticErr.message : staticErr,\n );\n // Fall through to return empty array\n }\n } else {\n console.warn(\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\n );\n }\n }\n\n const accounts = rawAccounts;\n\n const markets: DiscoveredMarket[] = [];\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\n const seenPubkeys = new Set();\n\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\n const pkStr = pubkey.toBase58();\n if (seenPubkeys.has(pkStr)) continue;\n seenPubkeys.add(pkStr);\n const data = new Uint8Array(account.data);\n\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\n // memcmp fallback or if the account happens to match a tier size by coincidence.\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\n // — are not mis-parsed as markets.\n if (isV17MarketAccount(data)) {\n try {\n const configV17 = parseWrapperConfigV17(data);\n markets.push({\n slabAddress: pubkey,\n programId,\n header: {} as SlabHeader,\n config: {} as MarketConfig,\n engine: {} as EngineState,\n params: {} as RiskParams,\n configV17,\n });\n } catch (err) {\n console.warn(\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\n err instanceof Error ? err.message : err,\n );\n }\n continue;\n }\n\n let valid = true;\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\n if (data[i] !== MAGIC_BYTES[i]) {\n valid = false;\n break;\n }\n }\n if (!valid) continue;\n\n // Detect layout from actual slab size — not slice length — so parse functions\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\n const layout = detectSlabLayout(dataSize, data);\n\n if (!layout) {\n console.warn(\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\n );\n continue;\n }\n\n try {\n const header = parseHeader(data);\n const config = parseConfig(data, layout);\n const engine = parseEngineLight(data, layout, maxAccounts);\n const params = parseParams(data, layout);\n\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\n } catch (err) {\n console.warn(\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n\n return markets;\n}\n\n/**\n * Options for `getMarketsByAddress`.\n */\nexport interface GetMarketsByAddressOptions {\n /**\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\n * Solana limits a single call to 100 accounts; callers may lower this\n * to reduce per-request payload size or avoid 429s.\n *\n * Default: 100 (Solana maximum).\n */\n batchSize?: number;\n\n /**\n * Delay in ms between batches when the address list exceeds `batchSize`.\n * Helps avoid rate-limiting on public RPCs.\n *\n * Default: 0 (no delay).\n */\n interBatchDelayMs?: number;\n}\n\n/**\n * Fetch and parse Percolator markets by their known slab addresses.\n *\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\n *\n * Callers must already know the market slab addresses (e.g. from an indexer,\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\n *\n * @param connection - Solana RPC connection\n * @param programId - The Percolator program that owns these slabs\n * @param addresses - Array of slab account public keys to fetch\n * @param options - Optional batching/delay configuration\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\n *\n * @example\n * ```ts\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\n * import { Connection, PublicKey } from \"@solana/web3.js\";\n *\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\n * const programId = getProgramId(\"mainnet\");\n * const slabs = [\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\n * // ... more known slab addresses\n * ];\n *\n * const markets = await getMarketsByAddress(connection, programId, slabs);\n * console.log(`Found ${markets.length} markets`);\n * ```\n */\nexport async function getMarketsByAddress(\n connection: Connection,\n programId: PublicKey,\n addresses: PublicKey[],\n options: GetMarketsByAddressOptions = {},\n): Promise {\n if (addresses.length === 0) return [];\n\n const {\n batchSize = 100,\n interBatchDelayMs = 0,\n } = options;\n\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\n\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\n const fetched: AccountResult[] = [];\n\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\n\n const response = await connection.getMultipleAccountsInfo(batch);\n\n for (let i = 0; i < batch.length; i++) {\n const info = response[i];\n if (info && info.data) {\n if (!info.owner.equals(programId)) {\n console.warn(\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\n );\n continue;\n }\n fetched.push({ pubkey: batch[i], data: info.data });\n }\n }\n\n // Inter-batch delay to avoid rate-limiting\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\n await new Promise(r => setTimeout(r, interBatchDelayMs));\n }\n }\n\n // Parse each account into a DiscoveredMarket\n const markets: DiscoveredMarket[] = [];\n\n for (const entry of fetched) {\n if (!entry) continue;\n const { pubkey, data: rawData } = entry;\n const data = new Uint8Array(rawData);\n\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\n if (isV17MarketAccount(data)) {\n try {\n const configV17 = parseWrapperConfigV17(data);\n // v17 accounts have no slab header/config/engine/params; supply defaults so\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\n // to detect a v17 market.\n markets.push({\n slabAddress: pubkey,\n programId,\n header: {} as SlabHeader,\n config: {} as MarketConfig,\n engine: {} as EngineState,\n params: {} as RiskParams,\n configV17,\n });\n } catch (err) {\n console.warn(\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\n err instanceof Error ? err.message : err,\n );\n }\n continue;\n }\n\n // Validate v12 magic bytes\n let valid = true;\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\n if (data[i] !== MAGIC_BYTES[i]) {\n valid = false;\n break;\n }\n }\n if (!valid) {\n console.warn(\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\n );\n continue;\n }\n\n // Detect layout from full account data length\n const layout = detectSlabLayout(data.length, data);\n if (!layout) {\n console.warn(\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\n );\n continue;\n }\n\n try {\n const header = parseHeader(data);\n const config = parseConfig(data, layout);\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\n const params = parseParams(data, layout);\n\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\n } catch (err) {\n console.warn(\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n\n return markets;\n}\n\n// ---------------------------------------------------------------------------\n// REST API-based market discovery (GH#59 / PERC-8424)\n// ---------------------------------------------------------------------------\n\n/**\n * Shape of a single market entry returned by the Percolator REST API\n * (`GET /markets`). Only the fields needed for discovery are typed here;\n * the full API response may contain additional statistics fields.\n */\nexport interface ApiMarketEntry {\n slab_address: string;\n symbol?: string;\n name?: string;\n decimals?: number;\n status?: string;\n [key: string]: unknown;\n}\n\n/** Options for {@link discoverMarketsViaApi}. */\nexport interface DiscoverMarketsViaApiOptions {\n /**\n * Timeout in ms for the HTTP request to the REST API.\n * Default: 10_000 (10 seconds).\n */\n timeoutMs?: number;\n\n /**\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\n * step (batch size, inter-batch delay).\n */\n onChainOptions?: GetMarketsByAddressOptions;\n}\n\n/**\n * Discover Percolator markets by first querying the REST API for slab addresses,\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\n *\n * This is the recommended discovery path for mainnet users who do not have a\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\n *\n * The REST API acts as an address directory only — all market data is verified\n * on-chain via `getMarketsByAddress`, so the caller gets the same\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\n *\n * @param connection - Solana RPC connection (any endpoint, including public)\n * @param programId - The Percolator program that owns the slabs\n * @param apiBaseUrl - Base URL of the Percolator REST API\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\n * @param options - Optional timeout and on-chain fetch configuration\n * @returns Parsed markets for all valid slab accounts discovered via the API\n *\n * @example\n * ```ts\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\n * import { Connection } from \"@solana/web3.js\";\n *\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\n * const programId = getProgramId(\"mainnet\");\n * const markets = await discoverMarketsViaApi(\n * connection,\n * programId,\n * \"https://percolatorlaunch.com/api\",\n * );\n * console.log(`Discovered ${markets.length} markets via API fallback`);\n * ```\n */\nexport async function discoverMarketsViaApi(\n connection: Connection,\n programId: PublicKey,\n apiBaseUrl: string,\n options: DiscoverMarketsViaApiOptions = {},\n): Promise {\n const { timeoutMs = 10_000, onChainOptions } = options;\n\n // Normalise base URL — strip trailing slash to avoid double-slash in path\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\n const url = `${base}/markets`;\n\n // Fetch market list from REST API\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n throw new Error(\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\n );\n }\n\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\n const apiMarkets = body.markets;\n\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\n return [];\n }\n\n // Extract valid slab addresses\n const addresses: PublicKey[] = [];\n for (const entry of apiMarkets) {\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\n try {\n addresses.push(new PublicKey(entry.slab_address));\n } catch {\n console.warn(\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\n );\n }\n }\n\n if (addresses.length === 0) {\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\n return [];\n }\n\n console.log(\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\n );\n\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\n}\n\n// ---------------------------------------------------------------------------\n// Static bundle fallback (PERC-8435 — tier 3)\n// ---------------------------------------------------------------------------\n\n/** Options for {@link discoverMarketsViaStaticBundle}. */\nexport interface DiscoverMarketsViaStaticBundleOptions {\n /**\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\n * step (batch size, inter-batch delay).\n */\n onChainOptions?: GetMarketsByAddressOptions;\n}\n\n/**\n * Discover Percolator markets from a static list of known slab addresses.\n *\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\n * a bundled list of known slab addresses and fetches their full account data\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\n *\n * The static list acts as an address directory only — all market data is verified\n * on-chain, so stale entries are silently skipped (the account won't have valid\n * magic bytes or will have been closed).\n *\n * @param connection - Solana RPC connection (any endpoint)\n * @param programId - The Percolator program that owns the slabs\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\n * @param options - Optional on-chain fetch configuration\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\n *\n * @example\n * ```ts\n * import {\n * discoverMarketsViaStaticBundle,\n * getStaticMarkets,\n * getProgramId,\n * } from \"@percolator/sdk\";\n * import { Connection } from \"@solana/web3.js\";\n *\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\n * const programId = getProgramId(\"mainnet\");\n * const entries = getStaticMarkets(\"mainnet\");\n *\n * const markets = await discoverMarketsViaStaticBundle(\n * connection,\n * programId,\n * entries,\n * );\n * console.log(`Recovered ${markets.length} markets from static bundle`);\n * ```\n */\nexport async function discoverMarketsViaStaticBundle(\n connection: Connection,\n programId: PublicKey,\n entries: StaticMarketEntry[],\n options: DiscoverMarketsViaStaticBundleOptions = {},\n): Promise {\n if (entries.length === 0) return [];\n\n // Extract valid slab addresses from static entries\n const addresses: PublicKey[] = [];\n for (const entry of entries) {\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\n try {\n addresses.push(new PublicKey(entry.slabAddress));\n } catch {\n console.warn(\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\n );\n }\n }\n\n if (addresses.length === 0) {\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\n return [];\n }\n\n console.log(\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\n );\n\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\n}\n","/**\n * Static market registry — bundled list of known Percolator slab addresses.\n *\n * This is the tier-3 fallback for `discoverMarkets()`: when both\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\n * the SDK falls back to this bundled list to bootstrap market discovery.\n *\n * The addresses are fetched on-chain via `getMarketsByAddress`\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\n * list only provides the *address directory* — no cached market data is used.\n *\n * ## Maintenance\n *\n * Update this list when new markets are deployed or old ones are retired.\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\n * or the REST API.\n *\n * @module\n */\n\nimport { PublicKey } from \"@solana/web3.js\";\nimport type { Network } from \"../config/program-ids.js\";\n\n/**\n * A single entry in the static market registry.\n *\n * Only the slab address (base58) is required. Optional metadata fields\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\n * they are **not** used for on-chain data and may become stale.\n */\nexport interface StaticMarketEntry {\n /** Base58-encoded slab account address. */\n slabAddress: string;\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\n symbol?: string;\n /** Optional descriptive name. */\n name?: string;\n}\n\n/**\n * Known mainnet market slab addresses.\n *\n * These are the markets deployed to the mainnet Percolator program\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\n *\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\n */\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\n];\n\n/**\n * Known devnet market slab addresses.\n *\n * These are discovered from the devnet Percolator program\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\n *\n * **Last updated:** 2026-04-04.\n */\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\n // Populated from prior discoverMarkets() runs on devnet.\n // These serve as the tier-3 safety net for devnet users.\n];\n\n/**\n * Full static registry indexed by network.\n */\nconst STATIC_REGISTRY: Record = {\n mainnet: MAINNET_MARKETS,\n devnet: DEVNET_MARKETS,\n};\n\n/**\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\n * Keyed by network.\n */\nconst USER_MARKETS: Record = {\n mainnet: [],\n devnet: [],\n};\n\n/**\n * Get the bundled static market list for a given network.\n *\n * Returns the built-in list merged with any entries added via\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\n * automatically — user-registered entries take precedence.\n *\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\n * @returns Array of static market entries (may be empty if no markets are known)\n *\n * @example\n * ```ts\n * import { getStaticMarkets } from \"@percolator/sdk\";\n *\n * const markets = getStaticMarkets(\"mainnet\");\n * console.log(`${markets.length} known mainnet slab addresses`);\n * ```\n */\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\n const builtin = STATIC_REGISTRY[network] ?? [];\n const user = USER_MARKETS[network] ?? [];\n\n if (user.length === 0) return [...builtin];\n\n // Merge: user entries override builtin entries with same slabAddress\n const seen = new Map();\n for (const entry of builtin) {\n seen.set(entry.slabAddress, entry);\n }\n for (const entry of user) {\n seen.set(entry.slabAddress, entry);\n }\n return [...seen.values()];\n}\n\n/**\n * Register additional static market entries at runtime.\n *\n * Use this to inject known slab addresses before calling `discoverMarkets()`\n * so that tier-3 fallback has addresses to work with — especially useful\n * right after mainnet launch when the bundled list may be empty.\n *\n * Entries are deduplicated by `slabAddress` — calling this multiple times\n * with the same address is safe.\n *\n * @param network - Target network\n * @param entries - One or more static market entries to register\n *\n * @example\n * ```ts\n * import { registerStaticMarkets } from \"@percolator/sdk\";\n *\n * registerStaticMarkets(\"mainnet\", [\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\n * ]);\n * ```\n */\nexport function registerStaticMarkets(\n network: Network,\n entries: StaticMarketEntry[],\n): void {\n const existing = USER_MARKETS[network];\n const seen = new Set(existing.map(e => e.slabAddress));\n\n for (const entry of entries) {\n if (!entry.slabAddress) continue;\n if (seen.has(entry.slabAddress)) continue;\n // Validate that slabAddress is a valid base58 public key\n try {\n new PublicKey(entry.slabAddress);\n } catch {\n console.warn(\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\n );\n continue;\n }\n seen.add(entry.slabAddress);\n existing.push(entry);\n }\n}\n\n/**\n * Clear all user-registered static market entries for a network.\n *\n * Useful in tests or when resetting state.\n *\n * @param network - Target network to clear (omit to clear all networks)\n */\nexport function clearStaticMarkets(network?: Network): void {\n if (network) {\n USER_MARKETS[network] = [];\n } else {\n USER_MARKETS.mainnet = [];\n USER_MARKETS.devnet = [];\n }\n}\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport {\n PUMPSWAP_PROGRAM_ID,\n RAYDIUM_CLMM_PROGRAM_ID,\n METEORA_DLMM_PROGRAM_ID,\n} from \"./pda.js\";\n\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\n\nexport interface DexPoolInfo {\n dexType: DexType;\n poolAddress: PublicKey;\n baseMint: PublicKey;\n quoteMint: PublicKey;\n baseVault?: PublicKey; // PumpSwap only\n quoteVault?: PublicKey; // PumpSwap only\n}\n\n/**\n * Detect DEX type from the program that owns the pool account.\n *\n * @param ownerProgramId - The program ID that owns the pool account\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\n *\n * Supported DEX programs:\n * - PumpSwap (constant-product AMM)\n * - Raydium CLMM (concentrated liquidity)\n * - Meteora DLMM (discretized liquidity)\n */\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\n return null;\n}\n\n/**\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\n *\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\n * @param poolAddress - The on-chain address of the pool account\n * @param data - Raw account data bytes\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\n * @throws Error if data is too short for the given DEX type\n */\nexport function parseDexPool(\n dexType: DexType,\n poolAddress: PublicKey,\n data: Uint8Array,\n): DexPoolInfo {\n switch (dexType) {\n case \"pumpswap\":\n return parsePumpSwapPool(poolAddress, data);\n case \"raydium-clmm\":\n return parseRaydiumClmmPool(poolAddress, data);\n case \"meteora-dlmm\":\n return parseMeteoraPool(poolAddress, data);\n }\n}\n\n/**\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\n *\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\n * markets, prefer Pyth or Chainlink oracles.\n *\n * @param dexType - The type of DEX\n * @param data - Raw pool account data\n * @param vaultData - For PumpSwap only: base and quote vault account data\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\n * ignored for raydium-clmm (decimals are embedded in the pool account).\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\n * and for PumpSwap pools quoted in a non-WSOL mint.\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\n * price mislabeled as USD.\n * @throws Error if data is too short, required params are missing, or computation fails\n */\nexport function computeDexSpotPriceE6(\n dexType: DexType,\n data: Uint8Array,\n vaultData?: { base: Uint8Array; quote: Uint8Array },\n decimals?: { base: number; quote: number },\n solPriceE6?: bigint,\n): bigint {\n switch (dexType) {\n case \"pumpswap\":\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\n // MUST supply decimals (fetched from the base/quote mints), matching the\n // meteora-dlmm contract below.\n if (!decimals) {\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\n }\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\n case \"raydium-clmm\":\n return computeRaydiumClmmPriceE6(data);\n case \"meteora-dlmm\":\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\n if (!decimals) {\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\n }\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\n }\n}\n\n// ============================================================================\n// Mint decimals helper\n// ============================================================================\n\n/**\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\n * can read this field directly instead of duplicating the magic number.\n */\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\n\n/**\n * Read the `decimals` field of any SPL mint account (including native WSOL).\n *\n * This replaces `getMint(connection, mint).decimals` for callers that need to\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\n * because the system account is not a valid token-program mint; this function\n * reads raw account data and extracts byte 44 directly, which works for all\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\n *\n * @param connection - Solana RPC connection\n * @param mint - The mint public key to query\n * @returns The `decimals` field value (0–255)\n * @throws Error if the account does not exist or is too short to hold a mint\n *\n * @example\n * ```ts\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\n *\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\n * base: baseDecimals,\n * quote: quoteDecimals,\n * });\n * ```\n */\nexport async function fetchMintDecimals(\n connection: Connection,\n mint: PublicKey,\n): Promise {\n const info = await connection.getAccountInfo(mint);\n if (!info) {\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\n }\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\n throw new Error(\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\n );\n }\n return info.data[SPL_MINT_DECIMALS_OFFSET];\n}\n\n// ============================================================================\n// PumpSwap\n// ============================================================================\n\n/**\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\n */\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\n\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\n// account layout (Anchor discriminator = 8 bytes):\n// [0:8] discriminator\n// [8] pool_bump u8\n// [9:11] index u16\n// [11:43] creator Pubkey\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\n// [107:139] lp_mint Pubkey\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\n// [203:211] lp_supply u64\n// [211:243] coin_creator Pubkey\n//\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\n// pubkeys. Verified against the live ANSEM pool on mainnet\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\n// balance at verification time). Note the base vault (holding the pump.fun token)\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\n\n/**\n * Parse a PumpSwap constant-product AMM pool account.\n * @internal\n */\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\n if (data.length < PUMPSWAP_MIN_LEN) {\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\n }\n return {\n dexType: \"pumpswap\",\n poolAddress,\n baseMint: new PublicKey(data.slice(43, 75)),\n quoteMint: new PublicKey(data.slice(75, 107)),\n baseVault: new PublicKey(data.slice(139, 171)),\n quoteVault: new PublicKey(data.slice(171, 203)),\n };\n}\n\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\n\n/**\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\n * converted to USD.\n *\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\n *\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\n * at all unless multiplied by the SOL/USD rate.\n *\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\n * whether SOL→USD conversion applies)\n * @param vaultData - Base and quote vault (SPL token account) raw data\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\n * PumpSwap pool).\n * @internal\n */\nfunction computePumpSwapPriceE6(\n poolData: Uint8Array,\n vaultData: { base: Uint8Array; quote: Uint8Array },\n decimals: { base: number; quote: number },\n solPriceE6?: bigint,\n): bigint {\n if (poolData.length < PUMPSWAP_MIN_LEN) {\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\n }\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\n }\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\n }\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\n\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\n\n const baseAmount = readU64LE(baseDv, 64);\n const quoteAmount = readU64LE(quoteDv, 64);\n\n if (baseAmount === 0n) return 0n;\n\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\n // the numerator by both the base-decimal correction AND the 1e6 output scale\n // before the single division, so low-priced tokens don't truncate to 0n.\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\n const baseScale = 10n ** BigInt(decimals.base);\n const quoteScale = 10n ** BigInt(decimals.quote);\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\n\n const quoteMint = new PublicKey(poolData.slice(75, 107));\n if (quoteMint.equals(WSOL_MINT)) {\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\n if (solPriceE6 === undefined) {\n throw new Error(\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\n );\n }\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\n }\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\n // already ~USD once decimal-adjusted — no further conversion needed.\n return quotePerBaseE6;\n}\n\n// ============================================================================\n// Raydium CLMM\n// ============================================================================\n\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\n\n/**\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\n * @internal\n */\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\n }\n return {\n dexType: \"raydium-clmm\",\n poolAddress,\n baseMint: new PublicKey(data.slice(73, 105)),\n quoteMint: new PublicKey(data.slice(105, 137)),\n };\n}\n\n/**\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\n *\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\n *\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\n *\n * @internal\n */\nconst MAX_TOKEN_DECIMALS = 24;\n\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\n throw new Error(\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\n );\n }\n}\n\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\n }\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n const decimals0 = data[233];\n const decimals1 = data[234];\n\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\n throw new Error(\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\n );\n }\n\n const sqrtPriceX64 = readU128LE(dv, 253);\n\n if (sqrtPriceX64 === 0n) return 0n;\n\n // #210: defer truncation to a single shift at the very end. The previous form\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\n\n const decimalDiff = 6 + decimals0 - decimals1;\n const adjustedDiff = decimalDiff - 6;\n\n if (adjustedDiff >= 0) {\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\n } else {\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\n }\n}\n\n// ============================================================================\n// Meteora DLMM\n// ============================================================================\n\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\n// [0:8] discriminator\n// [8:40] parameters (StaticParameters, 32 bytes)\n// [40:72] v_parameters (VariableParameters, 32 bytes)\n// [72] bump_seed u8\n// [73:75] bin_step_seed [u8;2]\n// [75] pair_type u8\n// [76:80] active_id i32\n// [80:82] bin_step u16\n// [82] status u8\n// [83] require_base_factor_seed u8\n// [84:86] base_factor_seed [u8;2]\n// [86] activation_type u8\n// [87] creator_pool_on_off_control u8\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\n// [152:184] reserve_x Pubkey\n// [184:216] reserve_y Pubkey\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\n\n/**\n * Parse a Meteora DLMM (discretized liquidity) pool account.\n *\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\n * on-chain `LbPair` struct layout (verified against mainnet pool\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\n *\n * @internal\n */\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\n if (data.length < METEORA_DLMM_MIN_LEN) {\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\n }\n return {\n dexType: \"meteora-dlmm\",\n poolAddress,\n baseMint: new PublicKey(data.slice(88, 120)),\n quoteMint: new PublicKey(data.slice(120, 152)),\n };\n}\n\n/**\n * Compute Meteora DLMM spot price from active_id and bin_step.\n *\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\n *\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\n * For negative active_id, computes the inverse.\n *\n * @internal\n */\nconst MAX_BIN_STEP = 10_000;\nconst MAX_ACTIVE_ID_ABS = 500_000;\n\nfunction computeMeteoraDlmmPriceE6(\n data: Uint8Array,\n decimalsBase: number,\n decimalsQuote: number,\n): bigint {\n if (data.length < METEORA_DLMM_MIN_LEN) {\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\n }\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\n // They happen to encode the same integer for most pools (explaining why the\n // old code produced correct prices), but reading the correct field is required\n // for correctness once those fields diverge.\n const binStep = dv.getUint16(80, true);\n const activeId = dv.getInt32(76, true);\n\n if (binStep === 0) return 0n;\n if (binStep > MAX_BIN_STEP) {\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\n }\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\n throw new Error(\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\n );\n }\n\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\n\n const isNeg = activeId < 0;\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\n\n let result = SCALE;\n let b = base;\n\n while (exp > 0n) {\n if (exp & 1n) {\n result = (result * b) / SCALE;\n }\n exp >>= 1n;\n if (exp > 0n) {\n b = (b * b) / SCALE;\n }\n }\n\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\n // arbitrary-precision, so the intermediate products cannot overflow.\n const diff = decimalsBase - decimalsQuote;\n\n if (isNeg) {\n if (result === 0n) return 0n;\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\n if (diff >= 0) {\n return (num * 10n ** BigInt(diff)) / result;\n }\n return num / (result * 10n ** BigInt(-diff));\n } else {\n // price_e6 = (result / 1e12) * 10^diff\n if (diff >= 0) {\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\n }\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Read a little-endian u64 from a DataView. */\nfunction readU64LE(dv: DataView, offset: number): bigint {\n const lo = BigInt(dv.getUint32(offset, true));\n const hi = BigInt(dv.getUint32(offset + 4, true));\n return lo | (hi << 32n);\n}\n\n/** Read a little-endian u128 from a DataView. */\nfunction readU128LE(dv: DataView, offset: number): bigint {\n const lo = readU64LE(dv, offset);\n const hi = readU64LE(dv, offset + 8);\n return lo | (hi << 64n);\n}\n","/**\n * Oracle account parsing utilities.\n *\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\n * so that this parser and the on-chain program agree byte-for-byte:\n *\n * CHAINLINK_HEADER_SIZE = 192\n * offset 8: version (u8) CL_OFF_VERSION\n * offset 138: decimals (u8) CL_OFF_DECIMALS\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\n *\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\n *\n * These utilities validate oracle data BEFORE parsing to prevent silent\n * propagation of stale or malformed Chainlink data as price.\n */\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * Minimum buffer size to read Chainlink price data.\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\n * The previous value (224) was smaller than the program's own floor, so the SDK\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\n * answer at offset 216.\n */\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\n\n/** Maximum reasonable decimals for a price feed */\nconst MAX_DECIMALS = 18;\n\n/** Offset of decimals field in Chainlink aggregator account */\nconst CHAINLINK_DECIMALS_OFFSET = 138;\n\n/**\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\n */\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\n\n/**\n * Offset of the latest answer.\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\n */\nconst CHAINLINK_ANSWER_OFFSET = 216;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface OraclePrice {\n price: bigint;\n decimals: number;\n /** Unix timestamp (seconds) of the last oracle update, if available. */\n updatedAt?: number;\n}\n\nexport interface ParseChainlinkOptions {\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\n maxStalenessSeconds?: number;\n /**\n * How far ahead of the local clock a publish timestamp may be before it is\n * treated as invalid rather than as clock skew. Defaults to 60s.\n * Only consulted when `maxStalenessSeconds` is set.\n */\n futureToleranceSeconds?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Browser-compatible read helpers using DataView\n// ---------------------------------------------------------------------------\n\nfunction readU8(data: Uint8Array, off: number): number {\n return data[off];\n}\n\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\n}\n\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\n}\n\nfunction readU32LE(data: Uint8Array, off: number): number {\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\n}\n\n/**\n * Default tolerance for a publish timestamp that appears to be in the future.\n *\n * The program compares the feed timestamp against the on-chain clock\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\n * between a user's machine and the cluster would otherwise reject a perfectly\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\n */\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Parse price data from a Chainlink aggregator account buffer.\n *\n * Validates:\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\n * program's own CHAINLINK_FEED_MIN_LEN)\n * - Decimals are in a reasonable range (0-18)\n * - Price is positive (non-zero)\n *\n * @param data - Raw account data from Chainlink aggregator\n * @param options - Optional staleness check (maxStalenessSeconds)\n * @returns Parsed oracle price with decimals and last-update timestamp\n * @throws if the buffer is invalid, contains unreasonable data, or (when\n * maxStalenessSeconds is set) the last update is older than that bound\n */\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\n if (data.length < CHAINLINK_MIN_SIZE) {\n throw new Error(\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\n );\n }\n\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\n if (decimals > MAX_DECIMALS) {\n throw new Error(\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\n );\n }\n\n // The program reads the answer as a full i128 LE (read_i128_le at\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\n // high (signed) halves rather than reading only the low 8 bytes, which would\n // silently truncate a large answer into a different price than the chain sees.\n //\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\n // on-chain. `price` is a bigint and holds the full i128 range.\n const answer =\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\n if (answer <= 0n) {\n throw new Error(\n `Oracle price is non-positive: ${answer}`\n );\n }\n const price = answer;\n\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\n\n if (options?.maxStalenessSeconds !== undefined) {\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\n // skipping the check: a zero timestamp means the feed has never published,\n // which is maximally stale, not exempt from staleness.\n if (updatedAt <= 0) {\n throw new Error(\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\n );\n }\n const now = Math.floor(Date.now() / 1000);\n const age = now - updatedAt;\n // The program rejects a negative age, but it measures against the on-chain\n // clock. We only have the local one, so a couple of seconds of ordinary skew\n // must not condemn a healthy feed — only an implausible jump ahead should.\n const futureTolerance =\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\n if (age < -futureTolerance) {\n throw new Error(\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\n `check the feed or the local clock`\n );\n }\n if (age > options.maxStalenessSeconds) {\n throw new Error(\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\n );\n }\n }\n\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\n}\n\n/**\n * Validate that a buffer looks like a valid Chainlink aggregator account.\n * Returns true if the buffer passes all validation checks, false otherwise.\n * Use this for non-throwing validation.\n */\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\n try {\n parseChainlinkPrice(data);\n return true;\n } catch {\n return false;\n }\n}\n\n// Re-export constants for consumers\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\n","import { Connection, PublicKey } from \"@solana/web3.js\";\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\n\n/**\n * Token2022 (Token Extensions) program ID.\n */\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\n);\n\n/**\n * Detect which token program owns a given mint account.\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\n *\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\n * attacker-controlled account owned by an arbitrary program (or a non-mint\n * account) would be accepted and its owner propagated as the \"token program\",\n * letting a forged program be passed into a later token CPI. Now we branch on\n * the owner and accept ONLY the two real token programs, throwing otherwise.\n *\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\n * Token-2022.\n */\nexport async function detectTokenProgram(\n connection: Connection,\n mint: PublicKey,\n): Promise {\n const info = await connection.getAccountInfo(mint);\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\n\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\n\n throw new Error(\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\n );\n}\n\n/**\n * Check if a given token program ID is Token2022.\n */\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\n}\n\n/**\n * Check if a given token program ID is the standard SPL Token program.\n */\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\n}\n","/**\n * @module stake\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\n *\n * Program: percolator-stake (dcccrypto/percolator-stake)\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\n * `src/config/program-ids.ts`)\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\n * this writing; treat as a placeholder until DevOps confirms)\n *\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\n * do not use it for new integrations).\n */\n\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\nexport { TOKEN_2022_PROGRAM_ID };\nimport { safeEnv } from '../config/program-ids.js';\nimport { concatBytes } from '../abi/encode.js';\n\n// ═══════════════════════════════════════════════════════════════\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Known stake program addresses per network.\n *\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\n * module targets — see the module doc above.\n *\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\n * confirms.\n *\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\n * silently default to mainnet: an unconfigured browser caller would have resolved to\n * a real, executing mainnet program rather than failing safe.\n */\nexport const STAKE_PROGRAM_IDS = {\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\n} as const;\nObject.freeze(STAKE_PROGRAM_IDS);\n\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\n\n/**\n * Resolve the stake program ID for the given network.\n *\n * Priority:\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\n *\n * Throws a clear error on mainnet when no address is available so callers\n * surface the gap instead of silently hitting the devnet program.\n */\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\n // Only consult the env override when no explicit network arg is provided.\n // An explicit network argument always wins so tests and multi-network callers\n // are not silently redirected to a DevOps-set override address.\n if (!network) {\n const override = safeEnv('STAKE_PROGRAM_ID');\n if (override) {\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\n // ambient env poisoning while allowing fresh pre-deploy addresses).\n if (\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\n ) {\n throw new Error(\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\n );\n }\n console.warn(\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\n );\n return new PublicKey(override);\n }\n }\n\n const detectedNetwork =\n network ??\n (() => {\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\n safeEnv('NETWORK')?.toLowerCase() ?? '';\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\n if (n === 'devnet') return 'devnet' as const;\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\n // i.e. in every browser bundle, where process.env is empty because env vars\n // are not inlined into third-party SDK code. An unconfigured frontend caller\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\n //\n // We deliberately do NOT substitute a devnet default here. Unlike\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\n // defaulting to devnet would merely defer it to the day mainnet launches and\n // a forgotten env var silently points a mainnet UI at the devnet vault.\n // Refuse to guess: the network must be explicit.\n // The message must not assert a cause it has not established. This fires in\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\n // with process.env fully available — so claiming \"browser bundle\" would send\n // a server-side caller chasing the wrong thing.\n throw new Error(\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\n 'for the wrong network.',\n );\n })();\n\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\n if (!id) {\n throw new Error(\n `Stake program not deployed on ${detectedNetwork}. ` +\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\n );\n }\n return new PublicKey(id);\n}\n\n/**\n * Default export — resolves for the current runtime network.\n * Use getStakeProgramId() with an explicit network argument where possible.\n *\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\n * resolving to the devnet address.\n */\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\n\n// ═══════════════════════════════════════════════════════════════\n// Instruction Tags — ADOPTED percolator-stake lineage\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\n//\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\n// side-by-side tag-delta table this was verified against. The comparison is now\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\n// NEW address that already runs the ADOPTED lineage below — there is no more\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\n// ═══════════════════════════════════════════════════════════════\n\nexport const STAKE_IX = {\n InitPool: 0,\n Deposit: 1,\n Withdraw: 2,\n FlushToInsurance: 3,\n UpdateConfig: 4,\n /**\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\n * zero pubkey CANCELS an outstanding proposal.\n *\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\n * wrapper marketauth rotation (a completely different key, done via the\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\n *\n * Wire: tag(1) + new_admin(32) = 33 bytes.\n * Accounts: [currentAdmin(signer), poolPda(writable)]\n */\n ProposeAdmin: 5,\n /**\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\n * PENDING admin signs to take ownership; requires an outstanding proposal\n * and the signer to equal `pool.pending_admin`.\n *\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\n * removed `AdminSetOracleAuthority` (rejects on-chain).\n *\n * Wire: tag(1) — no payload.\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\n */\n AcceptAdmin: 6,\n /**\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\n * LP holders an exit window. A decrease/unchanged value is rejected here\n * (use UpdateConfig, which applies decreases immediately).\n *\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\n * removed `AdminSetRiskThreshold` (rejects on-chain).\n *\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\n */\n ProposeCooldownIncrease: 7,\n /**\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\n *\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\n */\n CommitCooldownIncrease: 8,\n /**\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\n * proposal.\n *\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\n * removed `AdminResolveMarket` (rejects on-chain).\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda(writable)]\n */\n CancelCooldownIncrease: 9,\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\n TransferAdmin: 5,\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\n AdminSetOracleAuthority: 6,\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\n AdminSetRiskThreshold: 7,\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\n * CommitCooldownIncrease. */\n AdminSetMaintenanceFee: 8,\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\n * CancelCooldownIncrease. */\n AdminResolveMarket: 9,\n /**\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\n * percolator-vault program: transfer withdrawn insurance back into the pool\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\n * books admin-ATA -> pool-vault).\n */\n ReturnInsurance: 10,\n /** @deprecated Legacy alias for ReturnInsurance. */\n AdminWithdrawInsurance: 10,\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\n AdminSetInsurancePolicy: 11,\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\n AccrueFees: 12,\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\n InitTradingPool: 13,\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\n AdminSetHwmConfig: 14,\n /**\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\n * tranches. Sets `junior_fee_mult_bps`.\n *\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\n * below). Sending this payload against the DEPLOYED vault program would\n * execute BindInsuranceAuthority instead; only send it against the\n * ADOPTED percolator-stake lineage.\n *\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\n * Accounts: [admin(signer), poolPda(writable)]\n */\n AdminSetTrancheConfig: 15,\n /**\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\n * Same account shape as Deposit (tag 1).\n *\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\n * there (rejects). Live only on the adopted lineage.\n *\n * Wire: tag(1) + amount(u64) = 9 bytes.\n */\n DepositJunior: 16,\n /**\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\n * (0x0F) in the deployed percolator-vault program.\n *\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\n * binds both in one call, unlike the deployed vault program which only\n * bound insurance_authority. The human admin signs the outer tx as the\n * current authority/operator; vault_auth signs via invoke_signed.\n *\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\n */\n BindInsuranceAuthority: 19,\n /**\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\n * escape that moves the market's `insurance_authority` OFF our vault_auth\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\n * authority. NEW in the adopted lineage — no equivalent in the deployed\n * percolator-vault program (which has no un-bind escape at all).\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\n */\n RotateInsuranceAuthority: 20,\n /**\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\n * After this, no key can rotate ANY per-asset authority back to an\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\n * has completed. NEW in the adopted lineage.\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\n */\n BurnAssetAdmin: 21,\n /**\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\n * lineage.\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\n */\n RotateInsuranceOperator: 22,\n /**\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\n * insurance_operator, not asset_admin. `amount` capped to\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\n * NEW in the adopted lineage.\n *\n * Wire: tag(1) + amount(u64) = 9 bytes.\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\n * tokenProgram, percolatorProgram]\n */\n RecoverFlushedInsurance: 23,\n /**\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\n * without this proxy every stake-initialized market would be permanently\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\n * percolator-stake (see src/instruction.rs / src/processor.rs\n * `process_admin_resolve_market`, tag 24).\n *\n * NOTE on the name: the on-chain enum variant is literally\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\n * avoid re-using that already-claimed object key/export name — the tag-9\n * alias and this tag-24 instruction are unrelated aside from sharing an\n * on-chain name across two different lineages.\n *\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\n */\n AdminResolveMarketCpi: 24,\n /**\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\n * (blocks new deposits). Call after resolving the market on the wrapper\n * directly.\n *\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\n * there (rejects). Live only on the adopted lineage.\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda(writable)]\n */\n SetMarketResolved: 18,\n /**\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\n * signs the CPI via invoke_signed.\n *\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\n * insurance_share_bps(u16) = 7 bytes.\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\n *\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\n * Custom(52)/Custom(51) through the CPI.\n */\n AdminUpdateFeeSplit: 25,\n /**\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\n * signer model as tag 25.\n *\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\n *\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\n * `read_u128`.\n */\n AdminUpdateMaintenanceFeePerSlot: 26,\n /**\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\n *\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\n *\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\n */\n AdminUpdateBackingFeePolicy: 27,\n /**\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\n * model as tag 27.\n *\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\n *\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\n * `read_u64`, wrapper tag 88 with `read_u128`.\n */\n AdminUpdateTradeFeePolicy: 28,\n} as const;\nObject.freeze(STAKE_IX);\n\n// ═══════════════════════════════════════════════════════════════\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * User-facing hint text for `StakeError` custom program error codes\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\n *\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\n * error\" for 25-27 despite them being named enum variants); the hints below\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\n * (missing) on-chain string.\n */\nexport const STAKE_ERRORS: Record = {\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\n 8: \"Market is resolved — no new deposits allowed after resolution\",\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\n};\nObject.freeze(STAKE_ERRORS);\n\n// ═══════════════════════════════════════════════════════════════\n// PDA Derivation\n// ═══════════════════════════════════════════════════════════════\n\nconst TEXT = new TextEncoder();\n\n/** Derive the stake pool PDA for a given slab (market). */\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\n}\n\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\n}\n\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\n return PublicKey.findProgramAddressSync(\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\n\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\nfunction readU64LE(data: Uint8Array, off: number): bigint {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return view.getBigUint64(off, /* littleEndian= */ true);\n}\n\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\nfunction readU16LE(data: Uint8Array, off: number): number {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n return view.getUint16(off, /* littleEndian= */ true);\n}\n\nfunction requireDiscriminator(\n accountName: string,\n data: Uint8Array,\n offset: number,\n expected: Uint8Array,\n): void {\n for (let i = 0; i < expected.length; i += 1) {\n if (data[offset + i] !== expected[i]) {\n throw new Error(`${accountName} invalid discriminator`);\n }\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Instruction Encoders\n// ═══════════════════════════════════════════════════════════════\n\nfunction u64Le(v: bigint | number): Uint8Array {\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\n }\n\n const big = BigInt(v);\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\n const arr = new Uint8Array(8);\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\n}\n\nfunction u128Le(v: bigint | number): Uint8Array {\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\n }\n\n const big = BigInt(v);\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\n const arr = new Uint8Array(16);\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\n view.setBigUint64(8, big >> 64n, true);\n return arr;\n}\n\nfunction u16Le(v: number): Uint8Array {\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\n return arr;\n}\n\n/** Tag 0: InitPool — create stake pool for a slab. */\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.InitPool]),\n u64Le(cooldownSlots),\n u64Le(depositCap),\n );\n}\n\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\n}\n\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\n}\n\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\n}\n\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\nexport function encodeStakeUpdateConfig(\n newCooldownSlots?: bigint | number,\n newDepositCap?: bigint | number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.UpdateConfig]),\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\n u64Le(newCooldownSlots ?? 0n),\n new Uint8Array([newDepositCap != null ? 1 : 0]),\n u64Le(newDepositCap ?? 0n),\n );\n}\n\nfunction removedStakeInstruction(name: string, tag: number): never {\n throw new Error(\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\n );\n}\n\n/**\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\n * proposal.\n *\n * Accounts: [currentAdmin(signer), poolPda(writable)]\n */\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.ProposeAdmin]),\n newAdmin.toBytes(),\n );\n}\n\n/**\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\n * PENDING admin signs to become admin. Requires an outstanding proposal.\n *\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\n */\nexport function encodeStakeAcceptAdmin(): Uint8Array {\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\n}\n\n/**\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\n * until CommitCooldownIncrease is called after the on-chain timelock has\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\n *\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\n */\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\n u64Le(newCooldownSlots),\n );\n}\n\n/**\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\n *\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\n */\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\n}\n\n/**\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\n * increase proposal.\n *\n * Accounts: [admin(signer), poolPda(writable)]\n */\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\n}\n\n/**\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\n * percolator-stake lineage this module targets, tag 5 is the two-step\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\n */\nexport function encodeStakeTransferAdmin(): Uint8Array {\n throw new Error(\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\n );\n}\n\n/**\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\n * lineages). Throws.\n */\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\n void newAuthority;\n throw new Error(\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\n 'lineage — use encodeStakeAcceptAdmin() instead.',\n );\n}\n\n/**\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\n * both lineages). Throws.\n */\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\n void newThreshold;\n throw new Error(\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\n );\n}\n\n/**\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\n * both lineages). Throws.\n */\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\n void newFee;\n throw new Error(\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\n );\n}\n\n/**\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\n * lineages). Throws.\n */\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\n throw new Error(\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\n );\n}\n\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.ReturnInsurance]),\n u64Le(amount),\n );\n}\n\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\n return encodeStakeReturnInsurance(amount);\n}\n\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\nexport function encodeStakeAccrueFees(): Uint8Array {\n return new Uint8Array([STAKE_IX.AccrueFees]);\n}\n\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.InitTradingPool]),\n u64Le(cooldownSlots),\n u64Le(depositCap),\n );\n}\n\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\nexport function encodeStakeAdminSetHwmConfig(\n enabled: boolean,\n hwmFloorBps: number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\n new Uint8Array([enabled ? 1 : 0]),\n u16Le(hwmFloorBps),\n );\n}\n\n/**\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\n *\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\n * percolator-stake lineage; sending it against the currently-deployed vault\n * program would silently execute BindInsuranceAuthority instead.\n *\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\n * Accounts: [admin(signer), poolPda(writable)]\n */\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\n u16Le(juniorFeeMultBps),\n );\n}\n\n/**\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\n *\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\n *\n * Wire: tag(1) + amount(u64) = 9 bytes.\n */\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\n}\n\n/**\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\n * (blocks new deposits). Call after resolving the market on the wrapper\n * directly.\n *\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\n *\n * Wire: tag(1) — no payload.\n * Accounts: [admin(signer), poolPda(writable)]\n */\nexport function encodeStakeSetMarketResolved(): Uint8Array {\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\n}\n\n/**\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\n * (0x0F) in the deployed percolator-vault program.\n *\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\n * then kind=2) — a broader bind than the deployed vault program's\n * single-CPI version (insurance_authority only). Must be called once after\n * InitPool, before FlushToInsurance will work.\n *\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\n *\n * @returns 1-byte Uint8Array `[0x13]`.\n *\n * @example\n * ```ts\n * const data = encodeStakeBindInsuranceAuthority();\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\n * ```\n */\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\n}\n\n/**\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\n *\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\n * @param percolatorProgram Wrapper program ID.\n */\nexport interface BindInsuranceAuthorityAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n vaultAuth: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\n *\n * Account order matches src/processor.rs process_bind_insurance_authority\n * (adopted lineage — same account shape as the deployed vault program's tag\n * 15, only the tag byte moved):\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\n * [1] pool_pda writable (stake pool PDA)\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\n * [3] slab writable (wrapper market; needed for CPI)\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n *\n * @example\n * ```ts\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\n * ```\n */\nexport function bindInsuranceAuthorityAccounts(\n a: BindInsuranceAuthorityAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\n * the deployed percolator-vault program (which has no un-bind escape).\n *\n * Wire: tag(1) — no payload.\n *\n * @returns 1-byte Uint8Array.\n *\n * @example\n * ```ts\n * const data = encodeStakeRotateInsuranceAuthority();\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\n * ```\n */\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\n}\n\n/**\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\n * lineage.\n *\n * Wire: tag(1) — no payload.\n *\n * @returns 1-byte Uint8Array.\n *\n * @example\n * ```ts\n * const data = encodeStakeRotateInsuranceOperator();\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\n * ```\n */\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\n}\n\n/**\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\n *\n * @param admin Pool admin (outer tx signer; == pool.admin).\n * @param poolPda Stake pool PDA.\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\n * @param newTarget The successor authority/operator — co-signs the outer tx.\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\n * @param percolatorProgram Wrapper program ID.\n */\nexport interface RotateInsuranceAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n vaultAuth: PublicKey;\n newTarget: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\n * (tag 22) — identical account order in both (src/processor.rs\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\n * [0] admin signer, read-only (== pool.admin)\n * [1] pool_pda read-only\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\n * [4] slab writable (wrapper market; needed for CPI)\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function rotateInsuranceAccounts(\n a: RotateInsuranceAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\n * After this, no key can rotate ANY per-asset authority back to an\n * admin-controlled key. Call ONCE per market, only after\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\n *\n * Wire: tag(1) — no payload.\n *\n * @returns 1-byte Uint8Array.\n *\n * @example\n * ```ts\n * const data = encodeStakeBurnAssetAdmin();\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\n * ```\n */\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\n}\n\n/**\n * Account inputs for BurnAssetAdmin (tag 21).\n *\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\n * @param poolPda Stake pool PDA (writable — records the burn).\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\n * @param percolatorProgram Wrapper program ID.\n */\nexport interface BurnAssetAdminAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n vaultAuth: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\n * process_burn_asset_admin:\n * [0] admin signer, writable (current asset_admin == pool.admin)\n * [1] pool_pda writable (records asset_admin_burned)\n * [2] vault_auth read-only (placeholder new_authority slot)\n * [3] slab writable (wrapper market; needed for CPI)\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function burnAssetAdminAccounts(\n a: BurnAssetAdminAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: true },\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\n * adopted lineage.\n *\n * Wire: tag(1) + amount(u64) = 9 bytes.\n *\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\n *\n * @example\n * ```ts\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\n * ```\n */\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\n u64Le(amount),\n );\n}\n\n/**\n * Account inputs for RecoverFlushedInsurance (tag 23).\n *\n * @param caller Permissionless caller — no signer check required.\n * @param poolPda Stake pool PDA (writable).\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\n * @param wrapperMarket Wrapper market/slab account (writable).\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\n * @param wrapperVaultAuth Wrapper vault authority PDA.\n * @param tokenProgram Token program.\n * @param percolatorProgram Wrapper program ID.\n */\nexport interface RecoverFlushedInsuranceAccounts {\n caller: PublicKey;\n poolPda: PublicKey;\n poolVault: PublicKey;\n vaultAuth: PublicKey;\n wrapperMarket: PublicKey;\n wrapperVault: PublicKey;\n wrapperVaultAuth: PublicKey;\n tokenProgram: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\n * process_recover_flushed_insurance:\n * [0] caller (no signer check — permissionless)\n * [1] pool_pda writable\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\n * [4] market (wrapper) writable\n * [5] wrapper_vault writable (source — wrapper insurance vault)\n * [6] wrapper_vault_auth read-only\n * [7] token_program read-only\n * [8] percolator_program read-only\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function recoverFlushedInsuranceAccounts(\n a: RecoverFlushedInsuranceAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.caller, isSigner: false, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\n * can call the wrapper's ResolveMarket directly; this instruction has the\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\n * the (human) admin can trigger resolution. Does not mutate any local\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\n * separately afterward for local bookkeeping.\n *\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\n *\n * @returns 1-byte Uint8Array `[24]`.\n *\n * @example\n * ```ts\n * const data = encodeStakeAdminResolveMarketCpi();\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\n * ```\n */\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\n}\n\n/**\n * Account inputs for AdminResolveMarketCpi (tag 24).\n *\n * @param admin Pool admin (outer tx signer; == pool.admin).\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\n * @param percolatorProgram Wrapper program ID (CPI target).\n */\nexport interface AdminResolveMarketCpiAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\n * process_admin_resolve_market:\n * [0] admin signer, read-only (== pool.admin)\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function adminResolveMarketCpiAccounts(\n a: AdminResolveMarketCpiAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\n//\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\n// transaction, so the affected wrapper setters become reachable ONLY through a\n// stake-program CPI proxy. Before these four, exactly one proxy existed\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\n// wrapper handlers reachable — which is the mechanical reason the fee split\n// was unachievable on a staked market.\n//\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\n// VAULT_AUTH PDA signs.\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\n//\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\n *\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\n * whose length is not exactly 6 bytes after the tag.\n *\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\n *\n * Share validation happens in the WRAPPER, not here: a split that does not sum\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\n *\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\n * @returns 7-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\n * ```\n */\nexport function encodeStakeAdminUpdateFeeSplit(\n creatorShareBps: number,\n lpShareBps: number,\n insuranceShareBps: number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\n u16Le(creatorShareBps),\n u16Le(lpShareBps),\n u16Le(insuranceShareBps),\n );\n}\n\n/**\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\n * wrapper tag 88.\n *\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\n *\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\n * u64 fails at the stake program before the CPI is even attempted.\n *\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\n * 0 (maintenance fee disabled). The wrapper\n * range-checks against MAX_PROTOCOL_FEE_ABS.\n * @returns 17-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\n * ```\n */\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\n maintenanceFeePerSlot: bigint | number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\n u128Le(maintenanceFeePerSlot),\n );\n}\n\n/**\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\n * tag 51, signed by the `vault_auth` PDA.\n *\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\n * = 7 bytes.\n *\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\n * @param feeBps Backing fee in bps (u16).\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\n * @returns 7-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\n * const keys = adminUpdateBackingFeePolicyAccounts({\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\n * });\n * ```\n */\nexport function encodeStakeAdminUpdateBackingFeePolicy(\n domain: number,\n feeBps: number,\n insuranceShareBps: number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\n u16Le(domain),\n u16Le(feeBps),\n u16Le(insuranceShareBps),\n );\n}\n\n/**\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\n * 55, signed by the `vault_auth` PDA.\n *\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\n * checks `rest.len() == 8`.\n *\n * Sets `T`, the base trade fee that the four-way split divides.\n *\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\n * values above the market's `max_trading_fee_bps` or\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\n * @returns 9-byte instruction data buffer.\n *\n * @example\n * ```ts\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\n * ```\n */\nexport function encodeStakeAdminUpdateTradeFeePolicy(\n tradeFeeBaseBps: bigint | number,\n): Uint8Array {\n return concatBytes(\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\n u64Le(tradeFeeBaseBps),\n );\n}\n\n/**\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\n *\n * @param admin Pool admin (outer tx signer; == pool.admin).\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\n * @param slab Wrapper market-group slab (writable — CPI target).\n * @param percolatorProgram Wrapper program ID (CPI target).\n */\nexport interface StakeGroupAProxyAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for the GROUP A proxies — src/processor.rs\n * `process_admin_update_fee_split` (tag 25) and\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\n * identical layout:\n * [0] admin signer, read-only (== pool.admin)\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\n * [2] slab writable (wrapper market; CPI target)\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function stakeGroupAProxyAccounts(\n a: StakeGroupAProxyAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\n\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\n\n/**\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\n *\n * @param admin Pool admin (outer tx signer; == pool.admin).\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\n * insurance_authority; signs via invoke_signed.\n * @param slab Wrapper market-group slab (writable — CPI target).\n * @param percolatorProgram Wrapper program ID (CPI target).\n */\nexport interface StakeGroupBProxyAccounts {\n admin: PublicKey;\n poolPda: PublicKey;\n vaultAuth: PublicKey;\n slab: PublicKey;\n percolatorProgram: PublicKey;\n}\n\n/**\n * Build account keys for the GROUP B proxies — src/processor.rs\n * `process_admin_update_backing_fee_policy` (tag 27) and\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\n * layout:\n * [0] admin signer, read-only (== pool.admin)\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\n * [3] slab writable (wrapper market; CPI target)\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\n *\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\n * difference from GROUP A, and getting it wrong makes the CPI fail its\n * authority check rather than fail loudly at the account level.\n *\n * @param a Named accounts.\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\n */\nexport function stakeGroupBProxyAccounts(\n a: StakeGroupBProxyAccounts,\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: false },\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n ];\n}\n\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\n\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\n\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\nexport function encodeStakeAdminSetInsurancePolicy(\n authority: PublicKey,\n minWithdrawBase: bigint | number,\n maxWithdrawBps: number,\n cooldownSlots: bigint | number,\n): Uint8Array {\n void authority;\n void minWithdrawBase;\n void maxWithdrawBps;\n void cooldownSlots;\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\n}\n\n// ═══════════════════════════════════════════════════════════════\n// On-Chain State Layout — StakePool decoded fields\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\n * and PERC-303 (tranches).\n *\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\n * `_reserved` layout (verified against `state.rs` on\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\n * whatever bytes the program actually writes):\n *\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\n * (added later, #242) write into [10..18]/[18..26] regardless.\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\n * - This decoder reads both field sets as the raw bytes currently define\n * them (matching on-chain reality); it does NOT attempt to reconcile or\n * invalidate one set when the other is in use. Callers combining HWM and\n * the cooldown timelock on one pool should treat both `hwm*` and\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\n * against a direct on-chain read before trusting either.\n */\nexport interface StakePoolState {\n isInitialized: boolean;\n bump: number;\n vaultAuthorityBump: number;\n adminTransferred: boolean;\n marketResolved: boolean;\n\n slab: PublicKey;\n admin: PublicKey;\n collateralMint: PublicKey;\n lpMint: PublicKey;\n vault: PublicKey;\n\n totalDeposited: bigint;\n totalLpSupply: bigint;\n cooldownSlots: bigint;\n depositCap: bigint;\n totalFlushed: bigint;\n totalReturned: bigint;\n totalWithdrawn: bigint;\n\n percolatorProgram: PublicKey;\n\n /**\n * Pending admin for the two-step rotation (stake v2, offset 288).\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\n */\n pendingAdmin: PublicKey | null;\n\n // PERC-272: Fee yield fields\n totalFeesEarned: bigint;\n lastFeeAccrualSlot: bigint;\n lastVaultSnapshot: bigint;\n poolMode: number;\n\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\n // [0..8] discriminator\n // [8] version\n // [9] market_resolved\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\n // [24..32] PERC-313 hwm_last_epoch (u64)\n // [32] PERC-303 tranche_enabled\n // [33..41] PERC-303 junior_balance (u64)\n // [41..49] PERC-303 junior_total_lp (u64)\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\n // [51..59] N-realized_junior_loss (u64) — issue #161\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\n // [60..64] free\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\n\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\n hwmEnabled: boolean;\n epochHighWaterTvl: bigint;\n hwmFloorBps: number;\n hwmLastEpoch: bigint;\n\n // PERC-303: Tranche fields (from _reserved[32..51])\n trancheEnabled: boolean;\n juniorBalance: bigint;\n juniorTotalLp: bigint;\n juniorFeeMultBps: number;\n\n /**\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\n * ⚠️ Aliases HWM bytes — see interface doc.\n */\n pendingCooldownSlots: bigint;\n /**\n * #242 timelock: the slot at which the pending cooldown increase was\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\n * ⚠️ Aliases HWM bytes — see interface doc.\n */\n cooldownProposedAtSlot: bigint;\n /**\n * Cumulative insurance loss a fully-exited junior tranche permanently\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\n * total_pool_value() so recovered tokens don't windfall senior.\n */\n realizedJuniorLoss: bigint;\n /**\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\n * stay disabled — the wrapper roles cannot be moved back to an\n * admin-controlled key.\n */\n assetAdminBurned: boolean;\n /**\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\n * collateral actually recovered from the WRAPPER via the tag-23\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\n * insurance back out of the wrapper. Real struct field at offset 384..392\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\n *\n * Deliberately separate from `totalReturned`, which is also bumped by two\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\n */\n totalRecoveredFromWrapper: bigint | null;\n}\n\n/**\n * Size of StakePool on-chain (bytes) — v1 layout.\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\n * The _reserved block in v1 starts at offset 288; version byte = 1.\n *\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\n * migration is needed\"). v1/352-byte pools can only ever be observed as\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\n * redeploy (which abandons every existing market/pool wholesale — VERSION\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\n * detection exists purely to decode those pre-redeploy artifacts if you ever\n * need to; the ADOPTED program itself never creates a v1 pool.\n */\nexport const STAKE_POOL_SIZE_V1 = 352;\n\n/**\n * Size of StakePool on-chain (bytes) — v2 layout.\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\n * The _reserved block in v2 starts at offset 320; version byte = 2.\n * Verified via `core::mem::size_of::()` field-by-field against\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\n * padding (every u64 field lands on an 8-aligned cumulative offset).\n *\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\n * still needs to construct a v2-shaped buffer explicitly.\n */\nexport const STAKE_POOL_SIZE_V2 = 384;\n\n/**\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\n * instead of the broader (and gameable) `total_returned` counter — see\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\n * Verified via `core::mem::size_of::()` field-by-field against\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\n * padding (the appended u64 lands on the already-8-aligned offset 384).\n */\nexport const STAKE_POOL_SIZE_V3 = 392;\n\n/**\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\n * ADOPTED percolator-stake lineage creates. Currently equal to\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\n * constants in new code so a future version bump doesn't silently change the\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\n */\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\nexport const STAKE_POOL_CURRENT_VERSION = 3;\n\n/**\n * Decode a StakePool account from raw data buffer.\n *\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\n * v2 and v3). The layout version is detected from the data length before\n * reading the discriminator.\n *\n * v1/v2 support exists only to decode legacy pools created before the\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\n * on-chain `_reserved` layout collision).\n *\n * Uses DataView for all u64/u16 reads — browser-safe.\n */\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\n if (!isV3 && !isV2 && !isV1) {\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\n }\n\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\n // AFTER _reserved, not inside it, so the block start doesn't move again).\n const reservedOffset = isV1 ? 288 : 320;\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\n const version = data[reservedOffset + 8];\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\n if (version !== expectedVersion) {\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\n }\n\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n let off = 0;\n const isInitialized = bytes[off] === 1; off += 1;\n const bump = bytes[off]; off += 1;\n const vaultAuthorityBump = bytes[off]; off += 1;\n const adminTransferred = bytes[off] === 1; off += 1;\n off += 4; // _padding\n\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n\n const totalDeposited = readU64LE(bytes, off); off += 8;\n const totalLpSupply = readU64LE(bytes, off); off += 8;\n const cooldownSlots = readU64LE(bytes, off); off += 8;\n const depositCap = readU64LE(bytes, off); off += 8;\n const totalFlushed = readU64LE(bytes, off); off += 8;\n const totalReturned = readU64LE(bytes, off); off += 8;\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\n\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\n\n // PERC-272 fields (offset 256..288 in both v1 and v2)\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\n const poolMode = bytes[off]; off += 1;\n off += 7; // _mode_padding (off is now 288)\n\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\n let pendingAdmin: PublicKey | null = null;\n if (isV2 || isV3) {\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\n ? null\n : new PublicKey(pendingAdminBytes);\n }\n\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\n const reservedStart = off;\n // _reserved[8] = version (skipped)\n // _reserved[9] = market_resolved\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\n const marketResolved = bytes[reservedStart + 9] === 1;\n const hwmEnabled = bytes[reservedStart + 10] === 1;\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\n\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\n const trancheEnabled = bytes[reservedStart + 32] === 1;\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\n\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\n\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\n\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\n const totalRecoveredFromWrapper = isV3\n ? readU64LE(bytes, reservedStart + 64)\n : null;\n\n return {\n isInitialized,\n bump,\n vaultAuthorityBump,\n adminTransferred,\n marketResolved,\n slab,\n admin,\n collateralMint,\n lpMint,\n vault,\n totalDeposited,\n totalLpSupply,\n cooldownSlots,\n depositCap,\n totalFlushed,\n totalReturned,\n totalWithdrawn,\n percolatorProgram,\n pendingAdmin,\n totalFeesEarned,\n lastFeeAccrualSlot,\n lastVaultSnapshot,\n poolMode,\n hwmEnabled,\n epochHighWaterTvl,\n hwmFloorBps,\n hwmLastEpoch,\n trancheEnabled,\n juniorBalance,\n juniorTotalLp,\n juniorFeeMultBps,\n pendingCooldownSlots,\n cooldownProposedAtSlot,\n realizedJuniorLoss,\n assetAdminBurned,\n totalRecoveredFromWrapper,\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// StakeDeposit PDA decoder\n// ═══════════════════════════════════════════════════════════════\n\n/** Size of StakeDeposit on-chain (bytes). */\nexport const STAKE_DEPOSIT_SIZE = 152;\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\n\n/** Decoded StakeDeposit PDA state. */\nexport interface StakeDepositState {\n isInitialized: boolean;\n bump: number;\n pool: PublicKey;\n user: PublicKey;\n lastDepositSlot: bigint;\n lpAmount: bigint;\n}\n\n/**\n * Decode a StakeDeposit PDA account from raw data.\n *\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\n * [0] is_initialized u8\n * [1] bump u8\n * [2..8] _padding\n * [8..40] pool [u8; 32]\n * [40..72] user [u8; 32]\n * [72..80] last_deposit_slot u64\n * [80..88] lp_amount u64\n * [88..152] _reserved\n */\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\n if (data.length < STAKE_DEPOSIT_SIZE) {\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\n }\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\n return {\n isInitialized: data[0] === 1,\n bump: data[1],\n pool: new PublicKey(data.subarray(8, 40)),\n user: new PublicKey(data.subarray(40, 72)),\n lastDepositSlot: readU64LE(data, 72),\n lpAmount: readU64LE(data, 80),\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Account Specs (for building TransactionInstructions)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface StakeAccounts {\n /** InitPool accounts */\n initPool: {\n admin: PublicKey;\n slab: PublicKey;\n pool: PublicKey;\n lpMint: PublicKey;\n vault: PublicKey;\n vaultAuth: PublicKey;\n collateralMint: PublicKey;\n percolatorProgram: PublicKey;\n };\n /** Deposit accounts */\n deposit: {\n user: PublicKey;\n pool: PublicKey;\n userCollateralAta: PublicKey;\n vault: PublicKey;\n lpMint: PublicKey;\n userLpAta: PublicKey;\n vaultAuth: PublicKey;\n depositPda: PublicKey;\n };\n /** Withdraw accounts */\n withdraw: {\n user: PublicKey;\n pool: PublicKey;\n userLpAta: PublicKey;\n lpMint: PublicKey;\n vault: PublicKey;\n userCollateralAta: PublicKey;\n vaultAuth: PublicKey;\n depositPda: PublicKey;\n };\n /** FlushToInsurance accounts (CPI from stake → percolator) */\n flushToInsurance: {\n caller: PublicKey;\n pool: PublicKey;\n vault: PublicKey;\n vaultAuth: PublicKey;\n slab: PublicKey;\n wrapperVault: PublicKey;\n percolatorProgram: PublicKey;\n };\n}\n\n/**\n * Build account keys for InitPool instruction.\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\n *\n * @param a - Named accounts for the InitPool instruction.\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\n */\nexport function initPoolAccounts(\n a: StakeAccounts['initPool'],\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n) {\n return [\n { pubkey: a.admin, isSigner: true, isWritable: true },\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\n { pubkey: a.pool, isSigner: false, isWritable: true },\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\n { pubkey: a.vault, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Build account keys for Deposit instruction.\n *\n * @param a - Named accounts for the Deposit instruction.\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\n */\nexport function depositAccounts(\n a: StakeAccounts['deposit'],\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n) {\n return [\n { pubkey: a.user, isSigner: true, isWritable: false },\n { pubkey: a.pool, isSigner: false, isWritable: true },\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\n { pubkey: a.vault, isSigner: false, isWritable: true },\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Build account keys for Withdraw instruction.\n *\n * @param a - Named accounts for the Withdraw instruction.\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\n */\nexport function withdrawAccounts(\n a: StakeAccounts['withdraw'],\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n) {\n return [\n { pubkey: a.user, isSigner: true, isWritable: false },\n { pubkey: a.pool, isSigner: false, isWritable: true },\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\n { pubkey: a.vault, isSigner: false, isWritable: true },\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\n ];\n}\n\n/**\n * Build account keys for FlushToInsurance instruction.\n *\n * @param a - Named accounts for the FlushToInsurance instruction.\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\n */\nexport function flushToInsuranceAccounts(\n a: StakeAccounts['flushToInsurance'],\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\n) {\n return [\n { pubkey: a.caller, isSigner: true, isWritable: false },\n { pubkey: a.pool, isSigner: false, isWritable: true },\n { pubkey: a.vault, isSigner: false, isWritable: true },\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\n { pubkey: a.slab, isSigner: false, isWritable: true },\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\n ];\n}\n","/**\n * @module adl\n * Percolator ADL (Auto-Deleveraging) client utilities.\n *\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\n * The most profitable positions on the dominant side are deleveraged first.\n *\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\n * instruction being structurally available to any signer.\n *\n * API surface:\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\n * - AdlRankingResult — full ranking with trigger status\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\n * - AdlApiRanking — single ranked position from /api/adl/rankings\n * - AdlApiResult — full result from /api/adl/rankings\n * - AdlSide — \"long\" | \"short\"\n */\n\nimport {\n Connection,\n PublicKey,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n fetchSlab,\n parseAllAccounts,\n parseEngine,\n parseConfig,\n detectSlabLayout,\n AccountKind,\n Account,\n SlabLayout,\n} from \"./slab.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Position side derived from positionSize sign. */\nexport type AdlSide = \"long\" | \"short\";\n\nconst V17_ADL_UNSUPPORTED_MESSAGE =\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\n\n/**\n * A ranked open position for ADL purposes.\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\n * and will be deleveraged first.\n */\nexport interface AdlRankedPosition {\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\n idx: number;\n /** Owner public key. */\n owner: PublicKey;\n /** Raw position size (i128 — negative = short, positive = long). */\n positionSize: bigint;\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\n pnl: bigint;\n /** Capital at entry in lamports (u128). */\n capital: bigint;\n /**\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\n * pnlPct = pnl * 10_000 / capital.\n * Higher = more profitable = deleveraged first.\n */\n pnlPct: bigint;\n /** Long or short. */\n side: AdlSide;\n /**\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\n * `-1` if position size is zero (inactive).\n */\n adlRank: number;\n}\n\n/**\n * Result of `fetchAdlRankedPositions`.\n */\nexport interface AdlRankingResult {\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\n ranked: AdlRankedPosition[];\n /**\n * Longs ranked separately (adlRank within this subset).\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\n */\n longs: AdlRankedPosition[];\n /**\n * Shorts ranked separately (adlRank within this subset).\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\n * unrealised gain for the short-side holder).\n */\n shorts: AdlRankedPosition[];\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\n isTriggered: boolean;\n /** pnl_pos_tot from engine state. */\n pnlPosTot: bigint;\n /** max_pnl_cap from market config. */\n maxPnlCap: bigint;\n /**\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\n *\n * `null` when the side cannot be determined — either engine state could not be\n * parsed at all, OR the detected slab layout carries no open-interest fields.\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\n *\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\n * convention, not an on-chain guarantee — the deployed wrapper\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\n */\n dominantSide: AdlSide | null;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Compute PnL% in basis points for a position.\n * Returns 0n when capital is 0 to avoid division by zero.\n */\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\n if (capital === 0n) return 0n;\n return (pnl * 10_000n) / capital;\n}\n\n// ---------------------------------------------------------------------------\n// Core API\n// ---------------------------------------------------------------------------\n\n/**\n * Check whether ADL is currently triggered on a slab.\n *\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\n *\n * @param slabData - Raw slab account bytes.\n * @returns true if ADL is triggered.\n *\n * @example\n * ```ts\n * const data = await fetchSlab(connection, slabKey);\n * if (isAdlTriggered(data)) {\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\n * }\n * ```\n */\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\n const layout = detectSlabLayout(slabData.length, slabData);\n if (!layout) return false;\n try {\n const engine = parseEngine(slabData);\n if (engine.pnlPosTot === 0n) return false;\n const config = parseConfig(slabData, layout);\n if (config.maxPnlCap === 0n) return false;\n return engine.pnlPosTot > config.maxPnlCap;\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\n *\n * Positions are ranked separately per side:\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\n *\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\n * the position at rank 0 of the dominant side is deleveraged first.\n *\n * @param connection - Solana connection.\n * @param slab - Slab (market) public key.\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\n *\n * @example\n * ```ts\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\n * if (isTriggered && longs.length > 0) {\n * const target = longs[0]; // highest PnL long\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\n * }\n * ```\n */\nexport async function fetchAdlRankedPositions(\n connection: Connection,\n slab: PublicKey\n): Promise {\n const data = await fetchSlab(connection, slab);\n return rankAdlPositions(data);\n}\n\n/**\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\n * Useful when you already have the slab data (e.g., from a subscription).\n */\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\n const layout = detectSlabLayout(slabData.length, slabData);\n\n let pnlPosTot = 0n;\n let dominantSide: AdlSide | null = null;\n try {\n const engine = parseEngine(slabData);\n pnlPosTot = engine.pnlPosTot;\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\n // comparing them would fabricate \"long\" from absent data.\n const hasOiFields =\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\n if (hasOiFields) {\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\n }\n } catch (err) {\n console.warn(\n `[rankAdlPositions] parseEngine failed:`,\n err instanceof Error ? err.message : err,\n );\n }\n\n let maxPnlCap = 0n;\n let isTriggered = false;\n if (layout) {\n try {\n const config = parseConfig(slabData, layout);\n maxPnlCap = config.maxPnlCap;\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\n } catch {\n // If config parse fails, leave isTriggered=false; ranking still useful.\n }\n }\n\n // Parse all used accounts.\n const accounts = parseAllAccounts(slabData);\n\n // Build ranked position list (user accounts with non-zero position only).\n const positions: AdlRankedPosition[] = [];\n for (const { idx, account } of accounts) {\n if (account.kind !== AccountKind.User) continue;\n if (account.positionSize === 0n) continue;\n\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\n // For shorts, positionSize is negative — PnL computation is symmetric:\n // a short profits when price falls, so pnl stored in the slab already\n // reflects mark-to-market gain/loss for both sides.\n const pnlPct = computePnlPct(account.pnl, account.capital);\n\n positions.push({\n idx,\n owner: account.owner,\n positionSize: account.positionSize,\n pnl: account.pnl,\n capital: account.capital,\n pnlPct,\n side,\n adlRank: -1, // assigned below\n });\n }\n\n // Rank longs: descending pnlPct (most profitable first).\n const longs = positions\n .filter(p => p.side === \"long\")\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\n longs.forEach((p, i) => { p.adlRank = i; });\n\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\n // magnitude, but pnlPct can be negative; sort descending still puts\n // the \"least negative\" aka \"most profitable\" short first).\n const shorts = positions\n .filter(p => p.side === \"short\")\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\n shorts.forEach((p, i) => { p.adlRank = i; });\n\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\n const ranked = [...longs, ...shorts].sort(\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\n );\n\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\n}\n\n/**\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\n * utilities remain available.\n *\n * This function is kept as a deprecated compatibility stub so consumers get a\n * deterministic error instead of a lower-level removed-instruction throw.\n *\n * @param caller - Signer — must be the market keeper/admin authority.\n * @param slab - Slab (market) public key.\n * @param oracle - Primary oracle public key for this market.\n * @param programId - Percolator program ID.\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\n */\nexport function buildAdlInstruction(\n _caller: PublicKey,\n _slab: PublicKey,\n _oracle: PublicKey,\n _programId: PublicKey,\n targetIdx: number,\n _backupOracles: PublicKey[] = []\n): TransactionInstruction {\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\n throw new Error(\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\n );\n }\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\n}\n\n/**\n * Choose which ranked position an ADL should target.\n *\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\n * a test routed through it could not observe the choice.\n *\n * - An explicit `preferSide` always wins.\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\n * a candidate, nothing more.\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\n * rather than guessing a side.\n */\nexport function selectAdlTarget(\n ranking: Pick,\n preferSide?: AdlSide,\n): AdlRankedPosition | undefined {\n if (preferSide === \"long\") return ranking.longs[0];\n if (preferSide === \"short\") return ranking.shorts[0];\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\n return ranking.ranked[0];\n}\n\n/**\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\n *\n * Returns `null` when ADL is not triggered or no eligible positions exist.\n *\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\n * When a target IS found it calls `buildAdlInstruction`, which throws\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\n * revision of this note claimed it did, which was simply wrong.) It is kept for\n * v12 slabs and for when an equivalent v17 instruction lands; the target\n * selection in `selectAdlTarget` stays valid either way.\n *\n * @param connection - Solana connection.\n * @param caller - Signer — must be the market keeper/admin authority.\n * @param slab - Slab (market) public key.\n * @param oracle - Primary oracle public key.\n * @param programId - Percolator program ID.\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\n * If omitted, picks the dominant side's (greater net OI)\n * top-ranked position — or the overall top-ranked position\n * when dominantSide is null (engine unparseable, or a\n * layout with no OI fields such as V0/V2/v12.15).\n * @param backupOracles - Optional extra oracle accounts.\n *\n * @example\n * ```ts\n * const ix = await buildAdlTransaction(\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\n * );\n * if (ix) {\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\n * }\n * ```\n */\nexport async function buildAdlTransaction(\n connection: Connection,\n caller: PublicKey,\n slab: PublicKey,\n oracle: PublicKey,\n programId: PublicKey,\n preferSide?: AdlSide,\n backupOracles: PublicKey[] = []\n): Promise {\n const ranking = await fetchAdlRankedPositions(connection, slab);\n\n if (!ranking.isTriggered) return null;\n\n const target = selectAdlTarget(ranking, preferSide);\n\n if (!target) return null;\n\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\n}\n\n// ---------------------------------------------------------------------------\n// AdlEvent — on-chain log decoder (PERC-8312)\n// ---------------------------------------------------------------------------\n\n/**\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\n *\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\n *\n * Fields:\n * - `tag` — always `0xAD1E_0001` (2970353665n)\n * - `targetIdx` — slab account index that was deleveraged\n * - `price` — oracle price used (in market price units, e.g. e6)\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\n *\n * @example\n * ```ts\n * const logs = tx.meta?.logMessages ?? [];\n * const event = parseAdlEvent(logs);\n * if (event) {\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\n * }\n * ```\n */\nexport interface AdlEvent {\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\n tag: bigint;\n /** Slab account index that was deleveraged. */\n targetIdx: number;\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\n price: bigint;\n /**\n * Absolute position size closed (reassembled from lo+hi u64).\n * This is the i128 absolute value — always non-negative.\n */\n closedAbs: bigint;\n}\n\n/** Magic discriminator for the ADL event log line. */\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\n\n/**\n * Parse the AdlEvent from a transaction's log messages.\n *\n * Searches for a \"Program log: \" line where the first\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\n *\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\n * by this program ID are accepted. Events from CPI-called programs (which can\n * produce identical `Program log:` lines) are silently ignored. Pass the\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\n * Omit only in contexts where the full log has already been filtered.\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\n *\n * @example\n * ```ts\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\n * if (event) {\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\n * }\n * ```\n */\nexport function parseAdlEvent(\n logs: string[],\n percolatorProgramId?: string,\n): AdlEvent | null {\n // Track whether we are currently inside a top-level Percolator invocation.\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\n let insidePercolator = percolatorProgramId === undefined;\n let cpiDepth = 0;\n\n for (const line of logs) {\n if (typeof line !== \"string\") continue;\n\n if (percolatorProgramId !== undefined) {\n // Detect Percolator entry / exit.\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\n insidePercolator = true;\n cpiDepth = 0;\n continue;\n }\n if (\n line.startsWith(`Program ${percolatorProgramId} success`) ||\n line.startsWith(`Program ${percolatorProgramId} failed`)\n ) {\n insidePercolator = false;\n continue;\n }\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\n if (insidePercolator) {\n if (/^Program \\S+ invoke/.test(line)) {\n cpiDepth++;\n continue;\n }\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\n cpiDepth = Math.max(0, cpiDepth - 1);\n continue;\n }\n }\n // Skip log lines that are not inside Percolator or are from a CPI callee.\n if (!insidePercolator || cpiDepth > 0) continue;\n }\n\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\n const match = line.match(\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\n );\n if (!match) continue;\n\n let tag: bigint;\n try {\n tag = BigInt(match[1]);\n } catch {\n continue;\n }\n\n if (tag !== ADL_EVENT_TAG) continue;\n\n try {\n const targetIdx = Number(BigInt(match[2]));\n const price = BigInt(match[3]);\n const closedLo = BigInt(match[4]);\n const closedHi = BigInt(match[5]);\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\n const closedAbs = (closedHi << 64n) | closedLo;\n return { tag, targetIdx, price, closedAbs };\n } catch {\n continue;\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\n// ---------------------------------------------------------------------------\n\n/**\n * A single ranked position as returned by the /api/adl/rankings endpoint.\n */\nexport interface AdlApiRanking {\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\n rank: number;\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\n idx: number;\n /** Absolute PnL (lamports) as a decimal string. */\n pnlAbs: string;\n /** Capital at entry (lamports) as a decimal string. */\n capital: string;\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\n pnlPctMillionths: string;\n}\n\n/**\n * Full result from the /api/adl/rankings endpoint.\n */\nexport interface AdlApiResult {\n slabAddress: string;\n /** pnl_pos_tot from slab engine state (decimal string). */\n pnlPosTot: string;\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\n maxPnlCap: string;\n /** Insurance fund balance (decimal string). */\n insuranceFundBalance: string;\n /** Insurance fund lifetime fee revenue (decimal string). */\n insuranceFundFeeRevenue: string;\n /** Insurance utilization in basis points (0–10000). */\n insuranceUtilizationBps: number;\n /** true if pnlPosTot > maxPnlCap. */\n capExceeded: boolean;\n /** true if insurance fund is fully depleted (balance == 0). */\n insuranceDepleted: boolean;\n /** true if utilization BPS exceeds the configured ADL threshold. */\n utilizationTriggered: boolean;\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\n adlNeeded: boolean;\n /** Excess PnL above cap (decimal string). */\n excess: string;\n /** Ranked positions (empty if adlNeeded=false). */\n rankings: AdlApiRanking[];\n}\n\n/**\n * Fetch ADL rankings from the Percolator API.\n *\n * Calls `GET /api/adl/rankings?slab=
` and returns the\n * parsed result. Use this from the frontend or keeper to determine ADL\n * trigger status and pick the target index.\n *\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\n * @param slab - Slab (market) public key or base58 address string.\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\n * @returns Parsed `AdlApiResult`.\n * @throws On HTTP error or JSON parse failure.\n *\n * @example\n * ```ts\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\n * if (result.adlNeeded && result.rankings.length > 0) {\n * const target = result.rankings[0]; // rank 1 = highest PnL%\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\n * }\n * ```\n */\nexport async function fetchAdlRankings(\n apiBase: string,\n slab: PublicKey | string,\n fetchFn: typeof fetch = fetch,\n): Promise {\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\n const base = apiBase.replace(/\\/$/, \"\");\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\n\n const res = await fetchFn(url);\n if (!res.ok) {\n let body = \"\";\n try { body = await res.text(); } catch { /* ignore */ }\n throw new Error(\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\n );\n }\n\n const json: unknown = await res.json();\n\n // Runtime validation — the API response shape is not guaranteed\n if (typeof json !== \"object\" || json === null) {\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\n }\n const obj = json as Record;\n if (!Array.isArray(obj.rankings)) {\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\n }\n if (typeof obj.adlNeeded !== \"boolean\") {\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\n }\n if (typeof obj.capExceeded !== \"boolean\") {\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\n }\n if (typeof obj.slabAddress !== \"string\") {\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\n }\n if (typeof obj.pnlPosTot !== \"string\") {\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\n }\n if (typeof obj.maxPnlCap !== \"string\") {\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\n }\n for (const entry of obj.rankings) {\n if (typeof entry !== \"object\" || entry === null) {\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\n }\n const r = entry as Record;\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\n }\n }\n\n return json as AdlApiResult;\n}\n","/**\n * @module backing-bucket\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\n *\n * ## Why this module exists\n *\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\n * predicate.\n *\n * ## Why lapsing is routine, not exceptional\n *\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\n * bucket and only computes a fresh horizon once the bucket is no longer\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\n * far-future expiry defers the lapse; it does not prevent it.\n *\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\n *\n * | Attempt against a lapsed domain | Result |\n * |---|---|\n * | settle a **loss** | `EngineLockActive` Custom(21) |\n * | settle a **gain** | `EngineStale` Custom(19) |\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\n *\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\n * keeper duty, alongside the fee crank.\n *\n * ## Layout provenance\n *\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\n *\n * ```\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\n * BackingBucketV16Account size=97\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\n * 88 expiry_slot 96 status\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\n * ```\n *\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\n */\n\nimport {\n V17_MARKET_GROUP_OFF,\n V17_MARKET_GROUP_LEN,\n V17_MARKET_ASSET_SLOT_LEN,\n isV17MarketAccount,\n} from \"./slab.js\";\n\n// ---------------------------------------------------------------------------\n// Little-endian readers (module-local, matching slab.ts's private helpers)\n// ---------------------------------------------------------------------------\n\nfunction readU8At(data: Uint8Array, off: number): number {\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\n return data[off]!;\n}\n\nfunction readU32LEAt(data: Uint8Array, off: number): number {\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\n}\n\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\n}\n\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\n const lo = dv.getBigUint64(0, true);\n const hi = dv.getBigUint64(8, true);\n return (hi << 64n) | lo;\n}\n\n// ---------------------------------------------------------------------------\n// Layout constants — all verified with offset_of! (see module doc)\n// ---------------------------------------------------------------------------\n\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\nexport const V17_GROUP_CONFIG_REL = 32;\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\nexport const V17_GROUP_MODE_REL = 626;\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\n\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\n/** `size_of::()`. */\nexport const V17_BACKING_BUCKET_LEN = 97;\n\n// BackingBucketV16Account field offsets, relative to the bucket start.\nconst BB_MARKET_ID = 0;\nconst BB_FRESH_UNLIENED = 8;\nconst BB_VALID_LIENED = 24;\nconst BB_CONSUMED_LIENED = 40;\nconst BB_IMPAIRED_LIENED = 56;\nconst BB_UTILIZATION_FEE = 72;\nconst BB_EXPIRY_SLOT = 88;\nconst BB_STATUS = 96;\n\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\nexport const V17_MARKET_MODE_LIVE = 0;\n\n/**\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\n * serialized as a single `u8` in declaration order.\n *\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\n */\nexport enum BackingBucketStatus {\n Empty = 0,\n Fresh = 1,\n Expired = 2,\n Impaired = 3,\n}\n\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\nexport function backingBucketStatusName(status: number): string {\n switch (status) {\n case BackingBucketStatus.Empty:\n return \"Empty\";\n case BackingBucketStatus.Fresh:\n return \"Fresh\";\n case BackingBucketStatus.Expired:\n return \"Expired\";\n case BackingBucketStatus.Impaired:\n return \"Impaired\";\n default:\n return `Unknown(${status})`;\n }\n}\n\n/** One source-domain backing bucket, decoded from a v17 market account. */\nexport interface BackingBucketV17 {\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\n domain: number;\n /** `domain / 2` — the asset slot this domain belongs to. */\n assetIndex: number;\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\n side: \"long\" | \"short\";\n /** `BackingBucketV16Account::market_id`. */\n marketId: bigint;\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\n freshUnlienedBackingNum: bigint;\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\n validLienedBackingNum: bigint;\n /** Principal already consumed by settlement. */\n consumedLienedBackingNum: bigint;\n /** Principal whose lien has been impaired. */\n impairedLienedBackingNum: bigint;\n /** Utilization fees accrued to this bucket. */\n utilizationFeeEarnings: bigint;\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\n expirySlot: bigint;\n /** Raw status byte. */\n status: number;\n /** `backingBucketStatusName(status)`. */\n statusName: string;\n /**\n * `status === Fresh && nowSlot >= expirySlot`.\n *\n * This is the *deadlock* condition — settlement against this domain fails in both\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\n * which additionally applies the wrapper's mode and domain-bound gates.\n */\n lapsed: boolean;\n /**\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\n * See {@link isBackingBucketExpirable} for the full derivation.\n */\n expirable: boolean;\n}\n\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\nexport interface BackingBucketMarketState {\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\n mode: number;\n /** `header.current_slot` — the engine's own monotone slot counter. */\n headerCurrentSlot: bigint;\n /**\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\n */\n nowSlot: bigint;\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\n maxMarketSlots: number;\n /** Asset slots physically present in the account buffer. */\n physicalAssetSlots: number;\n /**\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\n * this index are never expirable; see {@link isBackingBucketExpirable}.\n */\n addressableDomainCount: number;\n /** One entry per addressable domain, ascending by `domain`. */\n buckets: BackingBucketV17[];\n}\n\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\nexport interface BackingBucketExpiryContext {\n /** `header.mode`. */\n mode: number;\n /** `max(chainSlot, header.current_slot)`. */\n nowSlot: bigint;\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\n addressableDomainCount: number;\n}\n\n/**\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\n *\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\n * program rather than from prose. In order of evaluation on chain:\n *\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\n * market reaches the same transition through the engine's own\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\n * may be *configured* for more slots than its account was *sized* for.\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\n * both deadlocked and expirable, and the two boundaries agree\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\n *\n * `now_slot` is never caller-supplied — the program computes\n * `max(Clock::get().slot, header.current_slot)` itself\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\n * bricked. It cannot produce a false positive, because the program recomputes the same\n * `max` and no caller can lower it.\n *\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\n * two more u128 reads to defend against something that indicates corruption anyway.\n *\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\n *\n * @example\n * ```ts\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\n * for (const b of state.buckets) {\n * if (isBackingBucketExpirable(b, state)) {\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\n * }\n * }\n * ```\n */\nexport function isBackingBucketExpirable(\n bucket: Pick,\n ctx: BackingBucketExpiryContext,\n): boolean {\n // (1) Live-only mode gate.\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\n // (4) The lapse condition, exactly as the engine states it.\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\n return ctx.nowSlot >= bucket.expirySlot;\n}\n\n/** Options for {@link parseBackingBucketsV17}. */\nexport interface ParseBackingBucketsOptions {\n /**\n * The current chain slot (`connection.getSlot()`).\n *\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\n * lapses, never over-report them) but a keeper should always supply it — a market whose\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\n * bricked.\n */\n chainSlot?: bigint | number;\n}\n\n/**\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\n *\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\n *\n * @param data - Raw bytes of the v17 market group account.\n * @param opts - See {@link ParseBackingBucketsOptions}.\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\n *\n * @example\n * ```ts\n * const info = await connection.getAccountInfo(marketPk);\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\n * chainSlot: await connection.getSlot(),\n * });\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\n * ```\n */\nexport function parseBackingBucketsV17(\n data: Uint8Array,\n opts: ParseBackingBucketsOptions = {},\n): BackingBucketMarketState {\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\n if (data.length < MIN_LEN) {\n throw new Error(\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\n );\n }\n if (!isV17MarketAccount(data)) {\n throw new Error(\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\n );\n }\n\n const groupOff = V17_MARKET_GROUP_OFF;\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\n const maxMarketSlots = readU32LEAt(\n data,\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\n );\n\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\n const chainSlot =\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\n if (chainSlot < 0n) {\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\n }\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\n\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\n const physicalAssetSlots = Math.max(\n 0,\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\n );\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\n const addressableDomainCount = addressableAssetSlots * 2;\n\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\n const buckets: BackingBucketV17[] = [];\n\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\n const engineBase =\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\n for (const side of [\"long\", \"short\"] as const) {\n const bucketOff =\n engineBase +\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\n\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\n const status = readU8At(data, bucketOff + BB_STATUS);\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\n\n const bucket: BackingBucketV17 = {\n domain,\n assetIndex,\n side,\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\n expirySlot,\n status,\n statusName: backingBucketStatusName(status),\n lapsed,\n expirable: false,\n };\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\n buckets.push(bucket);\n }\n }\n\n return {\n mode,\n headerCurrentSlot,\n nowSlot,\n maxMarketSlots,\n physicalAssetSlots,\n addressableDomainCount,\n buckets,\n };\n}\n\n/**\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\n *\n * Returns domain indices in ascending order, ready to feed straight into\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\n * common case on a healthy market, and the case in which a keeper must send nothing.\n *\n * @param data - Raw bytes of the v17 market group account.\n * @param opts - See {@link ParseBackingBucketsOptions}.\n * @returns Ascending list of expirable domain indices; empty when none are due.\n *\n * @example\n * ```ts\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\n * for (const domain of domains) {\n * tx.add(new TransactionInstruction({\n * programId: WRAPPER_ID,\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\n * }));\n * }\n * ```\n */\nexport function findExpirableBackingDomains(\n data: Uint8Array,\n opts: ParseBackingBucketsOptions = {},\n): number[] {\n return parseBackingBucketsV17(data, opts)\n .buckets.filter((b) => b.expirable)\n .map((b) => b.domain);\n}\n","import {\n Connection,\n type Commitment,\n type ConnectionConfig,\n} from \"@solana/web3.js\";\n\n// ---------------------------------------------------------------------------\n// Configuration Types\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for exponential-backoff retry on RPC calls.\n *\n * @example\n * ```ts\n * const retryConfig: RetryConfig = {\n * maxRetries: 3,\n * baseDelayMs: 500,\n * maxDelayMs: 10_000,\n * retryableStatusCodes: [429, 502, 503],\n * };\n * ```\n */\nexport interface RetryConfig {\n /**\n * Maximum number of retry attempts after the initial request fails.\n * @default 3\n */\n maxRetries?: number;\n\n /**\n * Base delay in ms for exponential backoff.\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\n * @default 500\n */\n baseDelayMs?: number;\n\n /**\n * Maximum delay in ms (backoff cap).\n * @default 10_000\n */\n maxDelayMs?: number;\n\n /**\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\n * jitter entirely (deterministic backoff).\n * @default 0.25\n */\n jitterFactor?: number;\n\n /**\n * HTTP status codes considered retryable.\n * Errors matching these codes (or containing their string representation)\n * will be retried.\n * @default [429, 502, 503, 504]\n */\n retryableStatusCodes?: number[];\n}\n\n/**\n * Configuration for a single RPC endpoint in the pool.\n *\n * @example\n * ```ts\n * const endpoint: RpcEndpointConfig = {\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\n * weight: 10,\n * label: \"helius-primary\",\n * };\n * ```\n */\nexport interface RpcEndpointConfig {\n /** RPC endpoint URL. */\n url: string;\n\n /**\n * Relative weight for round-robin selection.\n * Higher weight = more requests routed here.\n * @default 1\n */\n weight?: number;\n\n /**\n * Human-readable label for logging / diagnostics.\n * @default url hostname\n */\n label?: string;\n\n /**\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\n * merged into the Solana `Connection` constructor for this endpoint.\n */\n connectionConfig?: ConnectionConfig;\n}\n\n/**\n * Strategy for selecting the next RPC endpoint from the pool.\n *\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\n */\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\n\n/**\n * Full configuration for the RPC connection pool.\n *\n * @example\n * ```ts\n * import { RpcPool } from \"@percolator/sdk\";\n *\n * const pool = new RpcPool({\n * endpoints: [\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\n * ],\n * strategy: \"failover\",\n * retry: { maxRetries: 3, baseDelayMs: 500 },\n * requestTimeoutMs: 30_000,\n * });\n *\n * // Use like a Connection — same surface\n * const slot = await pool.call(conn => conn.getSlot());\n * ```\n */\nexport interface RpcPoolConfig {\n /**\n * One or more RPC endpoints. At least one is required.\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\n */\n endpoints: (RpcEndpointConfig | string)[];\n\n /**\n * How to pick the next endpoint.\n * @default \"failover\"\n */\n strategy?: SelectionStrategy;\n\n /**\n * Retry config applied to every `call()`.\n * Set to `false` to disable retries entirely.\n * @default { maxRetries: 3, baseDelayMs: 500 }\n */\n retry?: RetryConfig | false;\n\n /**\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\n * calls where supported, and is used as a deadline for the health probe.\n * @default 30_000\n */\n requestTimeoutMs?: number;\n\n /**\n * Default Solana commitment level for connections.\n * @default \"confirmed\"\n */\n commitment?: Commitment;\n\n /**\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\n * @default true\n */\n verbose?: boolean;\n\n /**\n * Time in ms after which a continuously unhealthy endpoint is automatically\n * restored to healthy so it can be retried. Set to 0 to disable time-based\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\n * endpoints are exhausted).\n * @default 60_000\n */\n recoveryAfterMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Health Probe\n// ---------------------------------------------------------------------------\n\n/**\n * Result of an RPC health probe.\n *\n * @example\n * ```ts\n * import { checkRpcHealth } from \"@percolator/sdk\";\n *\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\n * ```\n */\nexport interface RpcHealthResult {\n /** The endpoint that was probed. */\n endpoint: string;\n /** Whether the probe succeeded (getSlot returned without error). */\n healthy: boolean;\n /** Round-trip latency in milliseconds (0 if unhealthy). */\n latencyMs: number;\n /** Current slot height (0 if unhealthy). */\n slot: number;\n /** Error message if the probe failed. */\n error?: string;\n}\n\n/**\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\n *\n * @param endpoint - RPC URL to probe\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\n * @returns Health result with latency and slot height\n *\n * @example\n * ```ts\n * import { checkRpcHealth } from \"@percolator/sdk\";\n *\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\n * if (result.healthy) {\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\n * } else {\n * console.error(`RPC down: ${result.error}`);\n * }\n * ```\n */\nexport async function checkRpcHealth(\n endpoint: string,\n timeoutMs: number = 5_000,\n): Promise {\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\n const start = performance.now();\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"getSlot\",\n params: [{ commitment: \"processed\" }],\n }),\n signal: AbortSignal.timeout(timeoutMs),\n });\n const latencyMs = Math.round(performance.now() - start);\n if (!res.ok) {\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\n }\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\n if (json?.error || typeof json?.result !== \"number\") {\n return {\n endpoint,\n healthy: false,\n latencyMs,\n slot: 0,\n error: json?.error?.message ?? \"invalid getSlot response\",\n };\n }\n return { endpoint, healthy: true, latencyMs, slot: json.result };\n } catch (err) {\n const latencyMs = Math.round(performance.now() - start);\n return {\n endpoint,\n healthy: false,\n latencyMs,\n slot: 0,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal Helpers\n// ---------------------------------------------------------------------------\n\n/** Resolved defaults for RetryConfig. */\ninterface ResolvedRetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n jitterFactor: number;\n retryableStatusCodes: number[];\n}\n\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\n if (cfg === false) return null;\n const c = cfg ?? {};\n return {\n maxRetries: c.maxRetries ?? 3,\n baseDelayMs: c.baseDelayMs ?? 500,\n maxDelayMs: c.maxDelayMs ?? 10_000,\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\n };\n}\n\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\n if (typeof ep === \"string\") return { url: ep };\n return ep;\n}\n\nfunction endpointLabel(ep: RpcEndpointConfig): string {\n if (ep.label) return ep.label;\n try {\n return new URL(ep.url).hostname;\n } catch {\n return ep.url.slice(0, 40);\n }\n}\n\nfunction isRetryable(err: unknown, codes: number[]): boolean {\n if (!err) return false;\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\n // error shapes by name BEFORE any substring match below.\n const errName = (err as { name?: unknown })?.name;\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\n const msg = err instanceof Error ? err.message : String(err);\n for (const code of codes) {\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\n let timer: ReturnType;\n const promise = new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), ms);\n });\n return { promise, cancel: () => clearTimeout(timer!) };\n}\n\n/** Sleep utility. */\nfunction sleep(ms: number): Promise {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\n * key, password) from a URL so it is safe for logging / status output.\n */\nfunction redactUrl(raw: string): string {\n try {\n const u = new URL(raw);\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\n for (const k of [...u.searchParams.keys()]) {\n if (sensitive.test(k)) {\n u.searchParams.set(k, \"***\");\n }\n }\n return u.toString();\n } catch {\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\n return raw;\n }\n}\n\n// ---------------------------------------------------------------------------\n// RpcPool\n// ---------------------------------------------------------------------------\n\n/** Per-endpoint tracked state. */\ninterface EndpointState {\n config: RpcEndpointConfig;\n connection: Connection;\n label: string;\n weight: number;\n /** Consecutive failure count. Resets on success. */\n failures: number;\n /** Whether this endpoint is considered healthy. */\n healthy: boolean;\n /** Last probe latency (ms), -1 if never probed. */\n lastLatencyMs: number;\n /**\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\n * failure streak. Cleared on success or manual recovery. Used by the\n * time-based auto-recovery logic in `selectEndpoint`.\n */\n unhealthySince?: number;\n}\n\n/**\n * RPC connection pool with retry, failover, and round-robin support.\n *\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\n * that automatically retries transient errors and fails over to alternate\n * endpoints when one goes down.\n *\n * @example\n * ```ts\n * import { RpcPool } from \"@percolator/sdk\";\n *\n * const pool = new RpcPool({\n * endpoints: [\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\n * ],\n * strategy: \"failover\",\n * retry: { maxRetries: 3 },\n * requestTimeoutMs: 30_000,\n * });\n *\n * // Execute any Connection method through the pool\n * const slot = await pool.call(conn => conn.getSlot());\n *\n * // Or get a raw connection for one-off use\n * const conn = pool.getConnection();\n *\n * // Health check all endpoints\n * const results = await pool.healthCheck();\n * ```\n */\nexport class RpcPool {\n private readonly endpoints: EndpointState[];\n private readonly strategy: SelectionStrategy;\n private readonly retryConfig: ResolvedRetryConfig | null;\n private readonly requestTimeoutMs: number;\n private readonly verbose: boolean;\n /** Time-based recovery window in ms (0 = disabled). */\n private readonly recoveryAfterMs: number;\n\n /** Round-robin index tracker. */\n private rrIndex: number = 0;\n\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\n private static readonly UNHEALTHY_THRESHOLD = 3;\n\n /** Minimum endpoints before auto-recovery is attempted. */\n private static readonly MIN_HEALTHY = 1;\n\n constructor(config: RpcPoolConfig) {\n if (!config.endpoints || config.endpoints.length === 0) {\n throw new Error(\"RpcPool: at least one endpoint is required\");\n }\n\n this.strategy = config.strategy ?? \"failover\";\n this.retryConfig = resolveRetryConfig(config.retry);\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\n this.verbose = config.verbose ?? true;\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\n\n const commitment = config.commitment ?? \"confirmed\";\n\n this.endpoints = config.endpoints.map(raw => {\n const ep = normalizeEndpoint(raw);\n const connConfig: ConnectionConfig = {\n commitment,\n ...ep.connectionConfig,\n };\n return {\n config: ep,\n connection: new Connection(ep.url, connConfig),\n label: endpointLabel(ep),\n weight: Math.max(1, ep.weight ?? 1),\n failures: 0,\n healthy: true,\n lastLatencyMs: -1,\n };\n });\n }\n\n // -----------------------------------------------------------------------\n // Public API\n // -----------------------------------------------------------------------\n\n /**\n * Execute a function against a pooled connection with automatic retry\n * and failover.\n *\n * @param fn - Async function that receives a `Connection` and returns a result.\n * @returns The result of `fn`.\n * @throws The last error if all retries and failovers are exhausted.\n *\n * @example\n * ```ts\n * const balance = await pool.call(c => c.getBalance(pubkey));\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\n * ```\n */\n async call(fn: (connection: Connection) => Promise): Promise {\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\n let lastError: unknown;\n\n // Track which endpoints we have tried in this call to avoid infinite loops.\n const triedEndpoints = new Set();\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\n const maxTotalIterations = maxAttempts + this.endpoints.length;\n let totalIterations = 0;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (++totalIterations > maxTotalIterations) break;\n const epIdx = this.selectEndpoint(triedEndpoints);\n if (epIdx === -1) {\n // All endpoints exhausted\n break;\n }\n const ep = this.endpoints[epIdx];\n\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\n try {\n const result = await Promise.race([\n fn(ep.connection),\n timeout.promise,\n ]);\n\n // Success — reset failure count\n ep.failures = 0;\n ep.healthy = true;\n ep.unhealthySince = undefined;\n return result;\n } catch (err) {\n lastError = err;\n ep.failures++;\n\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\n ep.healthy = false;\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\n if (this.verbose) {\n console.warn(\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\n );\n }\n }\n\n const retryable = this.retryConfig\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\n : false;\n\n if (!retryable) {\n // For non-retryable errors in failover mode, try the next endpoint\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\n triedEndpoints.add(epIdx);\n // Don't count this as a retry attempt — just failover\n attempt--;\n if (triedEndpoints.size >= this.endpoints.length) break;\n continue;\n }\n throw err;\n }\n\n // Retryable error\n if (this.verbose) {\n console.warn(\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\n err instanceof Error ? err.message : err,\n );\n }\n\n // In failover mode, try next endpoint before retrying same one\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\n triedEndpoints.add(epIdx);\n }\n\n // Backoff before retry\n if (attempt < maxAttempts - 1 && this.retryConfig) {\n const delay = computeDelay(attempt, this.retryConfig);\n await sleep(delay);\n }\n } finally {\n timeout.cancel();\n }\n }\n\n // All attempts exhausted — try recovery before giving up\n this.maybeRecoverEndpoints();\n\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\n }\n\n /**\n * Get a raw `Connection` from the current preferred endpoint.\n * Useful when you need to pass a Connection to external code.\n *\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\n *\n * @returns Solana Connection from the current preferred endpoint.\n *\n * @example\n * ```ts\n * const conn = pool.getConnection();\n * const balance = await conn.getBalance(pubkey);\n * ```\n */\n getConnection(): Connection {\n const idx = this.selectEndpoint();\n if (idx === -1) {\n // All marked unhealthy — reset and use first\n this.maybeRecoverEndpoints();\n return this.endpoints[0].connection;\n }\n return this.endpoints[idx].connection;\n }\n\n /**\n * Run a health check against all endpoints in the pool.\n *\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\n * @returns Array of health results, one per endpoint.\n *\n * @example\n * ```ts\n * const results = await pool.healthCheck();\n * for (const r of results) {\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\n * }\n * ```\n */\n async healthCheck(timeoutMs: number = 5_000): Promise {\n const results = await Promise.all(\n this.endpoints.map(async (ep) => {\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\n ep.lastLatencyMs = result.latencyMs;\n ep.healthy = result.healthy;\n if (result.healthy) {\n ep.failures = 0;\n ep.unhealthySince = undefined;\n }\n result.endpoint = redactUrl(result.endpoint);\n return result;\n }),\n );\n return results;\n }\n\n /**\n * Get the number of endpoints in the pool.\n */\n get size(): number {\n return this.endpoints.length;\n }\n\n /**\n * Get the number of currently healthy endpoints.\n */\n get healthyCount(): number {\n return this.endpoints.filter(ep => ep.healthy).length;\n }\n\n /**\n * Get endpoint labels and their current status.\n *\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\n */\n status(): Array<{\n label: string;\n url: string;\n healthy: boolean;\n failures: number;\n lastLatencyMs: number;\n }> {\n return this.endpoints.map(ep => ({\n label: ep.label,\n url: redactUrl(ep.config.url),\n healthy: ep.healthy,\n failures: ep.failures,\n lastLatencyMs: ep.lastLatencyMs,\n }));\n }\n\n // -----------------------------------------------------------------------\n // Internals\n // -----------------------------------------------------------------------\n\n /**\n * Select the next endpoint based on strategy.\n * Returns -1 if no endpoint is available.\n */\n private selectEndpoint(exclude?: Set): number {\n // Time-based auto-recovery: restore endpoints that have been unhealthy\n // for longer than recoveryAfterMs so they can be retried.\n if (this.recoveryAfterMs > 0) {\n const now = Date.now();\n for (const ep of this.endpoints) {\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\n ep.healthy = true;\n ep.failures = 0;\n ep.unhealthySince = undefined;\n if (this.verbose) {\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\n }\n }\n }\n }\n\n const healthy = this.endpoints\n .map((ep, i) => ({ ep, i }))\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\n\n if (healthy.length === 0) {\n // No healthy endpoints — try all non-excluded\n const remaining = this.endpoints\n .map((_, i) => i)\n .filter(i => !(exclude?.has(i)));\n return remaining.length > 0 ? remaining[0] : -1;\n }\n\n if (this.strategy === \"failover\") {\n // Return first healthy (by insertion order)\n return healthy[0].i;\n }\n\n // Weighted round-robin\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\n\n let cumulative = 0;\n for (const { ep, i } of healthy) {\n cumulative += ep.weight;\n if (this.rrIndex < cumulative) return i;\n }\n\n return healthy[healthy.length - 1].i;\n }\n\n /**\n * If all endpoints are unhealthy, reset them so we at least try again.\n */\n private maybeRecoverEndpoints(): void {\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\n if (healthyCount < RpcPool.MIN_HEALTHY) {\n if (this.verbose) {\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\n }\n for (const ep of this.endpoints) {\n ep.healthy = true;\n ep.failures = 0;\n ep.unhealthySince = undefined;\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Standalone retry wrapper (for use without a full pool)\n// ---------------------------------------------------------------------------\n\n/**\n * Execute an async function with exponential-backoff retry.\n *\n * Use this when you already have a `Connection` and just want retry logic\n * without a full pool.\n *\n * @param fn - Async function to execute\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\n * @returns Result of `fn`\n * @throws The last error if all retries are exhausted\n *\n * @example\n * ```ts\n * import { withRetry } from \"@percolator/sdk\";\n * import { Connection } from \"@solana/web3.js\";\n *\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\n * const slot = await withRetry(\n * () => conn.getSlot(),\n * { maxRetries: 3, baseDelayMs: 1000 },\n * );\n * ```\n */\nexport async function withRetry(\n fn: () => Promise,\n config?: RetryConfig,\n): Promise {\n const resolved = resolveRetryConfig(config) ?? {\n maxRetries: 3,\n baseDelayMs: 500,\n maxDelayMs: 10_000,\n jitterFactor: 0.25,\n retryableStatusCodes: [429, 502, 503, 504],\n };\n\n let lastError: unknown;\n const maxAttempts = resolved.maxRetries + 1;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\n throw err;\n }\n\n if (attempt < maxAttempts - 1) {\n const delay = computeDelay(attempt, resolved);\n await sleep(delay);\n }\n }\n }\n\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\n}\n\n// ---------------------------------------------------------------------------\n// Re-export helpers for testing\n// ---------------------------------------------------------------------------\n\n/** @internal — exposed for unit tests only */\nexport const _internal = {\n isRetryable,\n computeDelay,\n resolveRetryConfig,\n normalizeEndpoint,\n endpointLabel,\n} as const;\n","import {\n Connection,\n PublicKey,\n TransactionInstruction,\n Transaction,\n Keypair,\n SendOptions,\n Commitment,\n AccountMeta,\n ComputeBudgetProgram,\n} from \"@solana/web3.js\";\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\n\n/**\n * Rank of the three cluster confirmation levels the RPC reports in\n * `SignatureStatus.confirmationStatus`.\n */\nconst CONFIRMATION_RANK = {\n processed: 0,\n confirmed: 1,\n finalized: 2,\n} as const;\n\n/**\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\n * The deprecated aliases map onto their modern equivalents exactly as\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\n * recent -> processed.\n */\nfunction requiredConfirmationRank(commitment: Commitment): number {\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\n // aliases as:\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\n // 'finalized' | 'max' | 'root' -> requires finalized\n // everything else ('processed', 'recent') -> requires >= processed\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\n // meant a caller asking for `singleGossip` and observing only a `processed`\n // status was told the transaction had SETTLED — reintroducing exactly the\n // premature-settlement bug this function exists to prevent.\n switch (commitment) {\n case \"confirmed\":\n case \"single\":\n case \"singleGossip\":\n return CONFIRMATION_RANK.confirmed;\n case \"finalized\":\n case \"max\":\n case \"root\":\n return CONFIRMATION_RANK.finalized;\n case \"processed\":\n case \"recent\":\n default:\n return CONFIRMATION_RANK.processed;\n }\n}\n\n/**\n * True when an observed signature status is at least as strong as the level the\n * caller asked for. A merely \"processed\" transaction can still be dropped or\n * rolled back, so treating it as settled would reintroduce exactly the premature\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\n */\nfunction meetsCommitment(\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\n required: Commitment\n): boolean {\n if (!observed) return false;\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\n}\n\nexport interface BuildIxParams {\n programId: PublicKey;\n keys: AccountMeta[];\n data: Uint8Array | Buffer;\n}\n\n/**\n * Build a transaction instruction.\n */\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\n return new TransactionInstruction({\n programId: params.programId,\n keys: params.keys,\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\n // Cast to avoid Buffer polyfill issues in the browser.\n data: params.data as Buffer,\n });\n}\n\nexport interface TxResult {\n signature: string;\n slot: number;\n err: string | null;\n hint?: string;\n logs: string[];\n unitsConsumed?: number;\n}\n\nexport interface SimulateOrSendParams {\n connection: Connection;\n ix: TransactionInstruction;\n signers: Keypair[];\n simulate: boolean;\n commitment?: Commitment;\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\n /**\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\n * multiple of 1024 in [32768, 262144].\n */\n heapFrameBytes?: number;\n}\n\n/**\n * Simulate or send a transaction.\n * Returns consistent output for both modes.\n */\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\n\n/**\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\n */\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\n\nexport async function simulateOrSend(\n params: SimulateOrSendParams\n): Promise {\n const {\n connection,\n ix,\n signers,\n simulate,\n commitment,\n computeUnitLimit,\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\n } = params;\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\n\n if (typeof simulate !== \"boolean\") {\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\n }\n\n if (!signers.length) {\n throw new Error(\"simulateOrSend: at least one signer is required\");\n }\n\n if (computeUnitLimit !== undefined) {\n if (\n typeof computeUnitLimit !== \"number\" ||\n !Number.isInteger(computeUnitLimit) ||\n computeUnitLimit < 1 ||\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\n ) {\n throw new Error(\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\n );\n }\n }\n\n if (heapFrameBytes !== 0) {\n if (\n typeof heapFrameBytes !== \"number\" ||\n !Number.isInteger(heapFrameBytes) ||\n heapFrameBytes % 1024 !== 0 ||\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\n ) {\n throw new Error(\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\n );\n }\n }\n\n const tx = new Transaction();\n\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\n if (heapFrameBytes !== 0) {\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\n }\n\n // Add compute budget instruction if custom limit is specified\n if (computeUnitLimit !== undefined) {\n tx.add(\n ComputeBudgetProgram.setComputeUnitLimit({\n units: computeUnitLimit,\n })\n );\n }\n\n tx.add(ix);\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\n tx.recentBlockhash = latestBlockhash.blockhash;\n tx.feePayer = signers[0].publicKey;\n\n if (simulate) {\n try {\n tx.sign(...signers);\n const result = await connection.simulateTransaction(tx, signers);\n const logs = result.value.logs ?? [];\n let err: string | null = null;\n let hint: string | undefined;\n\n if (result.value.err) {\n const parsed = parseErrorFromLogs(logs);\n if (parsed) {\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\n hint = parsed.hint;\n } else {\n err = JSON.stringify(result.value.err);\n }\n }\n\n return {\n signature: \"(simulated)\",\n slot: result.context.slot,\n err,\n hint,\n logs,\n unitsConsumed: result.value.unitsConsumed ?? undefined,\n };\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n return {\n signature: \"(simulated)\",\n slot: 0,\n err: message,\n logs: [],\n };\n }\n }\n\n // Send\n const options: SendOptions = {\n skipPreflight: false,\n preflightCommitment: effectiveCommitment,\n };\n\n // sendTransaction is its own try/catch: only here is it true that no\n // signature was ever produced, so signature: \"\" is the correct result.\n let signature: string;\n try {\n signature = await connection.sendTransaction(tx, signers, options);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n return {\n signature: \"\",\n slot: 0,\n err: message,\n logs: [],\n };\n }\n\n // Fetch logs at the same finality level used for confirmation.\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\n\n try {\n const confirmation = await connection.confirmTransaction(\n {\n signature,\n blockhash: latestBlockhash.blockhash,\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\n },\n effectiveCommitment\n );\n\n const txInfo = await connection.getTransaction(signature, {\n commitment: txFinality,\n maxSupportedTransactionVersion: 0,\n });\n\n const logs = txInfo?.meta?.logMessages ?? [];\n let err: string | null = null;\n let hint: string | undefined;\n\n if (confirmation.value.err) {\n const parsed = parseErrorFromLogs(logs);\n if (parsed) {\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\n hint = parsed.hint;\n } else {\n err = JSON.stringify(confirmation.value.err);\n }\n }\n\n return {\n signature,\n slot: txInfo?.slot ?? 0,\n err,\n hint,\n logs,\n };\n } catch (e: unknown) {\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\n // only that we didn't observe confirmation in time. Previously this branch discarded\n // the real signature obtained above and returned signature: \"\", which left the caller\n // with no way to check whether it's safe to retry — for a non-idempotent operation\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\n // transaction that had actually already landed. Check the real on-chain status before\n // reporting failure, and always return the real signature so the caller can verify\n // it themselves even if this fallback check also fails.\n const message = e instanceof Error ? e.message : String(e);\n try {\n const status = await connection.getSignatureStatus(signature, {\n searchTransactionHistory: true,\n });\n // Only treat the fallback lookup as authoritative when the observed level\n // actually satisfies the commitment the caller asked for. `status.value`\n // being non-null merely means the cluster has SEEN the transaction — at\n // \"processed\" it can still be dropped or rolled back, and reporting that\n // as a settled success would be the same premature-settlement bug #311 fixed.\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\n const txInfo = await connection.getTransaction(signature, {\n commitment: txFinality,\n maxSupportedTransactionVersion: 0,\n });\n const logs = txInfo?.meta?.logMessages ?? [];\n let err: string | null = null;\n let hint: string | undefined;\n if (status.value.err) {\n const parsed = parseErrorFromLogs(logs);\n if (parsed) {\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\n hint = parsed.hint;\n } else {\n err = JSON.stringify(status.value.err);\n }\n }\n return {\n signature,\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\n // `status.context.slot` is the RPC's head slot at query time — a\n // different, much later number — so it must not be used as the tx slot.\n slot: txInfo?.slot ?? status.value.slot,\n err,\n hint,\n logs,\n };\n }\n if (status.value) {\n // Seen, but weaker than requested. Report it as unresolved rather than\n // settled, while still handing back the signature and the real landing slot.\n const observed = status.value.confirmationStatus ?? \"unknown\";\n return {\n signature,\n slot: status.value.slot,\n err:\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\n `Check signature ${signature} before retrying`,\n logs: [],\n };\n }\n } catch {\n // Status lookup itself failed too — fall through to the ambiguous result below,\n // which still carries the real signature instead of discarding it.\n }\n return {\n signature,\n slot: 0,\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\n logs: [],\n };\n }\n}\n\n/**\n * Format transaction result for output.\n */\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\n if (jsonMode) {\n return JSON.stringify(result, null, 2);\n }\n\n const lines: string[] = [];\n\n if (result.err) {\n lines.push(`Error: ${result.err}`);\n if (result.hint) {\n lines.push(`Hint: ${result.hint}`);\n }\n if (result.unitsConsumed !== undefined) {\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\n }\n if (result.logs.length > 0) {\n lines.push(\"Logs:\");\n result.logs.forEach((log) => lines.push(` ${log}`));\n }\n } else {\n lines.push(`Signature: ${result.signature}`);\n lines.push(`Slot: ${result.slot}`);\n if (result.unitsConsumed !== undefined) {\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\n }\n if (result.signature !== \"(simulated)\") {\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n","/**\n * @module lighthouse\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\n *\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\n * scanning service. It adds assertion instructions to transactions that verify account\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\n * X lamports\").\n *\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\n * logic is correct.\n *\n * **Solution:** The SDK provides utilities to:\n * 1. Detect Lighthouse instructions in a transaction\n * 2. Strip them before sending\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\n * 4. Provide clear, actionable error messages for end users\n *\n * @example\n * ```ts\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\n *\n * // Before sending: strip injected Lighthouse IXs\n * const cleanIxs = stripLighthouseInstructions(instructions);\n *\n * // After error: classify and give user-friendly message\n * if (isLighthouseError(error)) {\n * console.warn(\"Wallet middleware blocked the transaction\");\n * }\n * ```\n */\n\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\n *\n * This is an immutable Anchor program deployed at slot 294,179,293.\n * Wallets like Phantom inject instructions from this program into user\n * transactions to enforce Blowfish security assertions.\n */\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\n);\n\n/** Base58 string form for fast comparison without PublicKey instantiation. */\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\n\n/**\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\n * when an account constraint check fails.\n */\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\n\n/**\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\n * All are in the Anchor error range (0x1770–0x1900+).\n */\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\n 0x1770, // InstructionMissing\n 0x1771, // InstructionFallbackNotFound\n 0x1772, // InstructionDidNotDeserialize\n 0x1773, // InstructionDidNotSerialize\n 0x1780, // IdlInstructionStub\n 0x1790, // ConstraintMut\n 0x1791, // ConstraintHasOne\n 0x1792, // ConstraintSigner\n 0x1793, // ConstraintRaw\n 0x1794, // ConstraintOwner\n 0x1795, // ConstraintRentExempt\n 0x1796, // ConstraintSeeds\n 0x1797, // ConstraintExecutable\n 0x1798, // ConstraintState\n 0x1799, // ConstraintAssociated\n 0x179a, // ConstraintAssociatedInit\n 0x179b, // ConstraintClose\n 0x1900, // ConstraintAddress (the one we hit most often)\n] as const);\n\n// ============================================================================\n// Detection\n// ============================================================================\n\n/**\n * Check if a TransactionInstruction is from the Lighthouse program.\n *\n * @param ix - A Solana transaction instruction.\n * @returns `true` if the instruction's programId is Lighthouse.\n *\n * @example\n * ```ts\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\n * ```\n */\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\n}\n\n/**\n * Check if an error message or error object indicates a Lighthouse assertion failure.\n *\n * Detects:\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\n * - References to the Lighthouse program ID in error text\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\n * failing program is Lighthouse (identified by program ID in logs)\n *\n * @param error - An Error object, error message string, or transaction logs array.\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\n *\n * @example\n * ```ts\n * try {\n * await sendTransaction(tx);\n * } catch (e) {\n * if (isLighthouseError(e)) {\n * // Retry with skipPreflight or notify user about wallet middleware\n * }\n * }\n * ```\n */\nexport function isLighthouseError(error: unknown): boolean {\n const msg = extractErrorMessage(error);\n if (!msg) return false;\n\n // Direct program ID reference\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\n\n // 0x1900 hex error code (case-insensitive)\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\n\n // JSON InstructionError format: {\"Custom\": 6400}\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\n\n return false;\n}\n\n/**\n * Check if transaction logs contain evidence of a Lighthouse failure.\n *\n * More precise than `isLighthouseError` on a string — examines the program\n * invocation chain to confirm the error originates from Lighthouse, not from\n * a Percolator instruction that happens to return a similar code.\n *\n * @param logs - Array of transaction log lines from `getTransaction()`.\n * @returns `true` if logs show a Lighthouse program failure.\n */\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\n if (!Array.isArray(logs)) return false;\n\n let lighthouseDepth = 0;\n\n for (const line of logs) {\n if (typeof line !== \"string\") continue;\n\n // Track Lighthouse program invocation depth\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\n lighthouseDepth++;\n continue;\n }\n\n // Lighthouse program returned success — decrement depth\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\n if (lighthouseDepth > 0) lighthouseDepth--;\n continue;\n }\n\n // Only report failure when the Lighthouse program itself explicitly fails\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\n return true;\n }\n }\n\n return false;\n}\n\n// ============================================================================\n// Stripping / Mitigation\n// ============================================================================\n\n/**\n * Remove all Lighthouse assertion instructions from an instruction array.\n *\n * Call this before building a Transaction to prevent Lighthouse assertion\n * failures. Safe to call even if no Lighthouse instructions are present.\n *\n * @param instructions - Array of transaction instructions.\n * @returns Filtered array with Lighthouse instructions removed.\n *\n * @example\n * ```ts\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\n *\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\n * const clean = stripLighthouseInstructions(instructions);\n * const tx = new Transaction().add(...clean);\n * ```\n */\nexport function stripLighthouseInstructions(\n instructions: TransactionInstruction[],\n percolatorProgramId?: PublicKey,\n): TransactionInstruction[] {\n // When a programId is provided, refuse to strip guards from transactions\n // that don't contain any Percolator instructions — prevents misuse on\n // arbitrary transactions where Lighthouse guards are legitimate protection.\n if (percolatorProgramId) {\n const hasPercolatorIx = instructions.some(\n (ix) => ix.programId.equals(percolatorProgramId),\n );\n if (!hasPercolatorIx) {\n return instructions; // no Percolator instructions — leave guards intact\n }\n }\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\n}\n\n/**\n * Strip Lighthouse instructions from an already-built Transaction.\n *\n * Creates a new Transaction with the same recentBlockhash and feePayer\n * but without any Lighthouse instructions. The returned transaction is\n * unsigned and must be re-signed.\n *\n * @param transaction - A Transaction (signed or unsigned).\n * @returns A new Transaction without Lighthouse instructions, or the same\n * transaction if no Lighthouse instructions were found.\n *\n * @example\n * ```ts\n * const signed = await wallet.signTransaction(tx);\n * if (hasLighthouseInstructions(signed)) {\n * const clean = stripLighthouseFromTransaction(signed);\n * const reSigned = await wallet.signTransaction(clean);\n * await connection.sendRawTransaction(reSigned.serialize());\n * }\n * ```\n */\nexport function stripLighthouseFromTransaction(\n transaction: Transaction,\n percolatorProgramId?: PublicKey,\n): Transaction {\n // When a programId is provided, refuse to strip guards from transactions\n // that don't contain any Percolator instructions.\n if (percolatorProgramId) {\n const hasPercolatorIx = transaction.instructions.some(\n (ix) => ix.programId.equals(percolatorProgramId),\n );\n if (!hasPercolatorIx) return transaction;\n }\n\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\n if (!hasLighthouse) return transaction;\n\n const clean = new Transaction();\n clean.recentBlockhash = transaction.recentBlockhash;\n clean.feePayer = transaction.feePayer;\n\n for (const ix of transaction.instructions) {\n if (!isLighthouseInstruction(ix)) {\n clean.add(ix);\n }\n }\n\n return clean;\n}\n\n/**\n * Count Lighthouse instructions in an instruction array or transaction.\n *\n * @param ixsOrTx - Array of instructions or a Transaction.\n * @returns Number of Lighthouse instructions found.\n */\nexport function countLighthouseInstructions(\n ixsOrTx: TransactionInstruction[] | Transaction,\n): number {\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\n return instructions.filter(isLighthouseInstruction).length;\n}\n\n// ============================================================================\n// User-facing error messages\n// ============================================================================\n\n/**\n * User-friendly error message for Lighthouse assertion failures.\n *\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\n */\nexport const LIGHTHOUSE_USER_MESSAGE =\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\n \"This is a known compatibility issue — the transaction itself is valid. \" +\n \"Try one of these workarounds:\\n\" +\n \"1. Disable transaction simulation in your wallet settings\\n\" +\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\n \"3. The SDK will automatically retry without the guard\";\n\n/**\n * Classify an error and return an appropriate user-facing message.\n *\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\n * Otherwise returns `null` (callers should use their own error display).\n *\n * @param error - An Error, string, or logs array.\n * @returns User-facing message string, or `null` if not a Lighthouse error.\n */\nexport function classifyLighthouseError(error: unknown): string | null {\n if (isLighthouseError(error)) {\n return LIGHTHOUSE_USER_MESSAGE;\n }\n return null;\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction extractErrorMessage(error: unknown): string | null {\n if (!error) return null;\n if (typeof error === \"string\") return error;\n if (error instanceof Error) return error.message;\n if (typeof error === \"object\" && \"message\" in error) {\n return String((error as { message: unknown }).message);\n }\n try {\n return JSON.stringify(error);\n } catch {\n return null;\n }\n}\n","/**\n * Coin-margined perpetual trade math utilities.\n *\n * On-chain PnL formula:\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\n *\n * All prices are in e6 format (1 USD = 1_000_000).\n * All token amounts are in native units (e.g. lamports).\n */\n\n/**\n * Compute mark-to-market PnL for an open position.\n */\nexport function computeMarkPnl(\n positionSize: bigint,\n entryPrice: bigint,\n oraclePrice: bigint,\n): bigint {\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\n const absPos = positionSize < 0n ? -positionSize : positionSize;\n const diff =\n positionSize > 0n\n ? oraclePrice - entryPrice\n : entryPrice - oraclePrice;\n return (diff * absPos) / oraclePrice;\n}\n\n/**\n * Compute liquidation price given entry, capital, position and maintenance margin.\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\n */\nexport function computeLiqPrice(\n entryPrice: bigint,\n capital: bigint,\n positionSize: bigint,\n maintenanceMarginBps: bigint,\n): bigint {\n if (positionSize === 0n || entryPrice === 0n) return 0n;\n const absPos = positionSize < 0n ? -positionSize : positionSize;\n // capitalPerUnit scaled by 1e6 for precision\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\n\n if (positionSize > 0n) {\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\n const liq = entryPrice - adjusted;\n return liq > 0n ? liq : 0n;\n } else {\n // Guard: short positions liquidate when price rises above liq price.\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\n // meaning the position can never be liquidated. Return max u64 to signal this.\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\n return entryPrice + adjusted;\n }\n}\n\n/**\n * Compute estimated liquidation price BEFORE opening a trade.\n * Accounts for trading fees reducing effective capital.\n */\nexport function computePreTradeLiqPrice(\n oracleE6: bigint,\n margin: bigint,\n posSize: bigint,\n maintBps: bigint,\n feeBps: bigint,\n direction: \"long\" | \"short\",\n): bigint {\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\n const absPos = posSize < 0n ? -posSize : posSize;\n const signedPos = direction === \"long\" ? absPos : -absPos;\n // Fee adjusts the effective entry price, not the capital.\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\n let adjustedEntry: bigint;\n if (direction === \"long\") {\n adjustedEntry = oracleE6 + feeAdjust;\n } else {\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\n // feeBps >= 10000, misleading the UI into showing the position is safe.\n const shortEntry = oracleE6 - feeAdjust;\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\n }\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\n}\n\n/**\n * Compute trading fee from notional value and fee rate in bps.\n */\nexport function computeTradingFee(\n notional: bigint,\n tradingFeeBps: bigint,\n): bigint {\n return (notional * tradingFeeBps) / 10000n;\n}\n\n/**\n * Dynamic fee tier configuration.\n */\nexport interface FeeTierConfig {\n /** Base trading fee (Tier 1) in bps */\n baseBps: bigint;\n /** Tier 2 fee in bps (0 = disabled) */\n tier2Bps: bigint;\n /** Tier 3 fee in bps (0 = disabled) */\n tier3Bps: bigint;\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\n tier2Threshold: bigint;\n /** Notional threshold to enter Tier 3 */\n tier3Threshold: bigint;\n}\n\n/**\n * Compute the effective fee rate in bps using the tiered fee schedule.\n *\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\n * - notional < tier2Threshold → baseBps (Tier 1)\n * - notional < tier3Threshold → tier2Bps (Tier 2)\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\n *\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\n */\nexport function computeDynamicFeeBps(\n notional: bigint,\n config: FeeTierConfig,\n): bigint {\n if (config.tier2Threshold === 0n) return config.baseBps;\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\n if (notional >= config.tier2Threshold) return config.tier2Bps;\n return config.baseBps;\n}\n\n/**\n * Compute the dynamic trading fee for a given notional and tier config.\n *\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\n * via micro-trades).\n */\nexport function computeDynamicTradingFee(\n notional: bigint,\n config: FeeTierConfig,\n): bigint {\n const feeBps = computeDynamicFeeBps(notional, config);\n if (notional <= 0n || feeBps <= 0n) return 0n;\n return (notional * feeBps + 9999n) / 10000n;\n}\n\n/**\n * Fee split configuration.\n */\nexport interface FeeSplitConfig {\n /** LP vault share in bps (0–10_000) */\n lpBps: bigint;\n /** Protocol treasury share in bps */\n protocolBps: bigint;\n /** Market creator share in bps */\n creatorBps: bigint;\n}\n\n/**\n * Compute fee split for a total fee amount.\n *\n * Returns [lpShare, protocolShare, creatorShare].\n * If all split params are 0, 100% goes to LP (legacy behavior).\n * Creator gets the rounding remainder to ensure total is preserved.\n */\nexport function computeFeeSplit(\n totalFee: bigint,\n config: FeeSplitConfig,\n): [bigint, bigint, bigint] {\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\n return [totalFee, 0n, 0n];\n }\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\n }\n if (totalBps !== 10000n) {\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\n }\n\n const lp = (totalFee * config.lpBps) / 10000n;\n const protocol = (totalFee * config.protocolBps) / 10000n;\n const creator = totalFee - lp - protocol;\n return [lp, protocol, creator];\n}\n\n/**\n * Compute PnL as a percentage of capital.\n *\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\n * Number(bigint) silently truncates values above 2^53, which can produce\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\n */\nexport function computePnlPercent(\n pnlTokens: bigint,\n capital: bigint,\n): number {\n if (capital === 0n) return 0;\n const scaledPct = (pnlTokens * 10_000n) / capital;\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\n // unhandled exceptions from crashing the UI on large positions.\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\n return Number(scaledPct) / 100;\n}\n\n/**\n * Estimate entry price including fee impact (slippage approximation).\n */\nexport function computeEstimatedEntryPrice(\n oracleE6: bigint,\n tradingFeeBps: bigint,\n direction: \"long\" | \"short\",\n): bigint {\n if (oracleE6 === 0n) return 0n;\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\n if (direction === \"long\") return oracleE6 + feeImpact;\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\n // when fee >= 100%, misleading the UI.\n const shortEntry = oracleE6 - feeImpact;\n return shortEntry > 0n ? shortEntry : 1n;\n}\n\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\n\n/**\n * Convert per-slot funding rate (bps) to annualized percentage.\n */\nexport function computeFundingRateAnnualized(\n fundingRateBpsPerSlot: bigint,\n): number {\n // Clamp rather than throw: extreme funding rates are display-only values;\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\n return (bpsPerSlot * slotsPerYear) / 100;\n}\n\n/**\n * Compute margin required for a given notional and initial margin bps.\n */\nexport function computeRequiredMargin(\n notional: bigint,\n initialMarginBps: bigint,\n): bigint {\n return (notional * initialMarginBps) / 10000n;\n}\n\n/**\n * Compute maximum leverage from initial margin bps, as an exact ratio.\n *\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\n * {@link computeMaxLeverageFloor} instead.\n *\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\n */\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\n if (initialMarginBps <= 0n) {\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\n }\n // Use floating-point division so fractional leverage is preserved.\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\n return 10000 / Number(initialMarginBps);\n}\n\n/**\n * Compute maximum leverage from initial margin bps, floored to a whole\n * multiplier — the conservative integer form used by risk/sizing math.\n *\n * Kept separate from {@link computeMaxLeverage} because that one is a display\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\n * DOWN also keeps client-side caps at or below what the program enforces, so a\n * caller can never build a position the chain would reject on leverage.\n *\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\n */\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\n if (initialMarginBps <= 0n) {\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\n }\n return 10000n / initialMarginBps;\n}\n","/**\n * Warmup leverage cap utilities.\n *\n * During the market warmup period, capital is released linearly over\n * `warmupPeriodSlots` slots, which constrains the effective leverage\n * and maximum position size available to traders.\n */\n\nimport { computeMaxLeverageFloor } from \"./trading.js\";\n\n// =============================================================================\n// Warmup leverage cap utilities\n// =============================================================================\n\n/**\n * Compute unlocked capital during the warmup period.\n *\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\n * warmup period is 0, all capital is considered unlocked.\n *\n * @param totalCapital - Total deposited capital (native units).\n * @param currentSlot - The current on-chain slot.\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\n * @param warmupPeriodSlots - Total slots in the warmup period.\n * @returns The amount of capital currently unlocked.\n */\nexport function computeWarmupUnlockedCapital(\n totalCapital: bigint,\n currentSlot: bigint,\n warmupStartSlot: bigint,\n warmupPeriodSlots: bigint,\n): bigint {\n // No warmup configured or not started → all capital available\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\n if (totalCapital <= 0n) return 0n;\n\n const elapsed = currentSlot > warmupStartSlot\n ? currentSlot - warmupStartSlot\n : 0n;\n\n // Warmup complete\n if (elapsed >= warmupPeriodSlots) return totalCapital;\n\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\n return (totalCapital * elapsed) / warmupPeriodSlots;\n}\n\n/**\n * Compute the effective maximum leverage during the warmup period.\n *\n * During warmup, only unlocked capital can be used as margin. The effective\n * leverage relative to *total* capital is therefore capped at:\n *\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\n *\n * This returns a floored integer value (leverage is always a whole number\n * in the UI), with a minimum of 1x if any capital is unlocked.\n *\n * @param initialMarginBps - Initial margin requirement in basis points.\n * @param totalCapital - Total deposited capital (native units).\n * @param currentSlot - The current on-chain slot.\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\n * @param warmupPeriodSlots - Total slots in the warmup period.\n * @returns The effective maximum leverage (integer, ≥ 1).\n */\nexport function computeWarmupLeverageCap(\n initialMarginBps: bigint,\n totalCapital: bigint,\n currentSlot: bigint,\n warmupStartSlot: bigint,\n warmupPeriodSlots: bigint,\n): number {\n // Integer form: this is risk/sizing math, and the fractional\n // computeMaxLeverage() is a display value that cannot be used in BigInt\n // arithmetic. Flooring also keeps the client cap at or below the program's.\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\n\n // No warmup or warmup not started → full leverage\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\n if (totalCapital <= 0n) return 1;\n\n const unlocked = computeWarmupUnlockedCapital(\n totalCapital,\n currentSlot,\n warmupStartSlot,\n warmupPeriodSlots,\n );\n\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\n\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\n return Math.max(1, effectiveLev);\n}\n\n/**\n * Compute the maximum position size allowed during warmup.\n *\n * This is the unlocked capital multiplied by the base max leverage.\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\n * relative to total capital), this gives the absolute notional cap.\n *\n * @param initialMarginBps - Initial margin requirement in basis points.\n * @param totalCapital - Total deposited capital (native units).\n * @param currentSlot - The current on-chain slot.\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\n * @param warmupPeriodSlots - Total slots in the warmup period.\n * @returns Maximum position size in native units.\n */\nexport function computeWarmupMaxPositionSize(\n initialMarginBps: bigint,\n totalCapital: bigint,\n currentSlot: bigint,\n warmupStartSlot: bigint,\n warmupPeriodSlots: bigint,\n): bigint {\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\n const unlocked = computeWarmupUnlockedCapital(\n totalCapital,\n currentSlot,\n warmupStartSlot,\n warmupPeriodSlots,\n );\n return unlocked * maxLev;\n}\n","/**\n * Input validation utilities for CLI commands.\n * Provides descriptive error messages for invalid input.\n */\n\nimport { PublicKey } from \"@solana/web3.js\";\n\n// Constants for numeric limits\nconst U16_MAX = 65535;\nconst U64_MAX = BigInt(\"18446744073709551615\");\nconst I64_MIN = BigInt(\"-9223372036854775808\");\nconst I64_MAX = BigInt(\"9223372036854775807\");\nconst U128_MAX = (1n << 128n) - 1n;\nconst I128_MIN = -(1n << 127n);\nconst I128_MAX = (1n << 127n) - 1n;\n\nexport class ValidationError extends Error {\n constructor(\n public readonly field: string,\n message: string\n ) {\n super(`Invalid ${field}: ${message}`);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\n */\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\n\n/**\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\n */\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\n\n/**\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\n *\n * @param value - The string to validate.\n * @param field - The field name used in error messages.\n * @returns The trimmed, validated decimal string.\n */\nexport function requireDecimalUIntString(value: string, field: string): string {\n const t = value.trim();\n if (t === \"\") {\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\n }\n if (!DECIMAL_UINT_RE.test(t)) {\n throw new ValidationError(\n field,\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\n );\n }\n return t;\n}\n\n/**\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\n * (hex, scientific notation, underscores, fractions, leading zeros).\n *\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\n *\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\n * @param caller - The calling function name, used in the error message.\n * @returns The parsed BigInt value.\n * @throws {Error} When `val` does not match the strict decimal integer format.\n *\n * @example\n * safeBigInt(\"123\", \"encU64\") // 123n\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\n * safeBigInt(\"0x1\", \"encU64\") // throws\n * safeBigInt(\"1e5\", \"encU128\") // throws\n */\nexport function safeBigInt(val: string, caller: string): bigint {\n const t = val.trim();\n if (!DECIMAL_INT_RE.test(t)) {\n throw new Error(\n `${caller}: \"${val}\" is not a valid decimal integer ` +\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\n );\n }\n return BigInt(t);\n}\n\n/**\n * Validate a public key string.\n */\nexport function validatePublicKey(value: string, field: string): PublicKey {\n try {\n return new PublicKey(value);\n } catch {\n throw new ValidationError(\n field,\n `\"${value}\" is not a valid base58 public key. ` +\n `Example: \"11111111111111111111111111111111\"`\n );\n }\n}\n\n/**\n * Validate a non-negative integer index (u16 range for accounts).\n */\nexport function validateIndex(value: string, field: string): number {\n const t = requireDecimalUIntString(value, field);\n const bi = BigInt(t);\n if (bi > BigInt(U16_MAX)) {\n throw new ValidationError(\n field,\n `must be <= ${U16_MAX} (u16 max), got ${t}`\n );\n }\n return Number(bi);\n}\n\n/**\n * Validate a non-negative amount (u64 range).\n */\nexport function validateAmount(value: string, field: string): bigint {\n const t = requireDecimalUIntString(value, field);\n const num = BigInt(t);\n\n if (num < 0n) {\n throw new ValidationError(field, `must be non-negative, got ${num}`);\n }\n\n if (num > U64_MAX) {\n throw new ValidationError(\n field,\n `must be <= ${U64_MAX} (u64 max), got ${num}`\n );\n }\n\n return num;\n}\n\n/**\n * Validate a u128 value.\n */\nexport function validateU128(value: string, field: string): bigint {\n const t = requireDecimalUIntString(value, field);\n const num = BigInt(t);\n\n if (num < 0n) {\n throw new ValidationError(field, `must be non-negative, got ${num}`);\n }\n\n if (num > U128_MAX) {\n throw new ValidationError(\n field,\n `must be <= ${U128_MAX} (u128 max), got ${num}`\n );\n }\n\n return num;\n}\n\n/**\n * Validate an i64 value.\n */\nexport function validateI64(value: string, field: string): bigint {\n let num: bigint;\n\n try {\n num = safeBigInt(value, field);\n } catch {\n throw new ValidationError(\n field,\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\n );\n }\n\n if (num < I64_MIN) {\n throw new ValidationError(\n field,\n `must be >= ${I64_MIN} (i64 min), got ${num}`\n );\n }\n\n if (num > I64_MAX) {\n throw new ValidationError(\n field,\n `must be <= ${I64_MAX} (i64 max), got ${num}`\n );\n }\n\n return num;\n}\n\n/**\n * Validate an i128 value (trade sizes).\n */\nexport function validateI128(value: string, field: string): bigint {\n let num: bigint;\n\n try {\n num = safeBigInt(value, field);\n } catch {\n throw new ValidationError(\n field,\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\n );\n }\n\n if (num < I128_MIN) {\n throw new ValidationError(\n field,\n `must be >= ${I128_MIN} (i128 min), got ${num}`\n );\n }\n\n if (num > I128_MAX) {\n throw new ValidationError(\n field,\n `must be <= ${I128_MAX} (i128 max), got ${num}`\n );\n }\n\n return num;\n}\n\n/**\n * Validate a basis points value (0-10000).\n */\nexport function validateBps(value: string, field: string): number {\n const t = requireDecimalUIntString(value, field);\n const bi = BigInt(t);\n if (bi > 10000n) {\n throw new ValidationError(\n field,\n `must be <= 10000 (100%), got ${t}`\n );\n }\n return Number(bi);\n}\n\n/**\n * Validate a u64 value.\n */\nexport function validateU64(value: string, field: string): bigint {\n return validateAmount(value, field);\n}\n\n/**\n * Validate a u16 value.\n */\nexport function validateU16(value: string, field: string): number {\n const t = requireDecimalUIntString(value, field);\n const bi = BigInt(t);\n if (bi > BigInt(U16_MAX)) {\n throw new ValidationError(\n field,\n `must be <= ${U16_MAX} (u16 max), got ${t}`\n );\n }\n return Number(bi);\n}\n","/**\n * Smart Price Router — automatic oracle selection for any token.\n *\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\n * ranks them by liquidity/reliability, and returns the best oracle config.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\n\nexport interface PriceSource {\n type: PriceSourceType;\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\n address: string;\n /** DEX id for dex sources */\n dexId?: string;\n /** Pair label e.g. \"SOL / USDC\" */\n pairLabel?: string;\n /** USD liquidity depth — higher is better */\n liquidity: number;\n /** Latest spot price in USD */\n price: number;\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\n confidence: number;\n}\n\nexport interface PriceRouterResult {\n mint: string;\n bestSource: PriceSource | null;\n allSources: PriceSource[];\n /** ISO timestamp of resolution */\n resolvedAt: string;\n}\n\n/** Options for {@link resolvePrice}. */\nexport interface ResolvePriceOptions {\n timeoutMs?: number;\n}\n\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\n\nfunction isRecord(v: unknown): v is Record {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\n const already = signals.find((s) => s.aborted);\n if (already) {\n const c = new AbortController();\n c.abort(already.reason);\n return c.signal;\n }\n const active = signals.filter((s) => !s.aborted);\n if (active.length === 0) {\n const c = new AbortController();\n c.abort();\n return c.signal;\n }\n if (active.length === 1) return active[0];\n const ctrl = new AbortController();\n for (const s of active) {\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\n }\n return ctrl.signal;\n}\n\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\n\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\n if (!isRecord(json)) return [];\n const rawPairs = json.pairs;\n if (!Array.isArray(rawPairs)) return [];\n const sources: PriceSource[] = [];\n\n for (const pair of rawPairs) {\n if (!isRecord(pair)) continue;\n if (pair.chainId !== \"solana\") continue;\n const dexId = String(pair.dexId || \"\").toLowerCase();\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\n\n let liquidity = 0;\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\n liquidity = pair.liquidity.usd;\n }\n if (liquidity < 100) continue;\n\n let confidence = 30;\n if (liquidity > 1_000_000) confidence = 90;\n else if (liquidity > 100_000) confidence = 75;\n else if (liquidity > 10_000) confidence = 60;\n else if (liquidity > 1_000) confidence = 45;\n\n const priceUsd = pair.priceUsd;\n const price =\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\n ? parseFloat(String(priceUsd)) || 0\n : 0;\n\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\n // any source without a usable positive price.\n if (!(price > 0)) continue;\n\n let baseSym = \"?\";\n let quoteSym = \"?\";\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\n baseSym = pair.baseToken.symbol;\n }\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\n quoteSym = pair.quoteToken.symbol;\n }\n\n const addr = pair.pairAddress;\n sources.push({\n type: \"dex\",\n address: typeof addr === \"string\" ? addr : \"\",\n dexId,\n pairLabel: `${baseSym} / ${quoteSym}`,\n liquidity,\n price,\n confidence,\n });\n }\n\n sources.sort((a, b) => b.liquidity - a.liquidity);\n return sources.slice(0, 10);\n}\n\n/**\n * Parse a Jupiter price row.\n *\n * Handles BOTH shapes:\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\n *\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\n * cross-validation in this module was silently inert, including the #227/#315\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\n * mock or a proxy that still speaks v2 keeps working.\n */\nfunction parseJupiterMintEntry(\n json: unknown,\n mint: string,\n): { price: number; mintSymbol: string; liquidity: number } | null {\n if (!isRecord(json)) return null;\n\n // v3: the mint is a top-level key.\n const v3Row = json[mint];\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\n if (price <= 0) return null;\n const liquidity =\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\n ? v3Row.liquidity\n : 0;\n return { price, mintSymbol: \"?\", liquidity };\n }\n\n // v2 (retired): rows live under `data`.\n const data = json.data;\n if (!isRecord(data)) return null;\n const row = data[mint];\n if (!isRecord(row)) return null;\n const rawPrice = row.price;\n if (rawPrice === undefined || rawPrice === null) return null;\n const price = parseFloat(String(rawPrice)) || 0;\n if (price <= 0) return null;\n let mintSymbol = \"?\";\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\n return { price, mintSymbol, liquidity: 0 };\n}\n\n// ---------------------------------------------------------------------------\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\n// ---------------------------------------------------------------------------\n\nexport const PYTH_SOLANA_FEEDS: Record = {\n // SOL\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\n // BTC\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\n // ETH\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\n // USDC\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\n // USDT\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\n // BONK\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\n // JTO\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\n // JUP\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\n // PYTH\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\n // RAY\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\n // ORCA\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\n // MNGO\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\n // MSOL\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\n // JITOSOL\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\n // WIF\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\n // RENDER\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\n // W\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\n // TNSR\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\n // HNT\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\n // MOBILE\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\n // IOT\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\n};\nObject.freeze(PYTH_SOLANA_FEEDS);\n\n// Reverse lookup: mint → feed ID\nconst MINT_TO_PYTH_FEED = new Map();\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\n}\n\n// ---------------------------------------------------------------------------\n// DexScreener fetcher\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\n\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\n}\n\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\n try {\n const resp = await fetch(\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\n {\n signal: effectiveSignal(signal),\n headers: { \"User-Agent\": \"percolator/1.0\" },\n },\n );\n if (!resp.ok) return [];\n const json: unknown = await resp.json();\n return parseDexScreenerPairs(json);\n } catch {\n return [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pyth lookup\n// ---------------------------------------------------------------------------\n\nfunction lookupPythSource(mint: string): PriceSource | null {\n const entry = MINT_TO_PYTH_FEED.get(mint);\n if (!entry) return null;\n return {\n type: \"pyth\",\n address: entry.feedId,\n pairLabel: `${entry.symbol} / USD (Pyth)`,\n liquidity: Infinity, // Pyth is considered deep liquidity\n price: 0, // We don't fetch live price here; caller can enrich\n confidence: 95, // Pyth is highest reliability for supported tokens\n };\n}\n\n// ---------------------------------------------------------------------------\n// Jupiter price fallback\n// ---------------------------------------------------------------------------\n\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\n try {\n const resp = await fetch(\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\n {\n signal: effectiveSignal(signal),\n headers: { \"User-Agent\": \"percolator/1.0\" },\n },\n );\n if (!resp.ok) return null;\n const json: unknown = await resp.json();\n const row = parseJupiterMintEntry(json, mint);\n if (!row) return null;\n return {\n type: \"jupiter\",\n address: mint,\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\n // Used below to decide whether Jupiter is a credible enough reference to\n // demote a disagreeing pool.\n liquidity: row.liquidity,\n price: row.price,\n confidence: 40, // Fallback — lower confidence\n };\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Main resolver\n// ---------------------------------------------------------------------------\n\nexport async function resolvePrice(\n mint: string,\n signal?: AbortSignal,\n options?: ResolvePriceOptions,\n): Promise {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\n const combinedSignal = signal\n ? combineAbortSignals([signal, timeoutSignal])\n : timeoutSignal;\n\n const [dexSources, jupiterSource] = await Promise.all([\n fetchDexSources(mint, combinedSignal),\n fetchJupiterSource(mint, combinedSignal),\n ]);\n\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\n // the common case for permissionless markets — had its top DEX source ranked\n // purely on self-reported liquidity, with no check against an independent price\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\n // source's confidence to Jupiter's when they diverge beyond the same tightened\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\n // independent reference purely on liquidity. The source stays in allSources for\n // transparency; only its ranking weight is reduced.\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\n // ahead and bestSource unchanged.\n const DISTRUST_CONFIDENCE_MARGIN = 1;\n if (jupiterSource && jupiterSource.price > 0) {\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\n // itself — enrichment reads dexSources[0].price, which is untouched; only\n // ranking weight changes, and Pyth's own confidence (95) still outranks\n // everything here.\n //\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\n // Jupiter is an aggregate across venues, so it is normally the better\n // reference — but with v2 retired a malformed/empty response used to yield a\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\n // ranking alone rather than trust it.\n const jupiterIsCredible = jupiterSource.liquidity > 0;\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\n if (jupiterIsCredible) {\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\n // returns up to 10 pools and confidence is a step function of liquidity, so a\n // second pool in the same tier would otherwise keep its score and win\n // bestSource at the divergent price.\n for (const dex of dexSources) {\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\n dex.confidence = Math.min(dex.confidence, distrusted);\n }\n }\n }\n }\n\n const pythSource = lookupPythSource(mint);\n\n const allSources: PriceSource[] = [];\n\n // Add Pyth if available (highest priority for supported tokens)\n if (pythSource) {\n // Enrich Pyth price from Jupiter or DEX if available.\n // Guard: only push a Pyth source when we have at least one live price\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\n // at crank time on devnet/mainnet.\n const dexPrice = dexSources[0]?.price ?? 0;\n const jupPrice = jupiterSource?.price ?? 0;\n // #227: cross-validate the enrichment reference so a single manipulable DEX\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\n //\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\n let enrichedPrice = 0;\n let singleSource = false;\n if (dexPrice > 0 && jupPrice > 0) {\n const mid = (dexPrice + jupPrice) / 2;\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\n enrichedPrice = mid;\n } else {\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\n // DEX and Jupiter are still added below at their own confidence levels.\n console.warn(\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\n );\n }\n } else if (dexPrice > 0 || jupPrice > 0) {\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\n singleSource = true;\n }\n if (enrichedPrice > 0) {\n pythSource.price = enrichedPrice;\n if (singleSource) {\n pythSource.confidence = Math.min(pythSource.confidence, 50);\n }\n allSources.push(pythSource);\n }\n }\n\n // Add DEX sources\n allSources.push(...dexSources);\n\n // Add Jupiter as fallback\n if (jupiterSource) {\n allSources.push(jupiterSource);\n }\n\n // Sort by confidence descending (already accounts for liquidity/reliability)\n allSources.sort((a, b) => b.confidence - a.confidence);\n\n return {\n mint,\n bestSource: allSources[0] || null,\n allSources,\n resolvedAt: new Date().toISOString(),\n };\n}\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;A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","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file +{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst U8_MAX = 0xFF;\r\nconst U16_MAX = 0xFFFF;\r\nconst U32_MAX = 0xFFFFFFFF;\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\r\n if (typeof val === \"bigint\") return val;\r\n if (typeof val !== \"string\") {\r\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\r\n }\r\n if (!DECIMAL_INT_RE.test(val)) {\r\n throw new Error(`${fnName}: value must be a decimal integer string`);\r\n }\r\n return BigInt(val);\r\n}\r\n\r\n/**\r\n * Encode u8 (1 byte)\r\n */\r\nexport function encU8(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\r\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\r\n }\r\n return new Uint8Array([val]);\r\n}\r\n\r\n/**\r\n * Encode u16 little-endian (2 bytes)\r\n */\r\nexport function encU16(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\r\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u32 little-endian (4 bytes)\r\n */\r\nexport function encU32(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\r\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\r\n }\r\n const buf = new Uint8Array(4);\r\n new DataView(buf.buffer).setUint32(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u64 little-endian (8 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU64\");\r\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\r\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i64 little-endian (8 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI64\");\r\n const min = -(1n << 63n);\r\n const max = (1n << 63n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigInt64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u128 little-endian (16 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU128\");\r\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\r\n const max = (1n << 128n) - 1n;\r\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = n & 0xffff_ffff_ffff_ffffn;\r\n const hi = n >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i128 little-endian (16 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI128\");\r\n const min = -(1n << 127n);\r\n const max = (1n << 127n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\r\n\r\n // Convert to unsigned representation (two's complement)\r\n let unsigned = n;\r\n if (n < 0n) {\r\n unsigned = (1n << 128n) + n;\r\n }\r\n\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\r\n const hi = unsigned >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\r\n *\r\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\r\n * objects are validated before their bytes are returned so JavaScript callers\r\n * cannot provide malformed `toBytes()` output.\r\n *\r\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\r\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\r\n */\r\nexport function encPubkey(val: PublicKey | string): Uint8Array {\r\n try {\r\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\r\n\r\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\r\n throw new Error(\"value must be a PublicKey or base58 string\");\r\n }\r\n\r\n const bytes = pk.toBytes();\r\n\r\n if (!(bytes instanceof Uint8Array)) {\r\n throw new Error(\"toBytes() must return a Uint8Array\");\r\n }\r\n\r\n if (bytes.length !== 32) {\r\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\r\n }\r\n\r\n return bytes;\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\r\n }\r\n}\r\n\r\n/**\r\n * Encode a boolean as u8 (0 = false, 1 = true)\r\n */\r\nexport function encBool(val: boolean): Uint8Array {\r\n return encU8(val ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\r\n */\r\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\r\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\r\n const result = new Uint8Array(totalLen);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n encU8,\r\n encU16,\r\n encU32,\r\n encU64,\r\n encI64,\r\n encU128,\r\n encI128,\r\n encPubkey,\r\n concatBytes,\r\n} from \"./encode.js\";\r\n\r\n/**\r\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\r\n * v17 converged wrapper (percolator-prog @v17-convergence, source\r\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\r\n * InvalidInstructionData.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\r\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\r\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\r\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\r\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\r\n * all callers — the program hard-rejects nonzero.\r\n * - Domain fields: u8→u16 everywhere.\r\n */\r\nexport const IX_TAG = {\r\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\r\n InitMarket: 0,\r\n InitPortfolio: 1,\r\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\r\n InitUser: 1,\r\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\r\n InitLP: 2,\r\n Deposit: 3,\r\n /** @alias DepositCollateral @since v12.x alias */\r\n DepositCollateral: 3,\r\n Withdraw: 4,\r\n /** @alias WithdrawCollateral @since v12.x alias */\r\n WithdrawCollateral: 4,\r\n /**\r\n * PermissionlessCrank (tag 5).\r\n *\r\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\r\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\r\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\r\n * construct the payload manually and omit this field — that produces a\r\n * malformed instruction (missing bytes).\r\n */\r\n PermissionlessCrank: 5,\r\n /** @alias KeeperCrank @since v12.x alias */\r\n KeeperCrank: 5,\r\n TradeNoCpi: 6,\r\n LiquidateAtOracle: 7,\r\n ClosePortfolio: 8,\r\n /** @alias CloseAccount @since v12.x alias */\r\n CloseAccount: 8,\r\n TopUpInsurance: 9,\r\n TradeCpi: 10,\r\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\r\n SetRiskThreshold: 11,\r\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\r\n UpdateAdmin: 12,\r\n CloseSlab: 13,\r\n ResolveMarket: 19,\r\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\r\n TopUpBackingBucket: 24,\r\n ConvertReleasedPnl: 28,\r\n CloseResolved: 30,\r\n /**\r\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\r\n *\r\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\r\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\r\n * rotation uses tag 65 (UpdateAssetAuthority).\r\n */\r\n UpdateAuthority: 32,\r\n ConfigureHybridOracle: 34,\r\n ConfigureEwmaMark: 35,\r\n PushEwmaMark: 36,\r\n UpdateLiquidationFeePolicy: 37,\r\n ConfigurePermissionlessResolve: 38,\r\n ResolveStalePermissionless: 39,\r\n UpdateAssetLifecycle: 40,\r\n WithdrawInsurance: 41,\r\n CureAndCancelClose: 42,\r\n ForfeitRecoveryLeg: 43,\r\n RebalanceReduce: 44,\r\n FinalizeResetSide: 45,\r\n ClaimResolvedPayoutTopup: 46,\r\n RefineResolvedUnreceiptedBound: 47,\r\n SyncMaintenanceFee: 48,\r\n UpdateMaintenanceFeePolicy: 49,\r\n WithdrawBackingBucket: 50,\r\n UpdateBackingFeePolicy: 51,\r\n WithdrawBackingBucketEarnings: 52,\r\n SyncBackingDomainLedger: 53,\r\n SyncInsuranceLedger: 54,\r\n UpdateTradeFeePolicy: 55,\r\n TopUpInsuranceDomain: 56,\r\n /**\r\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\r\n *\r\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\r\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\r\n */\r\n WithdrawInsuranceAsset: 57,\r\n UpdateFeeRedirectPolicy: 58,\r\n UpdateMarketInitFeePolicy: 59,\r\n UpdateBaseUnitMints: 60,\r\n SwapSecondaryForPrimary: 61,\r\n ConfigureAuthMark: 62,\r\n PushAuthMark: 63,\r\n ForceCloseAbandonedAsset: 64,\r\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\r\n /**\r\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\r\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\r\n * 1 = INSURANCE — insurance_authority\r\n * 2 = INSURANCE_OPERATOR — insurance_operator\r\n * 3 = BACKING_BUCKET — backing_bucket_authority\r\n * 4 = ORACLE — oracle_authority\r\n *\r\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\r\n * See stake-program docs.\r\n */\r\n UpdateAssetAuthority: 65,\r\n /**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\r\n */\r\n BatchTradeNoCpi: 66,\r\n /**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\r\n */\r\n BatchTradeCpi: 67,\r\n /**\r\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n */\r\n SetMatcherConfig: 68,\r\n /**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\r\n */\r\n RestartAssetOracle: 69,\r\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\r\n /**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n */\r\n TransferPortfolioOwnership: 72,\r\n /**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n */\r\n SetNftProgramId: 73,\r\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\r\n /**\r\n * CreateLpVault (tag 74).\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\r\n */\r\n CreateLpVault: 74,\r\n /**\r\n * DepositToLpVault (tag 75).\r\n * Wire: tag(1) + amount(u128) = 17 bytes.\r\n */\r\n DepositToLpVault: 75,\r\n /**\r\n * RequestRedeemLpShares (tag 76).\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n */\r\n RequestRedeemLpShares: 76,\r\n /**\r\n * ExecuteRedemption (tag 77).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n ExecuteRedemption: 77,\r\n /**\r\n * LpVaultCrankFees (tag 78).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n LpVaultCrankFees: 78,\r\n /**\r\n * SetLpVaultPaused (tag 79).\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n */\r\n SetLpVaultPaused: 79,\r\n /**\r\n * CloseLpVault (tag 80).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n CloseLpVault: 80,\r\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\r\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\r\n LpVaultDeposit: 75,\r\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\r\n LpVaultWithdraw: 76,\r\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\r\n /** @deprecated v12.x tag 14. Removed in v17. */\r\n UpdateConfig: 14,\r\n /** @deprecated v12.x tag 15. Removed in v17. */\r\n SetMaintenanceFee: 15,\r\n /** @deprecated v12.x tag 16. Removed in v17. */\r\n SetOraclePriceCap: 16,\r\n /** @deprecated v12.x tag 17. Removed in v17. */\r\n AdminForceClose: 17,\r\n /** @deprecated v12.x tag 18. Removed in v17. */\r\n UpdateRiskParams: 18,\r\n /** @deprecated v12.x tag 20. Removed in v17. */\r\n SetPythOracle: 20,\r\n /** @deprecated v12.x tag 21. Removed in v17. */\r\n RenounceAdmin: 21,\r\n /** @deprecated v12.x tag 22. Removed in v17. */\r\n SetInsuranceWithdrawPolicy: 22,\r\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\r\n WithdrawInsuranceLimited: 23,\r\n /** @deprecated v12.x tag 25. Removed in v17. */\r\n FundMarketInsurance: 25,\r\n /** @deprecated v12.x tag 26. Removed in v17. */\r\n SetInsuranceIsolation: 26,\r\n /** @deprecated v12.x tag 27. Removed in v17. */\r\n DepositFeeCredits: 27,\r\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\r\n ResolvePermissionless: 29,\r\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\r\n ForceCloseResolved: 30,\r\n /** @deprecated v12.x tag 33. Removed in v17. */\r\n UpdateInsurancePolicy: 33,\r\n /** @deprecated v12.x tag 36. Removed in v12.17. */\r\n UnresolveMarket: 36,\r\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\r\n ChallengeSettlement: 43,\r\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\r\n ResolveDispute: 44,\r\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\r\n DepositLpCollateral: 45,\r\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\r\n WithdrawLpCollateral: 46,\r\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\r\n SetOffsetPair: 54,\r\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\r\n AttestCrossMargin: 55,\r\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\r\n PauseMarket: 56,\r\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\r\n UnpauseMarket: 58,\r\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\r\n MintPositionNft: 64,\r\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\r\n TransferPositionOwnership: 65,\r\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\r\n BurnPositionNft: 66,\r\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\r\n SetPendingSettlement: 67,\r\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\r\n ClearPendingSettlement: 68,\r\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\r\n TransferOwnershipCpi: 69,\r\n /** @deprecated v12.x tag 70. Not in v17. */\r\n SetWalletCap: 70,\r\n /** @deprecated v12.x tag 71. Not in v17. */\r\n SetOiImbalanceHardBlock: 71,\r\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\r\n RescueOrphanVault: 72,\r\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\r\n CloseOrphanSlab: 73,\r\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\r\n SetDexPool: 74,\r\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\r\n InitMatcherCtxV12: 75,\r\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\r\n SetMaxPnlCap: 78,\r\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\r\n SetOiCapMultiplier: 79,\r\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\r\n SetDisputeParams: 80,\r\n /** @deprecated v12.x tag 81. Not in v17. */\r\n SetLpCollateralParams: 81,\r\n /** @deprecated v12.x tag 82. Not in v17. */\r\n AcceptAdmin: 82,\r\n /**\r\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\r\n *\r\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\r\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\r\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\r\n * skew_spread_mult_bps(u16) = 70 bytes total.\r\n *\r\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\r\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\r\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\r\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\r\n *\r\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\r\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\r\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\r\n * free tag 83 for this instruction rather than the reverse.\r\n */\r\n InitMatcherCtx: 83,\r\n /**\r\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\r\n *\r\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\r\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\r\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\r\n *\r\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\r\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\r\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\r\n */\r\n WithdrawProtocolFee: 84,\r\n /**\r\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\r\n * cfg.protocol_fee_authority.\r\n *\r\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\r\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\r\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\r\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\r\n *\r\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\r\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\r\n */\r\n SetProtocolFeeAuthority: 85,\r\n /**\r\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\r\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\r\n *\r\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\r\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\r\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\r\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\r\n * FeeSplitFloorViolation.\r\n *\r\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\r\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\r\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\r\n * `encodeStakeAdminUpdateFeeSplit`.\r\n */\r\n UpdateFeeSplit: 86,\r\n /**\r\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\r\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\r\n * vault and into the bound stake pool's vault, where percolator-stake's\r\n * AccrueFees measures it as surplus and distributes it to stakers.\r\n *\r\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\r\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\r\n *\r\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\r\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\r\n * id. The only thing a caller decides is *when* the push happens.\r\n *\r\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\r\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\r\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\r\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\r\n * ResolveMarket, not after.\r\n */\r\n WithdrawInsuranceReserveToStake: 87,\r\n /**\r\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\r\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\r\n * argument with no setter anywhere in the dispatch table and was therefore\r\n * frozen for the life of the market.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\r\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\r\n * (v16_program.rs tag-88 arm), matching both the storage type\r\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\r\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\r\n * rejects the whole instruction with InvalidInstructionData.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\r\n */\r\n UpdateMaintenanceFeePerSlot: 88,\r\n /**\r\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\r\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\r\n * bucket to `Expired`/`Impaired` so settlement against that domain can\r\n * proceed again.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\r\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\r\n *\r\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\r\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\r\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\r\n * horizon defers the lapse, it does not avoid it. See\r\n * {@link encodeExpireBackingBucket} for the full keeper contract.\r\n */\r\n ExpireBackingBucket: 89,\r\n /**\r\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\r\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\r\n * Pays the market creator's accrued trade-fee share out of the vault and\r\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\r\n * EXACTLY `amount`.\r\n *\r\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\r\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\r\n * tag 84).\r\n *\r\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\r\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\r\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\r\n * config and pass that to drain it.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\r\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\r\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\r\n * alone, so this deliberate divergence is what lets the creator still claim\r\n * after staking (and stops the pool PDA claiming creator revenue).\r\n *\r\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\r\n * saturated — there is no partial fill. Nothing is debited on failure.\r\n */\r\n WithdrawCreatorFee: 90,\r\n /**\r\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\r\n * between the two domains of the LP vault's asset, carrying ledger principal\r\n * in lockstep. No tokens move: `header.vault` is untouched.\r\n *\r\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\r\n * gains from the OPPOSITE domain, so without this the pot the house actually\r\n * needs can never be refilled (spec.md L410 requires refill be source-domain\r\n * local).\r\n */\r\n RebalanceLpVaultBacking: 91,\r\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\r\n ReclaimEmptyAccount: 85,\r\n /** @deprecated v12.x tag 86. Not in v17. */\r\n SettleAccount: 86,\r\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\r\n UpdateMarkPrice: 90,\r\n /** @deprecated v12.x tag 91. Not in v17. */\r\n AuditCrank: 91,\r\n /** @deprecated v12.x tag 92. Not in v17. */\r\n AdvanceOraclePhase: 92,\r\n /** @deprecated v12.x tag 93. Not in v17. */\r\n SlashCreationDeposit: 93,\r\n /** @deprecated v12.x tag 94. Not in v17. */\r\n InitSharedVault: 94,\r\n /** @deprecated v12.x tag 95. Not in v17. */\r\n AllocateMarket: 95,\r\n /** @deprecated v12.x tag 96. Not in v17. */\r\n QueueWithdrawalSV: 96,\r\n /** @deprecated v12.x tag 97. Not in v17. */\r\n ClaimEpochWithdrawal: 97,\r\n /** @deprecated v12.x tag 98. Not in v17. */\r\n AdvanceEpoch: 98,\r\n /** @deprecated v12.x tag 99. Not in v17. */\r\n ReclaimSlabRent: 99,\r\n /** @deprecated v12.x tag 100. Not in v17. */\r\n CloseStaleSlabs: 100,\r\n /** @deprecated v12.x tag 101. Not in v17. */\r\n ExecuteAdl: 101,\r\n /** @deprecated v12.x tag 102. Not in v17. */\r\n QueueWithdrawal: 102,\r\n /** @deprecated v12.x tag 103. Not in v17. */\r\n ClaimQueuedWithdrawal: 103,\r\n /** @deprecated v12.x tag 104. Not in v17. */\r\n CancelQueuedWithdrawal: 104,\r\n /** @deprecated v12.x tag 105. Not in v17. */\r\n TradeCpiV: 105,\r\n} as const;\r\nObject.freeze(IX_TAG);\r\n\r\n/**\r\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\r\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\r\n *\r\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\r\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\r\n */\r\nexport const EXPECTED_SLAB_VERSION = 16;\r\n\r\n/**\r\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\r\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\r\n throw new Error(\r\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\r\n );\r\n}\r\n\r\n/**\r\n * InitMarket instruction data — v17 wire format.\r\n *\r\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\r\n *\r\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\r\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\r\n * provided as account metas or configured separately via ConfigureHybridOracle /\r\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\r\n *\r\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\r\n * is completely rejected by the v17 program — the first field read is now\r\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\r\n * a u16 portfolio count, producing invalid config or rejection at every call.\r\n *\r\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\r\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\r\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\r\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\r\n */\r\n/**\r\n * Optional 66-byte extended tail for InitMarket (S-4).\r\n *\r\n * When present and any field is non-zero the encoder appends a 66-byte block\r\n * in the exact order that the program reads it (percolator.rs:1516-1545):\r\n * insurance_withdraw_max_bps u16 (2 bytes)\r\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\r\n * permissionless_resolve_stale_slots u64 (8 bytes)\r\n * funding_horizon_slots u64 (8 bytes)\r\n * funding_k_bps u64 (8 bytes)\r\n * funding_max_premium_bps i64 (8 bytes)\r\n * funding_max_bps_per_slot i64 (8 bytes)\r\n * mark_min_fee u64 (8 bytes)\r\n * force_close_delay_slots u64 (8 bytes)\r\n * total = 2 + 8*8 = 66 bytes\r\n *\r\n * When absent (or all fields are zero) the encoder omits the tail and the\r\n * program treats all extended fields as their default zero values. This\r\n * preserves full backward compatibility with existing 344-byte payloads.\r\n */\r\nexport interface InitMarketExtendedTail {\r\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\r\n insuranceWithdrawMaxBps: number;\r\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\r\n insuranceWithdrawCooldownSlots: bigint | string;\r\n /** Slots after which an unresolved market may be permissionlessly resolved. */\r\n permissionlessResolveStaleSlots: bigint | string;\r\n /** Funding rate horizon in slots (custom_funding_k denominator). */\r\n fundingHorizonSlots: bigint | string;\r\n /** Funding rate K parameter in bps (0 = disabled). */\r\n fundingKBps: bigint | string;\r\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\r\n fundingMaxPremiumBps: bigint | string;\r\n /** Maximum funding rate change per slot in bps (i64). */\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\r\n markMinFee: bigint | string;\r\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\r\n forceCloseDelaySlots: bigint | string;\r\n /**\r\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\r\n *\r\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\r\n * the wrapper applies its deployment default\r\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\r\n * emits a 74-byte v2 tail with this value appended after\r\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\r\n * `InvalidConfigParam`; the engine then re-validates the solvency\r\n * envelope at `init_in_place`.\r\n *\r\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\r\n */\r\n maxPriceMoveBpsPerSlot?: bigint | string;\r\n}\r\n\r\nexport interface InitMarketArgs {\r\n admin: PublicKey | string;\r\n collateralMint: PublicKey | string;\r\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\r\n maxStalenessSecs: bigint | string;\r\n confFilterBps: number;\r\n invert: number;\r\n unitScale: number;\r\n initialMarkPriceE6: bigint | string;\r\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\r\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n maxInsuranceFloor?: bigint | string;\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n minOraclePriceCap?: bigint | string;\r\n // RiskParams block (16 fields, read by read_risk_params on-chain)\r\n /**\r\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\r\n * when hMin/hMax are not provided.\r\n */\r\n warmupPeriodSlots?: bigint | string;\r\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMin?: bigint | string;\r\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMax?: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n initialMarginBps: bigint | string;\r\n tradingFeeBps: bigint | string;\r\n maxAccounts: bigint | string;\r\n newAccountFee: bigint | string;\r\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\r\n maintenanceFeePerSlot: bigint | string;\r\n maxCrankStalenessSlots: bigint | string;\r\n liquidationFeeBps: bigint | string;\r\n liquidationFeeCap: bigint | string;\r\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\r\n minLiquidationAbs: bigint | string;\r\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\r\n minInitialDeposit?: bigint | string;\r\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\r\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\r\n /**\r\n * Optional 66-byte extended tail (S-4).\r\n * When present and any field is non-zero, appended after the 344-byte base payload.\r\n * When absent (or all zeros), the base 344-byte payload is sent and the program\r\n * uses default zero values for all extended fields.\r\n * @see InitMarketExtendedTail\r\n */\r\n extendedTail?: InitMarketExtendedTail;\r\n}\r\n\r\n/**\r\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\r\n *\r\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\r\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\r\n * Retained as a utility for off-chain feed ID validation.\r\n */\r\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function encodeFeedId(feedId: string): Uint8Array {\r\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\r\n if (!HEX_RE.test(hex)) {\r\n throw new Error(\r\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\r\n );\r\n }\r\n const bytes = new Uint8Array(32);\r\n for (let i = 0; i < 64; i += 2) {\r\n const byte = parseInt(hex.substring(i, i + 2), 16);\r\n if (Number.isNaN(byte)) {\r\n throw new Error(\r\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\r\n );\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\r\n * (10_000_000_000_000_000 — effectively unlimited).\r\n *\r\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\r\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\r\n * engine returns `RecoveryRequired` and refuses further liquidation until\r\n * the insurance fund covers the residual. Production markets MUST use this\r\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\r\n * limit is intended AND the insurance fund is sized accordingly.\r\n *\r\n * @example\r\n * ```ts\r\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\r\n * const data = encodeInitMarket({\r\n * ...otherParams,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\r\n\r\n// v17 wire layout (v16_program.rs decode arm at tag 0):\r\n// tag(1) +\r\n// max_portfolio_assets(u16=2) +\r\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\r\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\r\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\r\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\r\n// liquidation_fee_bps(u64=8) +\r\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\r\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\r\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\r\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\r\n// max_bankrupt_close_lifetime_slots(u64=8) +\r\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\r\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\r\nconst INIT_MARKET_V17_LEN = 219;\r\n\r\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\r\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\r\n// with no optional tail — all parameters are required fields in the main body.\r\n\r\n/**\r\n * InitMarket v17 argument interface.\r\n *\r\n * admin and collateralMint are passed as account metas (accounts[0] and\r\n * accounts[2] respectively), NOT in instruction data.\r\n *\r\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\r\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\r\n * after the market is created.\r\n *\r\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\r\n * max_portfolio_assets, h_min, h_max, initial_price,\r\n * min_nonzero_mm_req, min_nonzero_im_req,\r\n * maintenance_margin_bps, initial_margin_bps,\r\n * max_trading_fee_bps, trade_fee_base_bps,\r\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\r\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\r\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\r\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\r\n * max_bankrupt_close_lifetime_slots,\r\n * public_b_chunk_atoms, maintenance_fee_per_slot.\r\n */\r\nexport interface InitMarketV17Args {\r\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\r\n maxPortfolioAssets: number;\r\n /** Minimum funding horizon in slots (u64). */\r\n hMin: bigint | string;\r\n /** Maximum funding horizon in slots (u64). */\r\n hMax: bigint | string;\r\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\r\n initialPrice: bigint | string;\r\n /** Minimum non-zero maintenance margin requirement (u128). */\r\n minNonzeroMmReq: bigint | string;\r\n /** Minimum non-zero initial margin requirement (u128). */\r\n minNonzeroImReq: bigint | string;\r\n /** Maintenance margin ratio in bps (u64). */\r\n maintenanceMarginBps: bigint | string;\r\n /** Initial margin ratio in bps (u64). */\r\n initialMarginBps: bigint | string;\r\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\r\n maxTradingFeeBps: bigint | string;\r\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\r\n tradeFeeBaseBps: bigint | string;\r\n /** Liquidation fee in bps (u64). */\r\n liquidationFeeBps: bigint | string;\r\n /** Liquidation fee cap in absolute units (u128). */\r\n liquidationFeeCap: bigint | string;\r\n /** Minimum liquidation size in absolute units (u128). */\r\n minLiquidationAbs: bigint | string;\r\n /** Maximum price movement per slot in bps (u64). */\r\n maxPriceMoveBpsPerSlot: bigint | string;\r\n /** Maximum accrual delta-time in slots (u64). */\r\n maxAccrualDtSlots: bigint | string;\r\n /** Maximum absolute funding rate in e9 per slot (u64). */\r\n maxAbsFundingE9PerSlot: bigint | string;\r\n /** Minimum funding lifetime in slots (u64). */\r\n minFundingLifetimeSlots: bigint | string;\r\n /** Maximum account-B settlement chunks per crank (u64). */\r\n maxAccountBSettlementChunks: bigint | string;\r\n /** Maximum bankrupt-close chunks per crank (u64). */\r\n maxBankruptCloseChunks: bigint | string;\r\n /** Maximum bankrupt-close lifetime in slots (u64). */\r\n maxBankruptCloseLifetimeSlots: bigint | string;\r\n /**\r\n * Public-B chunk size in atoms (u128).\r\n *\r\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\r\n * the engine returns `RecoveryRequired` when the bankrupt position's\r\n * liability exceeds this limit and insurance is insufficient to cover it.\r\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\r\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\r\n * and a funded insurance pool.\r\n */\r\n publicBChunkAtoms: bigint | string;\r\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\n/**\r\n * Encode InitMarket instruction data (v17 wire format).\r\n *\r\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\r\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\r\n *\r\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\r\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\r\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\r\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\r\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\r\n *\r\n * @param args v17 market parameters (InitMarketV17Args)\r\n * @returns 227-byte Uint8Array\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMarket({\r\n * maxPortfolioAssets: 256,\r\n * hMin: 1000n,\r\n * hMax: 100000n,\r\n * initialPrice: 50_000_000_000n,\r\n * minNonzeroMmReq: 1_000_000n,\r\n * minNonzeroImReq: 2_000_000n,\r\n * maintenanceMarginBps: 500n,\r\n * initialMarginBps: 1000n,\r\n * maxTradingFeeBps: 100n,\r\n * tradeFeeBaseBps: 30n,\r\n * liquidationFeeBps: 100n,\r\n * liquidationFeeCap: 10_000_000n,\r\n * minLiquidationAbs: 1_000_000n,\r\n * maxPriceMoveBpsPerSlot: 4n,\r\n * maxAccrualDtSlots: 600n,\r\n * maxAbsFundingE9PerSlot: 1000n,\r\n * minFundingLifetimeSlots: 50n,\r\n * maxAccountBSettlementChunks: 10n,\r\n * maxBankruptCloseChunks: 10n,\r\n * maxBankruptCloseLifetimeSlots: 500n,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\r\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\r\n const isV17Args = 'maxPortfolioAssets' in args;\r\n\r\n let maxPortfolioAssets: number;\r\n let hMin: bigint | string;\r\n let hMax: bigint | string;\r\n let initialPrice: bigint | string;\r\n let minNonzeroMmReq: bigint | string;\r\n let minNonzeroImReq: bigint | string;\r\n let maintenanceMarginBps: bigint | string;\r\n let initialMarginBps: bigint | string;\r\n let maxTradingFeeBps: bigint | string;\r\n let tradeFeeBaseBps: bigint | string;\r\n let liquidationFeeBps: bigint | string;\r\n let liquidationFeeCap: bigint | string;\r\n let minLiquidationAbs: bigint | string;\r\n let maxPriceMoveBpsPerSlot: bigint | string;\r\n let maxAccrualDtSlots: bigint | string;\r\n let maxAbsFundingE9PerSlot: bigint | string;\r\n let minFundingLifetimeSlots: bigint | string;\r\n let maxAccountBSettlementChunks: bigint | string;\r\n let maxBankruptCloseChunks: bigint | string;\r\n let maxBankruptCloseLifetimeSlots: bigint | string;\r\n let publicBChunkAtoms: bigint | string;\r\n let maintenanceFeePerSlot: bigint | string;\r\n\r\n if (isV17Args) {\r\n const v = args as InitMarketV17Args;\r\n maxPortfolioAssets = v.maxPortfolioAssets;\r\n hMin = v.hMin;\r\n hMax = v.hMax;\r\n initialPrice = v.initialPrice;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n maxTradingFeeBps = v.maxTradingFeeBps;\r\n tradeFeeBaseBps = v.tradeFeeBaseBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\r\n maxAccrualDtSlots = v.maxAccrualDtSlots;\r\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\r\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\r\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\r\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\r\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\r\n publicBChunkAtoms = v.publicBChunkAtoms;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n } else {\r\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\r\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\r\n // invert, unitScale, extendedTail) are silently ignored.\r\n const v = args as InitMarketArgs;\r\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\r\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\r\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\r\n hMin = resolvedHMin;\r\n hMax = resolvedHMax;\r\n initialPrice = v.initialMarkPriceE6;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\r\n maxTradingFeeBps = v.tradingFeeBps;\r\n tradeFeeBaseBps = v.tradingFeeBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\r\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\r\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\r\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\r\n minFundingLifetimeSlots = 0n;\r\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\r\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\r\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\r\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\r\n // them to functional values instead so v12-initialized markets stay recoverable; callers\r\n // wanting explicit control should migrate to InitMarketV17Args.\r\n maxAccountBSettlementChunks = 10n;\r\n maxBankruptCloseChunks = 10n;\r\n maxBankruptCloseLifetimeSlots = 500n;\r\n publicBChunkAtoms = 1_000_000n;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n }\r\n\r\n const data = concatBytes(\r\n encU8(IX_TAG.InitMarket),\r\n encU16(maxPortfolioAssets),\r\n encU64(hMin),\r\n encU64(hMax),\r\n encU64(initialPrice),\r\n encU128(minNonzeroMmReq),\r\n encU128(minNonzeroImReq),\r\n encU64(maintenanceMarginBps),\r\n encU64(initialMarginBps),\r\n encU64(maxTradingFeeBps),\r\n encU64(tradeFeeBaseBps),\r\n encU64(liquidationFeeBps),\r\n encU128(liquidationFeeCap),\r\n encU128(minLiquidationAbs),\r\n encU64(maxPriceMoveBpsPerSlot),\r\n encU64(maxAccrualDtSlots),\r\n encU64(maxAbsFundingE9PerSlot),\r\n encU64(minFundingLifetimeSlots),\r\n encU64(maxAccountBSettlementChunks),\r\n encU64(maxBankruptCloseChunks),\r\n encU64(maxBankruptCloseLifetimeSlots),\r\n encU128(publicBChunkAtoms),\r\n encU128(maintenanceFeePerSlot),\r\n );\r\n\r\n if (data.length !== INIT_MARKET_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n return data;\r\n}\r\n\r\n/**\r\n * InitPortfolio / InitUser instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\r\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\r\n * Sending extra bytes causes garbage reads in downstream decoder arms.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitUser();\r\n * ```\r\n */\r\nexport interface InitUserArgs {\r\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\r\n feePayment?: bigint | string;\r\n}\r\n\r\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.InitPortfolio]);\r\n}\r\n\r\n/**\r\n * InitLP (tag 2) — REMOVED in v17.\r\n *\r\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\r\n */\r\nexport interface InitLPArgs {\r\n matcherProgram: PublicKey | string;\r\n matcherContext: PublicKey | string;\r\n feePayment: bigint | string;\r\n}\r\n\r\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\r\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\r\n}\r\n\r\n/**\r\n * DepositCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\r\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\r\n *\r\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface DepositCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\r\n *\r\n * @param amount Collateral to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\r\n * ```\r\n */\r\nexport interface WithdrawCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) action byte values.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\r\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\r\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\r\n */\r\nexport const CrankAction = {\r\n FeeSweep: 0,\r\n Liquidate: 1,\r\n} as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) instruction args.\r\n *\r\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\r\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\r\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\r\n * and the fee rate is always read from config inside\r\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\r\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\r\n * while still making forward progress. Any client still encoding the old\r\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\r\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\r\n * side, not a runtime check.\r\n *\r\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\r\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\r\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\r\n * `read_u64`/`read_i128`/`push_*` call sequence.\r\n *\r\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\r\n * The program hard-rejects any nonzero value with InvalidInstructionData.\r\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\r\n * produces a truncated instruction (missing 16 bytes).\r\n *\r\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\r\n * @param assetIndex Asset/domain index to operate on.\r\n * @param nowSlot Current slot (for crank freshness check).\r\n * @param recoveryReason Recovery reason byte (0 for normal operations).\r\n *\r\n * @example\r\n * ```ts\r\n * // Simple fee-sweep crank\r\n * const data = encodePermissionlessCrank({\r\n * action: CrankAction.FeeSweep,\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * recoveryReason: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface PermissionlessCrankArgs {\r\n action: number;\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n recoveryReason: number;\r\n}\r\n\r\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.PermissionlessCrank),\r\n encU8(args.action),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\r\n encU8(args.recoveryReason),\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\r\n * Use encodePermissionlessCrank() instead.\r\n *\r\n * Retained for source-compat only. Will throw to prevent silent misuse.\r\n */\r\nexport interface KeeperCrankArgs {\r\n callerIdx: number;\r\n candidates?: unknown[];\r\n}\r\n\r\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\r\n throw new Error(\r\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\r\n \"Use encodePermissionlessCrank() instead.\"\r\n );\r\n}\r\n\r\n/**\r\n * TradeNoCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\r\n * v17 has asset_index+size_q+exec_price+fee_bps.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\r\n * @param execPrice Execution price in e6 units.\r\n * @param feeBps Fee in basis points.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeNoCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * execPrice: 50_000_000_000n,\r\n * feeBps: 30n,\r\n * });\r\n * ```\r\n */\r\nexport interface TradeNoCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeNoCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.execPrice),\r\n encU64(args.feeBps),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\r\n *\r\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\r\n */\r\nexport interface LiquidateAtOracleArgs {\r\n targetIdx: number;\r\n}\r\n\r\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LiquidateAtOracle\",\r\n IX_TAG.LiquidateAtOracle,\r\n \"PermissionlessCrank (tag 5)\",\r\n );\r\n}\r\n\r\n/**\r\n * ClosePortfolio / CloseAccount instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\r\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\r\n * bytes from the old userIdx field cause InvalidInstructionData.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseAccount();\r\n * ```\r\n */\r\nexport interface CloseAccountArgs {\r\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\r\n userIdx?: number;\r\n}\r\n\r\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.ClosePortfolio]);\r\n}\r\n\r\n/**\r\n * TopUpInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\r\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\r\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\r\n *\r\n * @param amount Amount to top up the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\r\n * ```\r\n */\r\nexport interface TopUpInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * TopUpBackingBucket instruction data (tag 24).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\r\n * = 27 bytes.\r\n *\r\n * Deposits `amount` quote atoms of external collateral into a source domain's\r\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\r\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\r\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\r\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\r\n *\r\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\r\n * SHORT domain is `2*i + 1`.\r\n *\r\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\r\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\r\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\r\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\r\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\r\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\r\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\r\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\r\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\r\n * every later automatic loss-reserve requests the SAME existing expiry and\r\n * hits the harmless no-op arm instead of the LockActive trap.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\r\n * nonzero \"dust\" amount is sufficient — there is no\r\n * minimum floor enforced by the engine.\r\n * @param expirySlot Requested fresh-expiry slot (u64). Use\r\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\r\n *\r\n * @example\r\n * ```ts\r\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\r\n * const data = encodeTopUpBackingBucket({\r\n * domain: 0,\r\n * amount: 10_000n, // 0.01 Sim-USDC dust\r\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\r\n * });\r\n * ```\r\n */\r\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\r\n\r\nexport interface TopUpBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n expirySlot: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TopUpBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n encU64(args.expirySlot),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucket instruction data (tag 50).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\r\n * back to the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\r\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\r\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\r\n *\r\n * Together with TopUpBackingBucket (24, deposit) and\r\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\r\n * LP-provider backing-bucket loop.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateBackingFeePolicy instruction data (tag 51).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * THE switch that turns on LP-vault yield for a domain: sets the\r\n * backing-trade fee charged on that domain's fills, of which\r\n * `insurance_share_bps` is diverted to the insurance budget and the\r\n * remainder accrues to the domain's backing-bucket providers as\r\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\r\n * currently has this at 0 — which is why LP APY is 0%.\r\n *\r\n * Gated by the asset's `insurance_authority` (v16_program.rs\r\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\r\n * the market creator can call it even after the launch flow rotates\r\n * marketauth to the stake-pool PDA. Market must be Live.\r\n *\r\n * Handler-side validation (reverts InvalidInstruction otherwise):\r\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\r\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\r\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\r\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\r\n * of the fee (the rest goes to backing providers).\r\n */\r\nexport interface UpdateBackingFeePolicyArgs {\r\n domain: number;\r\n feeBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateBackingFeePolicy),\r\n encU16(args.domain),\r\n encU16(args.feeBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings instruction data (tag 52).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\r\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\r\n * the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket_earnings` → same\r\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\r\n * per-domain ledger account is REQUIRED (account [2]).\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketEarningsArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucketEarnings(\r\n args: WithdrawBackingBucketEarningsArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * TradeCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\r\n * v17 has asset_index+size_q+fee_bps+limit_price.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed).\r\n * @param feeBps Fee in basis points.\r\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\r\n * Buys: reject if exec_price > limit_price.\r\n * Sells: reject if exec_price < limit_price.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * feeBps: 30n,\r\n * limitPrice: 51_000_000_000n, // max price for a buy\r\n * });\r\n * ```\r\n */\r\nexport interface TradeCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n /** Limit price in e6 units. 0 = no limit. */\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.feeBps),\r\n encU64(args.limitPrice),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\r\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\r\n */\r\nexport interface TradeCpiV2Args {\r\n lpIdx: number;\r\n userIdx: number;\r\n size: bigint | string;\r\n bump: number;\r\n}\r\n\r\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\r\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\r\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\r\n */\r\nexport interface UnresolveMarketArgs {\r\n confirmation: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\r\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\r\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetRiskThresholdArgs {\r\n newThreshold: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\r\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * UpdateAdmin (tag 12) — REMOVED in v17.\r\n *\r\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\r\n */\r\nexport interface UpdateAdminArgs {\r\n newAdmin: PublicKey | string;\r\n}\r\n\r\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\r\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateAdmin\",\r\n IX_TAG.UpdateAdmin,\r\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\r\n );\r\n}\r\n\r\n/**\r\n * CloseSlab instruction data (1 byte)\r\n */\r\nexport function encodeCloseSlab(): Uint8Array {\r\n return encU8(IX_TAG.CloseSlab);\r\n}\r\n\r\n/**\r\n * UpdateConfig instruction data.\r\n *\r\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\r\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\r\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\r\n * src/percolator.rs:2027-2041 (handle_update_config decode).\r\n */\r\nexport interface UpdateConfigArgs {\r\n fundingHorizonSlots: bigint | string;\r\n fundingKBps: bigint | string;\r\n fundingMaxPremiumBps: bigint | string;\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /**\r\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\r\n * Wrapper field added at src/percolator.rs:2031.\r\n */\r\n tvlInsuranceCapMult?: number;\r\n}\r\n\r\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\r\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\r\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetMaintenanceFeeArgs {\r\n newFee: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\r\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * SetOraclePriceCap instruction data (9 bytes)\r\n * Set oracle price circuit breaker cap (admin only).\r\n *\r\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\r\n * 1_000_000 = 100% max move per slot.\r\n *\r\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\r\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\r\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\r\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\r\n *\r\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\r\n */\r\nexport interface SetOraclePriceCapArgs {\r\n maxChangeE2bps: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\r\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\r\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\r\n}\r\n\r\n/**\r\n * ResolveMode constants — retained for source compatibility with v12.x callers.\r\n *\r\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\r\n * no longer encoded into the instruction data. They may be used in logging or\r\n * off-chain logic but must not be passed to encodeResolveMarket.\r\n */\r\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\r\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\r\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\r\n\r\n/**\r\n * ResolveMarket instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\r\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\r\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\r\n * next read in a subsequent call, corrupting the instruction stream.\r\n *\r\n * The `mode` argument is accepted for source compatibility but is silently ignored.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeResolveMarket();\r\n * ```\r\n */\r\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\r\n return new Uint8Array([IX_TAG.ResolveMarket]);\r\n}\r\n\r\n/**\r\n * WithdrawInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\r\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\r\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\r\n * 1-byte payload fails on devnet/mainnet.\r\n *\r\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\r\n *\r\n * @param amount Amount to withdraw from the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * AdminForceClose instruction data (3 bytes)\r\n * Force-close any position at oracle price (admin only, skips margin checks).\r\n */\r\nexport interface AdminForceCloseArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\r\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\r\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\r\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\r\n * Use encodeSetInsuranceWithdrawPolicy instead.\r\n */\r\nexport interface UpdateRiskParamsArgs {\r\n initialMarginBps: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n tradingFeeBps?: bigint | string;\r\n}\r\n\r\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\r\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateRiskParams\",\r\n IX_TAG.UpdateRiskParams,\r\n \"encodeSetInsuranceWithdrawPolicy()\",\r\n );\r\n}\r\n\r\n/**\r\n * On-chain confirmation code for RenounceAdmin (must match program constant).\r\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\r\n */\r\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\r\n\r\n/**\r\n * On-chain confirmation code for UnresolveMarket (must match program constant).\r\n */\r\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\r\n\r\n/**\r\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\r\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\r\n * Use encodeWithdrawInsuranceLimited instead.\r\n */\r\nexport function encodeRenounceAdmin(): Uint8Array {\r\n return removedInstruction(\r\n \"RenounceAdmin\",\r\n IX_TAG.RenounceAdmin,\r\n \"encodeWithdrawInsuranceLimited()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\r\n * withdraw proportional collateral.\r\n *\r\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\r\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\r\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\r\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\r\n *\r\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\r\n *\r\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\r\n * [0] withdrawer signer\r\n * [1] slab writable\r\n * [2] withdrawerAta writable\r\n * [3] vault writable\r\n * [4] tokenProgram\r\n * [5] lpVaultMint writable\r\n * [6] withdrawerLpAta writable\r\n * [7] vaultAuthority\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\r\n *\r\n * @param lpAmount - Amount of LP vault tokens to burn.\r\n *\r\n * @example\r\n * ```ts\r\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\r\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\r\n *\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\r\n *\r\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\r\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\r\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\r\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\r\n * });\r\n * ```\r\n */\r\nexport interface LpVaultWithdrawArgs {\r\n /** Amount of LP vault tokens to burn. */\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\r\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\r\n */\r\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\r\n IX_TAG.LpVaultWithdraw,\r\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\r\n */\r\nexport function encodePauseMarket(): Uint8Array {\r\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\r\n */\r\nexport function encodeUnpauseMarket(): Uint8Array {\r\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-117: Pyth Oracle CPI Instructions\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetPythOracleArgs {\r\n feedId: Uint8Array;\r\n maxStalenessSecs: bigint;\r\n confFilterBps: number;\r\n}\r\n\r\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\r\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\r\n void args;\r\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\r\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\r\n *\r\n * @param feedId 32-byte Pyth feed ID\r\n * @param shardId Shard index (default 0 for mainnet/devnet)\r\n */\r\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\r\n\r\nexport async function derivePythPriceUpdateAccount(\r\n feedId: Uint8Array,\r\n shardId = 0,\r\n): Promise {\r\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\r\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\r\n }\r\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\r\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\r\n }\r\n const { PublicKey } = await import('@solana/web3.js');\r\n const shardBuf = new Uint8Array(2);\r\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\r\n const [pda] = PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\r\n );\r\n return pda.toBase58();\r\n}\r\n\r\n// SetPythOracle tag (32) is already defined in IX_TAG above.\r\n\r\n// PERC-118: Mark Price EMA Instructions\r\n// ============================================================================\r\n\r\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\r\n\r\n/**\r\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport function encodeUpdateMarkPrice(): Uint8Array {\r\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\r\n}\r\n\r\n/**\r\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\r\n */\r\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\r\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\r\n\r\n/**\r\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\r\n */\r\nexport function computeEmaMarkPrice(\r\n markPrevE6: bigint,\r\n oracleE6: bigint,\r\n dtSlots: bigint,\r\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\r\n capE2bps = 0n,\r\n): bigint {\r\n if (oracleE6 === 0n) return markPrevE6;\r\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\r\n\r\n let oracleClamped = oracleE6;\r\n if (capE2bps > 0n) {\r\n // Avoid overflow: divide early to reduce intermediate product\r\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\r\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\r\n const hi = markPrevE6 + maxDelta;\r\n if (oracleClamped < lo) oracleClamped = lo;\r\n if (oracleClamped > hi) oracleClamped = hi;\r\n }\r\n\r\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\r\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\r\n\r\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\r\n}\r\n\r\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\r\n// ============================================================================\r\n\r\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\r\n\r\n/**\r\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\r\n *\r\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\r\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\r\n * to authority_price_e6 on the slab.\r\n *\r\n * This is the core mechanism for permissionless token markets — no Pyth or\r\n * Chainlink feed is needed. The DEX AMM IS the oracle.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\r\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\r\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\r\n */\r\nexport function encodeUpdateHyperpMark(): Uint8Array {\r\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\r\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\r\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\r\n return removedInstruction(\r\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\r\n 34,\r\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-306: Per-Market Insurance Isolation\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\r\n */\r\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\r\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\r\n}\r\n\r\n/**\r\n * Set insurance isolation BPS for a market.\r\n * Accounts: [admin(signer), slab(writable)]\r\n */\r\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\r\n void args;\r\n return removedInstruction(\r\n \"SetInsuranceIsolation\",\r\n IX_TAG.SetInsuranceIsolation,\r\n \"encodeFundMarketInsurance()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\r\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\r\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\r\n// ============================================================================\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\r\n *\r\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\r\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\r\n *\r\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\r\n * ```\r\n */\r\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\r\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n/**\r\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\r\n *\r\n * Burns LP tokens and releases one tranche of SOL to the user.\r\n * Call once per epoch until epochs_remaining == 0.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\r\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\r\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\r\n */\r\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\r\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\r\n *\r\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\r\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\r\n * Use only to abandon a partial withdrawal.\r\n *\r\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\r\n */\r\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\r\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\r\n *\r\n * Permissionless. Surgically closes or reduces `targetIdx` position when\r\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\r\n * the incentive is unblocking the market for normal trading.\r\n *\r\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\r\n *\r\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\r\n *\r\n * @param targetIdx - Account index of the position to deleverage.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteAdl({ targetIdx: 5 });\r\n * ```\r\n */\r\nexport interface ExecuteAdlArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\r\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\r\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\r\n *\r\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\r\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\r\n * whose size does not match any current valid tier.\r\n *\r\n * Accounts: [dest(signer,writable), slab(writable)]\r\n */\r\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\r\nexport function encodeCloseStaleSlabs(): Uint8Array {\r\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\r\n}\r\n\r\n/**\r\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\r\n *\r\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\r\n * The slab account must sign (proves the caller holds the slab keypair).\r\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\r\n *\r\n * Accounts: [dest(signer,writable), slab(signer,writable)]\r\n */\r\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\r\nexport function encodeReclaimSlabRent(): Uint8Array {\r\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\r\n *\r\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\r\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\r\n * prevent DoS from transient failures).\r\n *\r\n * Accounts: [slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeAuditCrank();\r\n * ```\r\n */\r\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\r\nexport function encodeAuditCrank(): Uint8Array {\r\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// SMART PRICE ROUTER — quote computation for LP selection\r\n// ============================================================================\r\n\r\n/**\r\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\r\n */\r\nexport interface VammMatcherParams {\r\n mode: number; // 0 = Passive, 1 = vAMM\r\n tradingFeeBps: number;\r\n baseSpreadBps: number;\r\n maxTotalBps: number;\r\n impactKBps: number;\r\n liquidityNotionalE6: bigint;\r\n}\r\n\r\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\r\nexport const VAMM_MAGIC = 0x504552434d415443n;\r\n/** Alias matching the Rust constant name for parity tests */\r\nexport const MATCHER_MAGIC = VAMM_MAGIC;\r\n\r\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\r\nexport const CTX_RETURN_OFFSET = 0;\r\n/** Byte length of the MatcherReturn section of the context account */\r\nexport const MATCHER_RETURN_LEN = 64;\r\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\r\nexport const CTX_VAMM_OFFSET = 64;\r\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\r\nexport const CTX_VAMM_LEN = 256;\r\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\r\nexport const MATCHER_CONTEXT_LEN = 320;\r\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\r\nexport const MATCHER_CALL_LEN = 67;\r\n/**\r\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\r\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\r\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\r\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\r\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\r\n */\r\nexport const INIT_CTX_LEN = 78;\r\n\r\nconst BPS_DENOM = 10_000n;\r\n\r\n/**\r\n * Compute execution price for a given LP quote.\r\n * For buys (isLong=true): price above oracle.\r\n * For sells (isLong=false): price below oracle.\r\n */\r\nexport function computeVammQuote(\r\n params: VammMatcherParams,\r\n oraclePriceE6: bigint,\r\n tradeSize: bigint,\r\n isLong: boolean,\r\n): bigint {\r\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\r\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\r\n\r\n // Impact for vAMM mode\r\n let impactBps = 0n;\r\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\r\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\r\n }\r\n\r\n // Total = base_spread + trading_fee + impact, capped at max_total\r\n const maxTotal = BigInt(params.maxTotalBps);\r\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\r\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\r\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\r\n let totalBps = baseFee + clampedImpact;\r\n if (totalBps > maxTotal) totalBps = maxTotal;\r\n\r\n if (isLong) {\r\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\r\n } else {\r\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\r\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\r\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless crank)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\r\n *\r\n * Checks if a market should transition from Phase 0→1→2 based on\r\n * time elapsed and cumulative volume. Anyone can call this.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n */\r\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\r\nexport function encodeAdvanceOraclePhase(): Uint8Array {\r\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\r\n}\r\n\r\n/** Oracle phase constants matching on-chain values */\r\nexport const ORACLE_PHASE_NASCENT = 0;\r\nexport const ORACLE_PHASE_GROWING = 1;\r\nexport const ORACLE_PHASE_MATURE = 2;\r\n\r\n/** Phase transition thresholds (must match program constants) */\r\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\r\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\r\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\r\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\r\n\r\n/**\r\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\r\n *\r\n * @returns [newPhase, shouldTransition]\r\n */\r\nexport function checkPhaseTransition(\r\n currentSlot: bigint,\r\n marketCreatedSlot: bigint,\r\n oraclePhase: number,\r\n cumulativeVolumeE6: bigint,\r\n phase2DeltaSlots: number,\r\n hasMatureOracle: boolean,\r\n): [number, boolean] {\r\n switch (oraclePhase) {\r\n case 0: {\r\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\r\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\r\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\r\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\r\n if (timeReady || volumeReady) {\r\n return [ORACLE_PHASE_GROWING, true];\r\n }\r\n return [ORACLE_PHASE_NASCENT, false];\r\n }\r\n case 1: {\r\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\r\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\r\n const elapsedSincePhase2 = currentSlot - phase2Start;\r\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\r\n return [ORACLE_PHASE_MATURE, true];\r\n }\r\n return [ORACLE_PHASE_GROWING, false];\r\n }\r\n default:\r\n return [ORACLE_PHASE_MATURE, false];\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-629: Dynamic Creation Deposit\r\n// ============================================================================\r\n\r\n/**\r\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\r\n * after the spam grace period has elapsed (PERC-629).\r\n *\r\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\r\n * handler in the on-chain program. Sending this instruction will fail with\r\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [] Slab\r\n * 2. [writable] Creator history PDA\r\n * 3. [writable] Insurance vault\r\n * 4. [writable] Treasury\r\n * 5. [] System program\r\n *\r\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\r\n */\r\nexport function encodeSlashCreationDeposit(): Uint8Array {\r\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\r\n// ============================================================================\r\n\r\n/**\r\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\r\n *\r\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [writable] Shared vault PDA\r\n * 2. [] System program\r\n */\r\nexport interface InitSharedVaultArgs {\r\n epochDurationSlots: bigint | string;\r\n maxMarketExposureBps: number;\r\n}\r\n\r\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\r\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\r\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\r\n}\r\n\r\n/**\r\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\r\n * to a market (PERC-628).\r\n *\r\n * Instruction data: tag(1) + amount(16) = 17 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [] Slab\r\n * 2. [writable] Shared vault PDA\r\n * 3. [writable] Market alloc PDA\r\n * 4. [] System program\r\n */\r\nexport interface AllocateMarketArgs {\r\n amount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\r\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\r\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\r\n}\r\n\r\n/**\r\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\r\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\r\n *\r\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] System program\r\n */\r\nexport interface QueueWithdrawalSVArgs {\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\r\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\r\n}\r\n\r\n/**\r\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\r\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] Slab\r\n * 4. [writable] Vault\r\n * 5. [writable] User ATA\r\n * 6. [] Vault authority\r\n * 7. [] Token program\r\n */\r\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\r\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\r\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [writable] Shared vault PDA\r\n */\r\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\r\nexport function encodeAdvanceEpoch(): Uint8Array {\r\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\r\n}\r\n\r\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\r\n\r\n// PERC-8110 ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\r\n *\r\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\r\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\r\n *\r\n * - `threshold_bps = 0`: hard block disabled.\r\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\r\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\r\n *\r\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\r\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\r\n * });\r\n * ```\r\n */\r\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\r\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-608 — Position NFT instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\r\n *\r\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\r\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\r\n *\r\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\r\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\r\n * program creates it, so the ATA can't be created in a preceding instruction.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts (11):\r\n * 0. [signer, writable] payer\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\r\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\r\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\r\n * 5. [signer] owner (must match engine account owner)\r\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\r\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\r\n * 8. [] system_program\r\n * 9. [] rent sysvar\r\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\r\n */\r\nexport interface MintPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\r\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\r\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\r\n */\r\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\r\n IX_TAG.MintPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\r\n *\r\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\r\n * engine account's owner field. Requires `pending_settlement == 0`.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] current_owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA\r\n * 3. [writable] nft_mint PDA\r\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\r\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\r\n * 6. [] new_owner\r\n * 7. [] token_2022_program\r\n */\r\nexport interface TransferPositionOwnershipArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\r\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\r\n */\r\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\r\n IX_TAG.TransferPositionOwnership,\r\n \"encodeTransferPortfolioOwnership() (tag 72)\",\r\n );\r\n}\r\n\r\n/**\r\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\r\n *\r\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\r\n * Can only be called after the position is fully closed (size == 0).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (closed — rent to owner)\r\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\r\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\r\n * 5. [] vault_authority PDA\r\n * 6. [] token_2022_program\r\n */\r\nexport interface BurnPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\r\n * NFT burn is handled by the standalone percolator-nft program in v17.\r\n */\r\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\r\n IX_TAG.BurnPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin before performing a funding settlement transfer.\r\n * Blocks NFT transfers until ClearPendingSettlement is called.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface SetPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\r\n */\r\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\r\n IX_TAG.SetPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface ClearPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\r\n */\r\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\r\n IX_TAG.ClearPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\r\n *\r\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\r\n * Updates the engine account's owner field to the new_owner public key.\r\n * NOT intended for direct external use — always called via Token-2022 CPI.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] nft TransferHook program (CPI caller)\r\n * 1. [writable] slab\r\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\r\n */\r\nexport interface TransferOwnershipCpiArgs {\r\n userIdx: number;\r\n newOwner: PublicKey | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\r\n */\r\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\r\n IX_TAG.TransferOwnershipCpi,\r\n \"percolator-nft transfer hook\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-8111 — SetWalletCap (tag 70)\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\r\n *\r\n * Limits the maximum absolute position size any single wallet may hold on this market.\r\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\r\n *\r\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\r\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\r\n * Phase 1 launch value: 1_000_000_000n ($1,000).\r\n *\r\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\r\n * (error code 58) is returned.\r\n *\r\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * // Set $1K per-wallet cap\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\r\n * });\r\n *\r\n * // Disable cap\r\n * const disableIx = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\r\n * });\r\n * ```\r\n */\r\nexport interface SetWalletCapArgs {\r\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\r\n capE6: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\r\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\r\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\r\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\r\n *\r\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\r\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\r\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\r\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\r\n * handler reads the LP portfolio's stored matcher config and verifies that:\r\n * cfg.matcher_program == matcherProg\r\n * cfg.matcher_context == matcherCtx\r\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\r\n *\r\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\r\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\r\n * check on the deployed binary. No client-side signer of the delegate is needed.\r\n *\r\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\r\n * [0] lp_owner signer (LP portfolio owner)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\r\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\r\n * [4] matcher_prog read-only, executable (the matcher program)\r\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\r\n *\r\n * @param args.kind 0=Passive, 1=vAMM\r\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\r\n * @param args.baseSpreadBps Base spread in bps (u32)\r\n * @param args.maxTotalBps Max total spread in bps (u32)\r\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\r\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\r\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\r\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\r\n *\r\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\r\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\r\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\r\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\r\n * this tag free.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMatcherCtx({\r\n * kind: 0, // Passive\r\n * tradingFeeBps: 30,\r\n * baseSpreadBps: 50,\r\n * maxTotalBps: 200,\r\n * impactKBps: 0,\r\n * liquidityNotionalE6: 0n,\r\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\r\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\r\n * feeToInsuranceBps: 0,\r\n * skewSpreadMultBps: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface InitMatcherCtxArgs {\r\n /**\r\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\r\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\r\n */\r\n lpIdx?: number;\r\n /** Matcher kind: 0=Passive, 1=vAMM. */\r\n kind: number;\r\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\r\n tradingFeeBps: number;\r\n /** Base spread in bps (u32). */\r\n baseSpreadBps: number;\r\n /** Max total spread in bps (u32). */\r\n maxTotalBps: number;\r\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\r\n impactKBps: number;\r\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\r\n liquidityNotionalE6: bigint | string;\r\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\r\n maxFillAbs: bigint | string;\r\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\r\n maxInventoryAbs: bigint | string;\r\n /** Fraction of fees routed to insurance fund in bps (u16). */\r\n feeToInsuranceBps: number;\r\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\r\n skewSpreadMultBps: number;\r\n}\r\n\r\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\r\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\r\n\r\n/**\r\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\r\n *\r\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\r\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\r\n *\r\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\r\n * @returns 70-byte Uint8Array\r\n */\r\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(83), // IX_TAG.InitMatcherCtx = 83\r\n encU8(args.kind),\r\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\r\n encU128(args.liquidityNotionalE6), // u128 LE\r\n encU128(args.maxFillAbs), // u128 LE\r\n encU128(args.maxInventoryAbs), // u128 LE\r\n encU16(args.feeToInsuranceBps), // u16 LE\r\n encU16(args.skewSpreadMultBps), // u16 LE\r\n );\r\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n// ============================================================================\r\n// Missing encoders — corrected tag mappings (tags 22-74)\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\r\n */\r\nexport interface SetInsuranceWithdrawPolicyArgs {\r\n authority: PublicKey | string;\r\n minWithdrawBase: bigint | string;\r\n maxWithdrawBps: number;\r\n cooldownSlots: bigint | string;\r\n}\r\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\r\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\r\n */\r\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\r\n */\r\nexport function encodeResolvePermissionless(): Uint8Array {\r\n return removedInstruction(\r\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\r\n IX_TAG.ResolvePermissionless,\r\n \"encodeResolveStalePermissionless()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\r\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\r\n return removedInstruction(\r\n \"ForceCloseResolved\",\r\n IX_TAG.ForceCloseResolved,\r\n \"encodeCloseResolved() for v17\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeCreateLpVault (v12 format)\",\r\n IX_TAG.CreateLpVault,\r\n \"encodeCreateLpVaultV17()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeLpVaultDeposit (v12 format)\",\r\n IX_TAG.LpVaultDeposit,\r\n \"encodeDepositToLpVault()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\r\n */\r\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"ChallengeSettlement\",\r\n IX_TAG.ChallengeSettlement,\r\n undefined,\r\n );\r\n}\r\n\r\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\r\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\r\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\r\n}\r\n\r\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\r\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\r\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\r\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\r\n}\r\n\r\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\r\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\r\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\r\n}\r\n\r\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\r\nexport function encodeRescueOrphanVault(): Uint8Array {\r\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\r\n}\r\n\r\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\r\nexport function encodeCloseOrphanSlab(): Uint8Array {\r\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\r\n}\r\n\r\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\r\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\r\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeCreateInsuranceMint(): Uint8Array {\r\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n// ============================================================================\r\n// Phase B admin setters (tags 78-81) — added 2026-04-17\r\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\r\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport interface SetMaxPnlCapArgs {\r\n cap: bigint | string;\r\n}\r\n\r\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\r\n IX_TAG.SetMaxPnlCap,\r\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\r\n */\r\nexport interface SetOiCapMultiplierArgs {\r\n packed: bigint | string;\r\n}\r\n\r\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\r\n IX_TAG.SetOiCapMultiplier,\r\n \"encodeSetLpVaultPaused() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\r\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\r\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\r\n }\r\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\r\n }\r\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\r\n */\r\nexport interface SetDisputeParamsArgs {\r\n windowSlots: bigint | string;\r\n bondAmount: bigint | string;\r\n}\r\n\r\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\r\n IX_TAG.SetDisputeParams,\r\n \"encodeCloseLpVault() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\r\n */\r\nexport interface SetLpCollateralParamsArgs {\r\n enabled: number;\r\n ltvBps: number;\r\n}\r\n\r\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\r\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\r\n */\r\nexport function encodeAcceptAdmin(): Uint8Array {\r\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\r\n}\r\n\r\n// ============================================================================\r\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\r\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\r\n */\r\nexport interface ReclaimEmptyAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\r\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\r\n */\r\nexport interface SettleAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\r\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\r\n */\r\nexport interface DepositFeeCreditsArgs {\r\n userIdx: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\r\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\r\n}\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\r\n * Owner only.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\r\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\r\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\r\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\r\n * are identified by account key alone.\r\n *\r\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\r\n *\r\n * @param amount Amount of released PnL to convert (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface ConvertReleasedPnlArgs {\r\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ConvertReleasedPnl),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\r\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\r\n *\r\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\r\n *\r\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\r\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\r\n * Burning marketauth to zero is rejected on-chain.\r\n *\r\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\r\n * ```\r\n */\r\nexport interface UpdateAuthorityArgs {\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAuthority),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — UpdateAssetAuthority (tag 65)\r\n// ============================================================================\r\n\r\n/**\r\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\r\n *\r\n * Exact mapping from v16_program.rs lines 5246-5250:\r\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\r\n * ASSET_AUTH_INSURANCE = 1 → Insurance\r\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\r\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\r\n * ASSET_AUTH_ORACLE = 4 → Oracle\r\n *\r\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\r\n * slot. Wrong values silently corrupt authority state:\r\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\r\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\r\n * corrupting the market-level admin key instead.\r\n *\r\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\r\n * the stake vault PDA into the asset_admin authority slot.\r\n */\r\nexport const ASSET_AUTH_KIND = {\r\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\r\n AssetAdmin: 0,\r\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\r\n Insurance: 1,\r\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\r\n InsuranceOperator: 2,\r\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\r\n BackingBucket: 3,\r\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\r\n Oracle: 4,\r\n} as const;\r\nObject.freeze(ASSET_AUTH_KIND);\r\n\r\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\r\n\r\n/**\r\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * Gated by the asset's own asset_admin (can rotate any) or by the current\r\n * holder of that authority (self-rotation). Isolated to the given asset_index.\r\n *\r\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\r\n * @param kind ASSET_AUTH_KIND.* constant.\r\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\r\n *\r\n * @example\r\n * ```ts\r\n * // Rotate insurance authority for asset 0\r\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\r\n * const data = encodeUpdateAssetAuthority({\r\n * assetIndex: 0,\r\n * kind: ASSET_AUTH_KIND.Insurance,\r\n * newPubkey: newInsuranceKey,\r\n * });\r\n * ```\r\n */\r\nexport interface UpdateAssetAuthorityArgs {\r\n assetIndex: number;\r\n kind: AssetAuthKind;\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAssetAuthority),\r\n encU16(args.assetIndex),\r\n encU8(args.kind),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\r\n// ============================================================================\r\n\r\n/**\r\n * One leg of a BatchTradeNoCpi instruction.\r\n */\r\nexport interface BatchTradeNoCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\n/**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\r\n *\r\n * @param legs Array of up to 255 trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeNoCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\r\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\r\n * ]});\r\n * ```\r\n */\r\nexport interface BatchTradeNoCpiArgs {\r\n legs: BatchTradeNoCpiLeg[];\r\n}\r\n\r\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\r\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\r\n if (feeBps > 10_000n) {\r\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\r\n }\r\n}\r\n\r\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeNoCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.execPrice));\r\n parts.push(encU64(leg.feeBps));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n/**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\r\n *\r\n * @param legs Array of up to 255 CPI trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\r\n * ]});\r\n * ```\r\n */\r\n\r\nexport interface BatchTradeCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport interface BatchTradeCpiArgs {\r\n legs: BatchTradeCpiLeg[];\r\n}\r\n\r\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.feeBps));\r\n parts.push(encU64(leg.limitPrice));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — SetMatcherConfig (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n *\r\n * @param enabled 1 = enabled, 0 = disabled.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetMatcherConfig({ enabled: 1 });\r\n * ```\r\n */\r\nexport interface SetMatcherConfigArgs {\r\n enabled: number;\r\n}\r\n\r\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\r\n if (args.enabled !== 0 && args.enabled !== 1) {\r\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\r\n }\r\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — RestartAssetOracle (tag 69)\r\n// ============================================================================\r\n\r\n/**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\r\n *\r\n * Used to un-stick a stale or hung oracle. Anyone can call this.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param nowSlot Current slot.\r\n * @param initialPrice Initial mark price in e6 units.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRestartAssetOracle({\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * initialPrice: 50_000_000_000n,\r\n * });\r\n * ```\r\n */\r\nexport interface RestartAssetOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialPrice: bigint | string;\r\n}\r\n\r\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RestartAssetOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialPrice),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\r\n *\r\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\r\n * asset_index is u16 (domain u8→u16 migration in v17).\r\n *\r\n * @param assetIndex Asset/domain index (u16, not u8).\r\n * @param amount Amount to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceAssetArgs {\r\n assetIndex: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawInsuranceAsset),\r\n encU16(args.assetIndex),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — LP-vault renumbered tags (74-80)\r\n// ============================================================================\r\n\r\n/**\r\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\r\n *\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\r\n *\r\n * @param feeShareBps LP vault fee share in bps (0-10000).\r\n * @param redemptionCooldownSlots Slots between redemption requests.\r\n * @param oiReservationThresholdBps OI reservation threshold in bps.\r\n * @param domain Asset/domain index (u16 in v17).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCreateLpVault({\r\n * feeShareBps: 5000,\r\n * redemptionCooldownSlots: 21600n,\r\n * oiReservationThresholdBps: 8000,\r\n * domain: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface CreateLpVaultArgs {\r\n feeShareBps: number;\r\n redemptionCooldownSlots: bigint | string;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n}\r\n\r\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.CreateLpVault),\r\n encU16(args.feeShareBps),\r\n encU64(args.redemptionCooldownSlots),\r\n encU16(args.oiReservationThresholdBps),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\r\n *\r\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\r\n *\r\n * `domain` selects which pot of the vault's asset receives the backing and MUST\r\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\r\n * NAV across both pots, so the depositor is indifferent to the choice; routing\r\n * exists so new money can reach whichever pot the house is drawing on.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\r\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\r\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\r\n * and mint the depositor free shares at existing holders' expense.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\r\n * ```\r\n */\r\nexport function encodeDepositToLpVault(args: {\r\n amount: bigint | string;\r\n domain: number;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositToLpVault),\r\n encU128(args.amount),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\r\n *\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\r\n * v17 uses shares u128 and a two-step request/execute redemption flow.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\r\n * ```\r\n */\r\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\r\n}\r\n\r\n/**\r\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\r\n * available-principal stay COMBINED across both pots, so this does not change\r\n * what the redeemer is owed — only where the atoms come from. A redemption draws\r\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\r\n * cover it; rebalance (tag 91) first.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteRedemption({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\r\n * choice cannot dilute; routing exists so fees can become backing in the pot\r\n * that needs it. The target ledger is created on first use.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\r\n * index 5 is the system program (needed to create a missing target ledger).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeLpVaultCrankFees({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\r\n * the LP vault's asset.\r\n *\r\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\r\n *\r\n * Permissionless: both pots belong to the same vault, so the move cannot extract\r\n * value, and the source-side gate refuses anything that would leave the source\r\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\r\n * open interest, already consumed, or impaired stays put.\r\n *\r\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\r\n * systemProgram]. The destination ledger is created on first arrival.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRebalanceLpVaultBacking({\r\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeRebalanceLpVaultBacking(args: {\r\n fromDomain: number;\r\n toDomain: number;\r\n amount: bigint | string;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RebalanceLpVaultBacking),\r\n encU16(args.fromDomain),\r\n encU16(args.toDomain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\r\n *\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n *\r\n * @param paused 1 = paused, 0 = active.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetLpVaultPaused({ paused: 1 });\r\n * ```\r\n */\r\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\r\n}\r\n\r\n/**\r\n * CloseLpVault (tag 80) — close an empty LP vault.\r\n *\r\n * Wire: tag(1) = 1 byte.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseLpVault();\r\n * ```\r\n */\r\nexport function encodeCloseLpVault(): Uint8Array {\r\n return encU8(IX_TAG.CloseLpVault);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NFT / B-3 (tags 72/73) — kept from v16\r\n// ============================================================================\r\n\r\n/**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n *\r\n * @param newOwner New owner pubkey.\r\n * @param assetIndex Asset/domain index.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTransferPortfolioOwnership({\r\n * newOwner: newOwnerKey,\r\n * assetIndex: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface TransferPortfolioOwnershipArgs {\r\n newOwner: PublicKey | string;\r\n assetIndex: number;\r\n}\r\n\r\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TransferPortfolioOwnership),\r\n encPubkey(args.newOwner),\r\n encU16(args.assetIndex),\r\n );\r\n}\r\n\r\n/**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n *\r\n * @param nftProgramId Pubkey of the percolator-nft program.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\r\n * ```\r\n */\r\nexport interface SetNftProgramIdArgs {\r\n nftProgramId: PublicKey | string;\r\n}\r\n\r\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetNftProgramId),\r\n encPubkey(args.nftProgramId),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\r\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\r\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\r\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\r\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\r\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\r\n *\r\n * Constraints (from v16_program.rs:10419-10435):\r\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\r\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\r\n * - hybrid_soft_stale_slots > 0\r\n * - invert ∈ {0, 1}\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\r\n * @param oracleLegCount Number of active oracle legs (1–3).\r\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\r\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\r\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\r\n * @param markMinFee Minimum fee charged per mark-price update.\r\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\r\n * @param unitScale Unit scaling factor (u32).\r\n * @param confFilterBps Confidence filter in basis points (u16).\r\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureHybridOracle({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * nowUnixTs: 1700000000n,\r\n * oracleLegCount: 1,\r\n * oracleLegFlags: 0,\r\n * maxStalenessSecs: 60n,\r\n * hybridSoftStaleSlots: 100n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * invert: 0,\r\n * unitScale: 1000000,\r\n * confFilterBps: 200,\r\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\r\n * });\r\n * assert(data.length === 156);\r\n * ```\r\n */\r\nexport interface ConfigureHybridOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n nowUnixTs: bigint | string;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n maxStalenessSecs: bigint | string;\r\n hybridSoftStaleSlots: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\r\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\r\n}\r\n\r\nconst ORACLE_LEG_CAP = 3;\r\n\r\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\r\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\r\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\r\n }\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureHybridOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI64(args.nowUnixTs),\r\n encU8(args.oracleLegCount),\r\n encU8(args.oracleLegFlags),\r\n encU64(args.maxStalenessSecs),\r\n encU64(args.hybridSoftStaleSlots),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n encU8(args.invert),\r\n encU32(args.unitScale),\r\n encU16(args.confFilterBps),\r\n encPubkey(args.oracleLegFeeds[0]),\r\n encPubkey(args.oracleLegFeeds[1]),\r\n encPubkey(args.oracleLegFeeds[2]),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\r\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10558-10563):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - mark_ewma_halflife_slots > 0\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\r\n * @param markMinFee Minimum fee charged per mark-price update (u64).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureEwmaMark({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * initialMarkE6: 50000000000n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * });\r\n * assert(data.length === 35);\r\n * ```\r\n */\r\nexport interface ConfigureEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n}\r\n\r\nfunction requirePositiveU64(value: bigint | string, field: string): void {\r\n const n = typeof value === \"string\" ? BigInt(value) : value;\r\n if (n <= 0n) {\r\n throw new Error(`${field} must be > 0`);\r\n }\r\n}\r\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n );\r\n}\r\n\r\n/**\r\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10771):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10665):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface ConfigureAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n}\r\n\r\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n );\r\n}\r\n\r\n/**\r\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10847):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\r\n// ============================================================================\r\n\r\n/**\r\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\r\n * to initialize a passive LP matcher context.\r\n *\r\n * This is NOT a wrapper instruction. Program = matcher program address.\r\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\r\n *\r\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\r\n * [0] = 2 (opcode: passive-LP init)\r\n * [1] = 0 (reserved)\r\n * [2..10] = 0 (8 bytes reserved)\r\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\r\n * [14..34] = 0 (20 bytes reserved)\r\n * [34..50] = max_fill_abs (u128 LE)\r\n * [50..66] = 0 (16 bytes reserved)\r\n * Total = 66 bytes\r\n *\r\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\r\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\r\n *\r\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\r\n * assert(data.length === 66);\r\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\r\n * ```\r\n */\r\nexport interface MatcherInitPassiveArgs {\r\n maxFillAbs: bigint | string;\r\n}\r\n\r\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\r\n const buf = new Uint8Array(66);\r\n buf[0] = 2;\r\n buf[1] = 0;\r\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\r\n const u32Bytes = encU32(100);\r\n buf.set(u32Bytes, 10);\r\n // [34..50] = max_fill_abs u128 LE\r\n const u128Bytes = encU128(args.maxFillAbs);\r\n buf.set(u128Bytes, 34);\r\n return buf;\r\n}\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\r\n// handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\r\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\r\n//\r\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\r\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\r\n// all — sending this encoded data to it would be rejected or misinterpreted.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee instruction data (tag 84).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\r\n * WrapperConfigV17) to an external token account. Signer-gated on\r\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\r\n * clamped to what's actually available on-chain (engine surplus, vault\r\n * balance) and only the actually-transferred amount is marked withdrawn —\r\n * this never errors solely because the ledger raced ahead of availability.\r\n *\r\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\r\n * currently-available capacity.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\r\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawProtocolFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawProtocolFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetProtocolFeeAuthority instruction data (tag 85).\r\n *\r\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\r\n *\r\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\r\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\r\n * marketauth/insurance_authority/any creator-facing gate) — see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\r\n * a keeper script iterates markets for a mass rotation.\r\n *\r\n * @param newAuthority New protocol-fee-authority pubkey.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\r\n * ```\r\n */\r\nexport interface SetProtocolFeeAuthorityArgs {\r\n newAuthority: PublicKey;\r\n}\r\n\r\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetProtocolFeeAuthority),\r\n encPubkey(args.newAuthority),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\r\n *\r\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\r\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\r\n * three stored shares below, which are bps *of T* and must sum to exactly\r\n * `FEE_SHARE_TOTAL_BPS`.\r\n *\r\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\r\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\r\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\r\n * above its ceiling necessarily drags another leg under its floor.\r\n *\r\n * Defaults are written unconditionally at InitMarket and are never instruction\r\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\r\n * legs correctly from its first trade.\r\n */\r\nexport const FEE_SPLIT = {\r\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\r\n PROTOCOL_FEE_BPS: 2000,\r\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\r\n FEE_SHARE_TOTAL_BPS: 8000,\r\n DEFAULT_CREATOR_SHARE_BPS: 1600,\r\n DEFAULT_LP_SHARE_BPS: 4800,\r\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\r\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\r\n MAX_CREATOR_SHARE_BPS: 3600,\r\n /** LP floor, bps of T (40% of the post-protocol remainder). */\r\n MIN_LP_SHARE_BPS: 3200,\r\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\r\n MIN_INSURANCE_SHARE_BPS: 1200,\r\n} as const;\r\nObject.freeze(FEE_SPLIT);\r\n\r\n/**\r\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\r\n * the split would be accepted on-chain, otherwise a human-readable reason.\r\n *\r\n * Provided so a wizard/UI can reject a bad split before paying for a\r\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\r\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\r\n * floors), so this is a convenience, never the security boundary.\r\n *\r\n * @param args The three candidate shares, in bps of T.\r\n * @returns `null` if valid, else a string describing the first violation.\r\n *\r\n * @example\r\n * ```ts\r\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\r\n * // => null (these are the on-chain defaults)\r\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\r\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\r\n * ```\r\n */\r\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\r\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\r\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\r\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\r\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\r\n }\r\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\r\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\r\n }\r\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\r\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\r\n }\r\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\r\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * UpdateFeeSplit instruction data (tag 86).\r\n *\r\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\r\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\r\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\r\n * {@link validateFeeSplit} to check before sending.\r\n *\r\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\r\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\r\n * top-level transaction and this tag is reachable only via the stake program's\r\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\r\n *\r\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\r\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\r\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Restore the on-chain defaults explicitly.\r\n * const data = encodeUpdateFeeSplit({\r\n * creatorShareBps: 1600,\r\n * lpShareBps: 4800,\r\n * insuranceShareBps: 1600,\r\n * });\r\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateFeeSplitArgs {\r\n creatorShareBps: number;\r\n lpShareBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateFeeSplit),\r\n encU16(args.creatorShareBps),\r\n encU16(args.lpShareBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\r\n *\r\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\r\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\r\n * clamped on-chain to engine-available surplus, and the destination is derived\r\n * rather than passed.\r\n *\r\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\r\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\r\n * PINNED stake program id, so there is nothing for a caller to redirect.\r\n *\r\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\r\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\r\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\r\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\r\n * resolution.\r\n *\r\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\r\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\r\n * stake deployment.\r\n *\r\n * @returns 1-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceReserveToStake();\r\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\r\n * ```\r\n */\r\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\r\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\r\n}\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\r\n *\r\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\r\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\r\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\r\n * wrapper rejects the instruction outright.\r\n *\r\n * Gated on `cfg.marketauth`. The wrapper range-checks against\r\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\r\n * exceeded — the same bound InitMarket applies.\r\n *\r\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\r\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\r\n * (maintenance fee disabled).\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\r\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateMaintenanceFeePerSlotArgs {\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateMaintenanceFeePerSlot(\r\n args: UpdateMaintenanceFeePerSlotArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\r\n encU128(args.maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateTradeFeePolicy instruction data (tag 55).\r\n *\r\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\r\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\r\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\r\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\r\n * (stake tag 28).\r\n *\r\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\r\n * with `read_u128`.\r\n *\r\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\r\n * which left stake tag 28's CPI target unrepresentable from the SDK.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\r\n * ```\r\n */\r\nexport interface UpdateTradeFeePolicyArgs {\r\n tradeFeeBaseBps: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateTradeFeePolicy),\r\n encU64(args.tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * ExpireBackingBucket instruction data (tag 89).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\r\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\r\n * domain: read_u16(&mut rest)? }`) followed by the shared\r\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\r\n *\r\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\r\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\r\n * authority to hold.\r\n *\r\n * ## Why this exists\r\n *\r\n * A realized loss reserves capital as counterparty backing, which opens the\r\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\r\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\r\n * END in all three directions, permanently:\r\n *\r\n * - settling a GAIN against it -> Custom(19) EngineStale\r\n * - reserving a further LOSS -> Custom(21) EngineLockActive\r\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\r\n *\r\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\r\n * no call site that reached the engine's own escape hatch\r\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\r\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\r\n * good. Tag 89 IS that missing call site.\r\n *\r\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\r\n *\r\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\r\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\r\n * once when the bucket opens and is never extended. Seeding a long horizon\r\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\r\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\r\n * incident-response tool: a keeper should scan live markets for domains whose\r\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\r\n * nobody cranks it, the first lapse silently bricks the domain and the failure\r\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\r\n * settlement.\r\n *\r\n * ## Safety\r\n *\r\n * Permissionless is not an authority hole. The engine refuses the transition\r\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\r\n * is read from the runtime `Clock` (via\r\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\r\n * — so no caller can force an early forfeiture. Moves no tokens.\r\n *\r\n * Expiry forfeits the lapsed principal to the junior pool. That is the\r\n * engine's documented expiry semantics, not a haircut invented by this\r\n * instruction; the alternative is the account never settling at all.\r\n *\r\n * ## Failure modes\r\n *\r\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\r\n * resolved/wound-down path reaches the transition through the engine's own\r\n * resolved-close sweep, so re-entering it from outside is refused.\r\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\r\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\r\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\r\n * speculatively on a healthy domain is safe (it just reverts).\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short), u16. Must be\r\n * `< 2 * max_market_slots`.\r\n * @returns 3-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\r\n * const data = encodeExpireBackingBucket({ domain: 0 });\r\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\r\n * // beyond the fee payer.\r\n * ```\r\n */\r\nexport interface ExpireBackingBucketArgs {\r\n domain: number;\r\n}\r\n\r\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ExpireBackingBucket),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n//\r\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\r\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\r\n// 576-byte config — see solana/slab.ts).\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee instruction data (tag 90).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\r\n * percolator-prog `src/v16_program.rs`:\r\n *\r\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\r\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\r\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\r\n * -> total length is EXACTLY 17; any trailing byte is rejected\r\n * encode arm: out.push(90); push_u128(&mut out, amount)\r\n *\r\n * Pays the market creator's accrued trade-fee share out of the market vault to\r\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\r\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\r\n * backstop): before this change the creator leg was credited INTO the backstop,\r\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\r\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\r\n * counter.\r\n *\r\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\r\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\r\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\r\n * `parseWrapperConfigV17` and pass that exact value.\r\n *\r\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\r\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\r\n * the whole instruction fails closed (EngineLockActive); retry with less.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\r\n * `cfg.marketauth`), so claiming still works on a staked market where\r\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\r\n *\r\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\r\n * u64, so anything above u64::MAX is an over-claim).\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketAccount.data);\r\n * // Drain the full claimable balance:\r\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\r\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawCreatorFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCreatorFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n","import {\r\n PublicKey,\r\n AccountMeta,\r\n SYSVAR_CLOCK_PUBKEY,\r\n SYSVAR_RENT_PUBKEY,\r\n SystemProgram,\r\n} from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Account spec for building instruction account metas.\r\n * Each instruction has a fixed ordering that matches the Rust processor.\r\n */\r\nexport interface AccountSpec {\r\n name: string;\r\n signer: boolean;\r\n writable: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// ACCOUNT ORDERINGS - Single source of truth\r\n// ============================================================================\r\n\r\n/**\r\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\r\n */\r\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"mint\", signer: false, writable: false },\r\n { name: \"vault\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"dummyAta\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * InitPortfolio (tag 2): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\r\n * [0] owner signer, writable (portfolio owner; pays for alloc)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n *\r\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\r\n * InitPortfolio does not transfer collateral and does not read the clock.\r\n */\r\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * InitLP: 6 accounts\r\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\r\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\r\n * [0] user signer, writable (LP owner; pays fee)\r\n * [1] slab writable\r\n * [2] userAta writable (collateral source for fee)\r\n * [3] vault writable (collateral destination)\r\n * [4] tokenProgram read-only\r\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\r\n */\r\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Deposit (tag 3): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] sourceToken writable (owner's collateral ATA)\r\n * [4] vaultToken writable (program vault token account)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\r\n */\r\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Withdraw (tag 4): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] destToken writable (owner's collateral ATA — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs token CPI)\r\n * [6] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\r\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\r\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\r\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\r\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\r\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\r\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\r\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\r\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\r\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\r\n */\r\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\r\n { name: \"nftRegistry\", signer: false, writable: false },\r\n { name: \"positionNft\", signer: false, writable: false },\r\n { name: \"signerNftAta\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\r\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\r\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\r\n */\r\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\r\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\r\n}\r\n\r\n/**\r\n * KeeperCrank: 4 accounts\r\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\r\n */\r\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\r\n * [0] owner signer, writable (keeper key; receives liquidation reward)\r\n * [1] market writable (the market-group slab)\r\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\r\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\r\n *\r\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\r\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\r\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\r\n * the same program and have a different key from accounts[2].\r\n *\r\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\r\n * including oracle tail and optional keeper portfolio.\r\n */\r\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * RestartAssetOracle (tag 69): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\r\n * [0] authority signer (asset_admin for the target asset_index)\r\n * [1] market writable (the market-group slab)\r\n *\r\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\r\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\r\n * Permissionless in the sense that any holder of asset_admin can call it.\r\n */\r\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n\r\n/**\r\n * TradeNoCpi (tag 9): 5 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\r\n * [0] signerA signer, writable (party A — portfolio owner)\r\n * [1] signerB signer, writable (party B — portfolio owner)\r\n * [2] market writable (market-group slab; program-owned)\r\n * [3] accountA writable (portfolio A; program-owned)\r\n * [4] accountB writable (portfolio B; program-owned)\r\n *\r\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\r\n * signerB replaces lp (both portfolios must have live owner signers).\r\n */\r\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: true },\r\n { name: \"signerB\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LiquidateAtOracle: 4 accounts\r\n * Note: account[0] is unused but must be present\r\n */\r\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\r\n { name: \"unused\", signer: false, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClosePortfolio (tag 8): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\r\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\r\n *\r\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\r\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\r\n * portfolio and closes the account back to the market slab.\r\n */\r\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\r\n * [0] signer signer, writable (insurance authority for asset 0)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\r\n *\r\n * v12 stale accounts removed: clock sysvar (was at [5]).\r\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\r\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\r\n * per-authority deposit principals; omit for simple vault top-ups.\r\n */\r\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\r\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\r\n * omit for a simple top-up with no ledger tracking)\r\n *\r\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\r\n */\r\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority-OWNED token account — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\r\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\r\n * so it stays callable by the creator wallet after the\r\n * launch flow rotates marketauth to the stake-pool PDA)\r\n * [1] market writable (market-group slab; program-owned)\r\n */\r\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\r\n * unlike tag 50 where it is an optional tail)\r\n * [3] destToken writable (authority-OWNED token account — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [6] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\r\n * [0] signerA signer (party A — portfolio owner)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] accountA writable (portfolio A; program-owned)\r\n * [3] accountB writable (portfolio B; program-owned)\r\n * [4] matcherProg read-only, executable (matcher program)\r\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\r\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\r\n * [7+] tail additional accounts forwarded to matcher CPI\r\n *\r\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\r\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\r\n * market replaces slab name.\r\n */\r\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetRiskThreshold: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAdmin: 2 accounts\r\n */\r\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * AcceptAdmin: 2 accounts (tag 82)\r\n * Second half of two-step admin transfer. The proposed new admin must sign to\r\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\r\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\r\n * [1] slab writable\r\n */\r\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\r\n { name: \"pendingAdmin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CloseSlab: 6 accounts\r\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\r\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\r\n * [0] dest signer, writable (receives rent + drained vault tokens)\r\n * [1] slab writable\r\n * [2] vault writable (token account — drained)\r\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\r\n * [4] destAta writable (dest's token ATA receiving drained tokens)\r\n * [5] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"destAta\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\r\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\r\n * 3-account form: [admin(s+w), slab(w), clock].\r\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\r\n * needs to re-read price during config commit). Default to the 3-account form;\r\n * callers that need oracle re-reads should append the oracle account themselves.\r\n */\r\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetMaintenanceFee: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetOraclePriceCap: 3 accounts.\r\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\r\n * Layout: [admin(s+w), slab(w), clock].\r\n */\r\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ResolveMarket (tag 19): 2 accounts.\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\r\n * `handle_resolve_market` at src/v16_program.rs:12269:\r\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\r\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\r\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\r\n * clock account, and never touches an oracle account at all.\r\n *\r\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\r\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\r\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\r\n * also admin-gated, market-level, no token movement — which is\r\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\r\n * when the program does not require it only widens the account's write lock.\r\n */\r\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\r\n * [0] authority signer, writable (insurance authority)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority's collateral ATA — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\r\n *\r\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\r\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\r\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\r\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\r\n * the handler does a same-instruction accrue_market_to against the fresh\r\n * oracle price to prevent withdrawals against overstated insurance.\r\n * On resolved markets the oracle is frozen — 7 accounts suffice.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"authorityAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\r\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UnpauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\r\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\r\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\r\n// (set_insurance_withdraw_policy), 6876 (update_authority).\r\n// ============================================================================\r\n\r\n/**\r\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10470.\r\n */\r\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SettleAccount (tag 26): 3 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10503.\r\n */\r\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\r\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\r\n * Owner only. No token movement (internal PnL-bucket conversion within the\r\n * same portfolio).\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\r\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\r\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\r\n * at src/v16_program.rs:17469, which reads:\r\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\r\n * [1] market writable — `expect_writable` + `expect_owner`\r\n * [2] portfolio writable — `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\r\n * is no clock account (the handler needs no slot) and no oracle account.\r\n *\r\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\r\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\r\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\r\n * portfolio rent — this instruction moves no lamports at all.\r\n *\r\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\r\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\r\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\r\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\r\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\r\n */\r\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\r\n * Wrapper: src/percolator.rs:9990.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\r\n * Wrapper: src/percolator.rs:6876.\r\n *\r\n * Both the current authority and the new authority must sign. For burn\r\n * (`new_pubkey == default()`) the new account is still passed but does\r\n * not need to sign per wrapper L7036 region.\r\n */\r\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"currentAuthority\", signer: true, writable: false },\r\n { name: \"newAuthority\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// ACCOUNT META BUILDERS\r\n// ============================================================================\r\n\r\n/**\r\n * Build AccountMeta array from spec and provided pubkeys.\r\n *\r\n * Accepts either:\r\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\r\n * - `Record` — named map keyed by account `name` (preferred form)\r\n *\r\n * Named-map form resolves accounts by spec name so callers don't have to\r\n * remember the positional order, and errors clearly on missing names.\r\n */\r\nexport function buildAccountMetas(\r\n spec: readonly AccountSpec[],\r\n keys: PublicKey[] | Record\r\n): AccountMeta[] {\r\n let keysArray: PublicKey[];\r\n\r\n if (Array.isArray(keys)) {\r\n keysArray = keys;\r\n } else {\r\n // Named map: resolve by spec name\r\n keysArray = spec.map((s) => {\r\n const key = (keys as Record)[s.name];\r\n if (!key) {\r\n throw new Error(\r\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\r\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\r\n );\r\n }\r\n return key;\r\n });\r\n }\r\n\r\n if (keysArray.length !== spec.length) {\r\n throw new Error(\r\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\r\n );\r\n }\r\n return spec.map((s, i) => ({\r\n pubkey: keysArray[i],\r\n isSigner: s.signer,\r\n isWritable: s.writable,\r\n }));\r\n}\r\n\r\n/**\r\n * CreateInsuranceMint: 9 accounts\r\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\r\n */\r\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"collateralMint\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"payer\", signer: true, writable: true },\r\n] as const;\r\n\r\n/**\r\n * DepositInsuranceLP: 8 accounts\r\n * Deposit collateral into insurance fund, receive LP tokens.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"depositorAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLP: 8 accounts\r\n * Burn LP tokens and withdraw proportional share of insurance fund.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\r\n *\r\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\r\n *\r\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\r\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\r\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\r\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\r\n *\r\n * Accounts:\r\n * [0] withdrawer signer, read-only\r\n * [1] slab writable\r\n * [2] withdrawerAta writable (collateral destination)\r\n * [3] vault writable (collateral source)\r\n * [4] tokenProgram read-only\r\n * [5] lpVaultMint writable (LP tokens burned from here)\r\n * [6] withdrawerLpAta writable (LP tokens source)\r\n * [7] vaultAuthority read-only (PDA that signs token transfers)\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\r\n */\r\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"creatorLockPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * FundMarketInsurance: 5 accounts (PERC-306)\r\n * Fund per-market isolated insurance balance.\r\n */\r\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceIsolation: 2 accounts (PERC-306)\r\n * Set max % of global fund this market can access.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal: 5 accounts (PERC-309)\r\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\r\n */\r\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"lpVaultState\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\r\n * Burns LP tokens and releases one epoch tranche of SOL.\r\n */\r\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\r\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\r\n */\r\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\r\n * Permissionless — surgically close/reduce the most profitable position\r\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\r\n * pass additional oracle accounts at accounts[4..].\r\n */\r\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs: 2 accounts (tag 51)\r\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\r\n */\r\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ReclaimSlabRent: 2 accounts (tag 52)\r\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\r\n */\r\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: true, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// AuditCrank (tag 53) — Permissionless invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank: 1 account (tag 53)\r\n * Permissionless. Verifies conservation invariants; pauses market on violation.\r\n */\r\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase: 1 account\r\n * Permissionless — no signer required beyond fee payer.\r\n */\r\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dexPool\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * CreateLpVault (tag 74): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\r\n * [0] admin signer, writable (marketauth — pays for PDA creation)\r\n * [1] market read-only (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\r\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\r\n * [4] systemProgram read-only (required for create_account CPI)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\r\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\r\n */\r\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositToLpVault (tag 75): 10 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\r\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] lpMint writable (LP share mint PDA)\r\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\r\n * [5] sourceToken writable (depositor's collateral ATA — source)\r\n * [6] vaultToken writable (program vault token account — destination)\r\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\r\n * [8] tokenProgram read-only\r\n * [9] systemProgram read-only (required for ledger create_account CPI)\r\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n *\r\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\r\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\r\n * and mints the depositor free shares at existing holders' expense. `ledger` at\r\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\r\n * which of the two actually receives the backing.\r\n *\r\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\r\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\r\n * ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\r\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n * [5] systemProgram read-only (required to create a missing target ledger)\r\n *\r\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\r\n * land in, and that pot's ledger is created on first use. Once deposits can be\r\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\r\n * so cranker had to become writable and the system program is now required.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\r\n *\r\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\r\n * carrying ledger principal in lockstep. No tokens move.\r\n *\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\r\n * destination ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry read-only (LpVaultRegistry PDA)\r\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\r\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\r\n * [5] systemProgram read-only\r\n */\r\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: false },\r\n { name: \"fromLedger\", signer: false, writable: true },\r\n { name: \"toLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"challenger\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"attestation\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8110: SetOiImbalanceHardBlock\r\n// ============================================================================\r\n\r\n/**\r\n * SetOiImbalanceHardBlock: 2 accounts\r\n * Sets the OI imbalance hard-block threshold (admin only)\r\n */\r\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-608: Position NFT Instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft: 10 accounts\r\n * Creates a Token-2022 position NFT for an open position.\r\n */\r\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TransferPositionOwnership: 8 accounts\r\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\r\n */\r\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\r\n { name: \"currentOwner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"currentOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwner\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * BurnPositionNft: 7 accounts\r\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\r\n */\r\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetPendingSettlement: 3 accounts\r\n * Keeper/admin sets pending_settlement flag before funding transfer.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ClearPendingSettlement: 3 accounts\r\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"nftProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8111: SetWalletCap\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap: 2 accounts\r\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\r\n */\r\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-SetDexPool: SetDexPool (tag 74)\r\n// ============================================================================\r\n\r\n/**\r\n * SetDexPool: 3 accounts\r\n * Admin pins the approved DEX pool address for a HYPERP market.\r\n * After this call, UpdateHyperpMark rejects any pool that does not match.\r\n */\r\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"poolAccount\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// InitMatcherCtx (tag 83) — v17 wire\r\n//\r\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\r\n// 83. The protocol-fee instructions below were renumbered to 84/85\r\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\r\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\r\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\r\n * [0] lpOwner signer (LP portfolio owner wallet)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\r\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\r\n * [4] matcherProg read-only, executable (the external matcher program)\r\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\r\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\r\n * calling the matcher CPI.\r\n *\r\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\r\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\r\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\r\n */\r\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\r\n *\r\n * Fixed accounts:\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned market account)\r\n *\r\n * Dynamic accounts [2..2+oracle_leg_count]:\r\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\r\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\r\n *\r\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\r\n] as const;\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\r\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushEwmaMark (tag 36): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\r\n */\r\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushAuthMark (tag 63): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\r\n */\r\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK B — SetMatcherConfig account spec (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\r\n * 6 accounts when enabling (enabled=1).\r\n *\r\n * [0] lpOwner signer (portfolio owner)\r\n * [1] market read-only (program-owned; owner-check only)\r\n * [2] lpPortfolio writable (program-owned portfolio)\r\n * [3] matcherProg read-only, executable (required when enabled=1 only)\r\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\r\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\r\n *\r\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\r\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\r\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\r\n */\r\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: true },\r\n // When enabled=1, also pass:\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee (tag 84): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\r\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\r\n * in the instruction data means \"withdraw all currently-available capacity\".\r\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\r\n * domain budgets; the protocol's claim is a separate, non-domain balance).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\r\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\r\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\r\n * seeds [program_id])\r\n * [2] market writable (program-owned market-group slab)\r\n *\r\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\r\n * authority — NOT marketauth, NOT insurance_authority, NOT any\r\n * creator-facing gate. No global fan-out: call once per market.\r\n */\r\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"upgradeAuthority\", signer: true, writable: false },\r\n { name: \"programData\", signer: false, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateFeeSplit (tag 86): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\r\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors the neighbouring marketauth-gated single-field setters\r\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\r\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\r\n *\r\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\r\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\r\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\r\n */\r\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_withdraw_insurance_reserve_to_stake):\r\n * [0] cranker signer (permissionless — any signer, pays fees only)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\r\n * wrapper's PINNED stake program id; its owner is\r\n * asserted BEFORE any byte is read — the forgery gate)\r\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\r\n * [4] vaultToken writable (this market's collateral vault token acct)\r\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\r\n * [6] tokenProgram read-only\r\n *\r\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\r\n * destination; percolator-stake's own AccrueFees is what later credits it.\r\n *\r\n * Failure codes are deliberately distinct so a keeper can tell the cases\r\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\r\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\r\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\r\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"stakePool\", signer: false, writable: false },\r\n { name: \"stakeVault\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\r\n * [0] admin signer (must match cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * ⚠ The instruction payload is a u128, not a u64. See\r\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\r\n */\r\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\r\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\r\n * cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\r\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\r\n * than by StakeInitPool; proxy is stake tag 28.\r\n *\r\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\r\n * the authority normally also being the fee payer. The program itself only\r\n * calls `expect_signer(authority)` — it never writes to this account.\r\n */\r\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\r\n * [0] market writable (program-owned market-group slab)\r\n *\r\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\r\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\r\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\r\n * instruction moves no tokens. The transaction still needs a fee payer, but\r\n * that signer is not an account of this instruction and is not checked against\r\n * anything.\r\n *\r\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\r\n * only by an authority that may be a cold key or a stake-pool PDA. The\r\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\r\n * against the runtime `Clock`), not an authority check. See\r\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\r\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\r\n * Custom(19) bucket not `Fresh`-and-lapsed.\r\n */\r\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee (tag 90): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\r\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\r\n * only the authority the program checks [0] against differs:\r\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account, owned by [0])\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\r\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\r\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\r\n * reflects the authority normally also being the transaction fee payer; the\r\n * program itself only calls expect_signer on it.\r\n *\r\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\r\n * does NOT accept marketauth as an alternate the way\r\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\r\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\r\n * pool claim the creator's revenue. It also means claiming keeps working after\r\n * StakeInitPool, since staking never rotates insurance_operator.\r\n *\r\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\r\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\r\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\r\n * from the loss backstop, so backstop gating does not apply).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\r\n// ============================================================================\r\n\r\nexport const WELL_KNOWN = {\r\n tokenProgram: TOKEN_PROGRAM_ID,\r\n clock: SYSVAR_CLOCK_PUBKEY,\r\n rent: SYSVAR_RENT_PUBKEY,\r\n systemProgram: SystemProgram.programId,\r\n} as const;\r\n","/**\r\n * Percolator v17 program error definitions.\r\n *\r\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\r\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\r\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\r\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\r\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\r\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\r\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\r\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\r\n *\r\n * Ordinals 0-61 read directly off the PercolatorError enum in\r\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\r\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\r\n * tentative\" TODO here is resolved.\r\n *\r\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\r\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Errors 0-29 have completely different names and semantics from v12.\r\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\r\n * - Errors 42-46 are NFT/B-3 (new in v17).\r\n * - v12.x errors 28-65 are entirely removed.\r\n */\r\nexport interface ErrorInfo {\r\n name: string;\r\n hint: string;\r\n}\r\n\r\nexport const PERCOLATOR_ERRORS: Record = {\r\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\r\n 0: {\r\n name: \"InvalidMagic\",\r\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\r\n },\r\n 1: {\r\n name: \"InvalidVersion\",\r\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\r\n },\r\n 2: {\r\n name: \"AlreadyInitialized\",\r\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\r\n },\r\n 3: {\r\n name: \"NotInitialized\",\r\n hint: \"Account is not initialized. Run InitMarket first.\",\r\n },\r\n 4: {\r\n name: \"InvalidAccountKind\",\r\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\r\n },\r\n 5: {\r\n name: \"InvalidAccountLen\",\r\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\r\n },\r\n 6: {\r\n name: \"ExpectedSigner\",\r\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\r\n },\r\n 7: {\r\n name: \"ExpectedWritable\",\r\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\r\n },\r\n 8: {\r\n name: \"Unauthorized\",\r\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\r\n },\r\n 9: {\r\n name: \"InvalidInstruction\",\r\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\r\n },\r\n 10: {\r\n name: \"InvalidMint\",\r\n hint: \"Token mint does not match the market's collateral mint.\",\r\n },\r\n 11: {\r\n name: \"InvalidTokenAccount\",\r\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\r\n },\r\n 12: {\r\n name: \"InvalidVaultAccount\",\r\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\r\n },\r\n 13: {\r\n name: \"InvalidTokenProgram\",\r\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\r\n },\r\n 14: {\r\n name: \"EngineInvalidConfig\",\r\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\r\n },\r\n 15: {\r\n name: \"EngineArithmeticOverflow\",\r\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\r\n },\r\n 16: {\r\n name: \"EngineProvenanceMismatch\",\r\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\r\n },\r\n 17: {\r\n name: \"EngineHiddenLeg\",\r\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\r\n },\r\n 18: {\r\n name: \"EngineInvalidLeg\",\r\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\r\n },\r\n 19: {\r\n name: \"EngineStale\",\r\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\r\n },\r\n 20: {\r\n name: \"EngineBStale\",\r\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\r\n },\r\n 21: {\r\n name: \"EngineLockActive\",\r\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\r\n },\r\n 22: {\r\n name: \"EngineNonProgress\",\r\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\r\n },\r\n 23: {\r\n name: \"EngineRecoveryRequired\",\r\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\r\n },\r\n 24: {\r\n name: \"EngineCounterOverflow\",\r\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\r\n },\r\n 25: {\r\n name: \"EngineCounterUnderflow\",\r\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\r\n },\r\n 26: {\r\n name: \"OracleInvalid\",\r\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\r\n },\r\n 27: {\r\n name: \"OracleStale\",\r\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\r\n },\r\n 28: {\r\n name: \"OracleConfTooWide\",\r\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\r\n },\r\n 29: {\r\n name: \"InvalidOracleKey\",\r\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\r\n },\r\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\r\n 30: {\r\n name: \"LpVaultAlreadyExists\",\r\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\r\n },\r\n 31: {\r\n name: \"LpVaultNotFound\",\r\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\r\n },\r\n 32: {\r\n name: \"LpVaultPaused\",\r\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\r\n },\r\n 33: {\r\n name: \"LpVaultSharesOutstanding\",\r\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\r\n },\r\n 34: {\r\n name: \"LpVaultZeroAmount\",\r\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\r\n },\r\n 35: {\r\n name: \"LpVaultInsufficientShares\",\r\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\r\n },\r\n 36: {\r\n name: \"LpVaultCooldownActive\",\r\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\r\n },\r\n 37: {\r\n name: \"LpVaultOiReservationViolated\",\r\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\r\n },\r\n 38: {\r\n name: \"LpVaultNoFeesToCrank\",\r\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\r\n },\r\n 39: {\r\n name: \"LpVaultSupplyMismatch\",\r\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\r\n },\r\n 40: {\r\n name: \"LpVaultAuthorityMismatch\",\r\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\r\n },\r\n 41: {\r\n name: \"LpVaultZeroSharesMinted\",\r\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\r\n },\r\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\r\n 42: {\r\n name: \"NftRegistryNotFound\",\r\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\r\n },\r\n 43: {\r\n name: \"NftPortfolioNotTransferable\",\r\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\r\n },\r\n 44: {\r\n name: \"NftTransferSelfOrZero\",\r\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\r\n },\r\n 45: {\r\n name: \"NftInvalidMintAuthority\",\r\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\r\n },\r\n 46: {\r\n name: \"NftPortfolioProvenance\",\r\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\r\n },\r\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\r\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\r\n 47: {\r\n name: \"InsuranceWithdrawCooldownActive\",\r\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\r\n },\r\n 48: {\r\n name: \"InsuranceWithdrawCeilingExceeded\",\r\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\r\n },\r\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\r\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\r\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\r\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\r\n // initial-margin failure, previously collapsed into the opaque\r\n // EngineInvalidConfig=14.\r\n 49: {\r\n name: \"EngineInsufficientInitialMargin\",\r\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\r\n },\r\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\r\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\r\n 50: {\r\n name: \"LpVaultDepositBelowMinimumLiquidity\",\r\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\r\n },\r\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\r\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\r\n // a3cb4390).\r\n //\r\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\r\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\r\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\r\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\r\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\r\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\r\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\r\n // EXACTLY and with no tolerance, against the bps floors below.\r\n 51: {\r\n name: \"FeeSplitFloorViolation\",\r\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\r\n },\r\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variants appended after\r\n // FeeSplitFloorViolation=51 on percolator-prog\r\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\r\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\r\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\r\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\r\n 52: {\r\n name: \"FeeSplitSumInvalid\",\r\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\r\n },\r\n 53: {\r\n name: \"NoInsuranceReserveToClaim\",\r\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\r\n },\r\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\r\n // Source: v16_program.rs, same branch. These seven previously ALL returned\r\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\r\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\r\n // destination-resolution now has its own code.\r\n //\r\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\r\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\r\n // removed. That variant existed only on an unmerged branch and was NEVER\r\n // deployed, so no on-chain consumer has ever observed the old meaning.\r\n 54: {\r\n name: \"StakePoolNotBound\",\r\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\r\n },\r\n 55: {\r\n name: \"StakePoolOwnerMismatch\",\r\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\r\n },\r\n 56: {\r\n name: \"StakePoolAuthorityMismatch\",\r\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\r\n },\r\n 57: {\r\n name: \"StakePoolMarketMismatch\",\r\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\r\n },\r\n 58: {\r\n name: \"StakePoolWrapperMismatch\",\r\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\r\n },\r\n 59: {\r\n name: \"StakePoolModeMismatch\",\r\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\r\n },\r\n 60: {\r\n name: \"StakeProgramNotPinned\",\r\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\r\n },\r\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\r\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n 61: {\r\n name: \"AssetSlotAlreadyConfigured\",\r\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\r\n },\r\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\r\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\r\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\r\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\r\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\r\n // wrapper this code is unreachable.\r\n 62: {\r\n name: \"CreatorFeeOverClaim\",\r\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\r\n },\r\n\r\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\r\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\r\n // slot 490057417, verified byte-identical.\r\n 63: {\r\n name: \"LpVaultBackingBucketNotEmpty\",\r\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\r\n },\r\n};\r\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\r\nObject.freeze(PERCOLATOR_ERRORS);\r\n\r\n/**\r\n * Decode a custom program error code to its info.\r\n *\r\n * @param code Custom error code from `custom program error: 0x`.\r\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\r\n */\r\nexport function decodeError(code: number): ErrorInfo | undefined {\r\n return PERCOLATOR_ERRORS[code];\r\n}\r\n\r\n/**\r\n * Get error name from code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\r\n */\r\nexport function getErrorName(code: number): string {\r\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\r\n}\r\n\r\n/**\r\n * Get actionable hint for error code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Actionable hint string, or undefined if not recognized.\r\n */\r\nexport function getErrorHint(code: number): string | undefined {\r\n return PERCOLATOR_ERRORS[code]?.hint;\r\n}\r\n\r\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\r\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\r\n\r\n/**\r\n * Parse a custom program error from transaction logs.\r\n *\r\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\r\n * Returns null if no custom error is found.\r\n *\r\n * @param logs Array of transaction log strings from the RPC response.\r\n * @returns Parsed error with code, name, and hint — or null if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\r\n * if (err) console.error(`${err.name}: ${err.hint}`);\r\n * ```\r\n */\r\nexport function parseErrorFromLogs(logs: string[]): {\r\n code: number;\r\n name: string;\r\n hint?: string;\r\n} | null {\r\n if (!Array.isArray(logs)) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\r\n \"i\",\r\n );\r\n for (const log of logs) {\r\n if (typeof log !== \"string\") {\r\n continue;\r\n }\r\n const match = log.match(re);\r\n if (match) {\r\n const code = parseInt(match[1], 16);\r\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\r\n continue;\r\n }\r\n const info = decodeError(code);\r\n return {\r\n code,\r\n name: info?.name ?? `Unknown(${code})`,\r\n hint: info?.hint,\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Standalone percolator-nft program SDK module.\r\n *\r\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\r\n * separate from the main Percolator program. It handles:\r\n * - MintPositionNft (tag 0)\r\n * - BurnPositionNft (tag 1)\r\n * - SettleFunding (tag 2)\r\n * - GetPositionValue (tag 3)\r\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\r\n * - EmergencyBurn (tag 5)\r\n *\r\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\r\n * PositionNft state : [\"position_nft\", portfolio_account, asset_index_u16_LE]\r\n * Mint authority : [\"mint_authority\"]\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\r\nimport { safeEnv } from \"../config/program-ids.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Program ID\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Allowlist of known NFT program addresses. */\r\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\r\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\r\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\r\n]);\r\n\r\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\r\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\r\n throw new Error(\r\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\r\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\r\n `Pass the programId argument explicitly to bypass env resolution.`,\r\n );\r\n}\r\n\r\n/**\r\n * The standalone percolator-nft program (TransferHook + mint authority).\r\n *\r\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\r\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\r\n * address while every other id in the SDK is devnet, so any consumer importing it built\r\n * transactions against a program that does not exist on devnet and failed late with\r\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\r\n * constant to work around it.\r\n */\r\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\r\n\r\nexport function getNftProgramId(): PublicKey {\r\n return NFT_PROGRAM_ID;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const NFT_IX_TAG = {\r\n MintPositionNft: 0,\r\n BurnPositionNft: 1,\r\n SettleFunding: 2,\r\n GetPositionValue: 3,\r\n ExecuteTransferHook: 4,\r\n EmergencyBurn: 5,\r\n RepairExtraMetas: 6,\r\n ReconcileBurnedNft: 7,\r\n} as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction encoders\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\r\nexport function encodeNftMint(assetIndex: number): Uint8Array {\r\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\r\n const buf = new Uint8Array(3);\r\n buf[0] = NFT_IX_TAG.MintPositionNft;\r\n buf.set(assetIndexBuf, 1);\r\n return buf;\r\n}\r\n\r\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\r\nexport function encodeNftBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\r\n}\r\n\r\n/** Encode SettleFunding (tag 2). Data: tag(1). */\r\nexport function encodeNftSettleFunding(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\r\n}\r\n\r\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\r\nexport function encodeNftEmergencyBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\r\n}\r\n\r\n/**\r\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\r\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\r\n * released) back to the recorded last holder, then closes the PositionNft PDA.\r\n */\r\nexport function encodeNftReconcile(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account meta templates\r\n// ---------------------------------------------------------------------------\r\n\r\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\r\n\r\n/**\r\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\r\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\r\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\r\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\r\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\r\n * `isSigner: undefined` and `isWritable: undefined` for every account\r\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\r\n * both to falsy, so EVERY account in the built instruction ends up\r\n * non-signer/read-only. The NFT program's own writable/signer checks then\r\n * reject the transaction (confirmed live against the deployed NFT program:\r\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\r\n * CPI — matching its `if !nft_pda.is_writable { return\r\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\r\n *\r\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\r\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\r\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\r\n * these arrays and working — the only prior working reference\r\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\r\n * bypassing the mismatch entirely.\r\n */\r\nexport function buildNftAccountMetas(\r\n spec: readonly AccountMeta[],\r\n keys: readonly PublicKey[],\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n if (keys.length !== spec.length) {\r\n throw new Error(\r\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\r\n );\r\n }\r\n return spec.map((code, i) => ({\r\n pubkey: keys[i],\r\n isSigner: code === \"s\" || code === \"sw\",\r\n isWritable: code === \"w\" || code === \"sw\",\r\n }));\r\n}\r\n\r\n/**\r\n * Account metas for MintPositionNft (tag 0). 12 accounts.\r\n *\r\n * 0. [signer, writable] payer / position owner\r\n * 1. [writable] PositionNft PDA (created)\r\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\r\n * 3. [writable] Owner's NFT ATA (created)\r\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [] Associated token account program\r\n * 8. [] System program\r\n * 9. [writable] ExtraAccountMetaList PDA\r\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\r\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\r\n *\r\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\r\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\r\n * writable and #10/#11 are required.\r\n */\r\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\r\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint,\r\n * PositionNft PDA and ExtraAccountMetaList rent)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint (supply → 0)\r\n * 3. [writable] Holder's NFT ATA (closed)\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n *\r\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\r\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\r\n */\r\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint\r\n * 3. [writable] Holder's NFT ATA\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n */\r\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for ReconcileBurnedNft (tag 7, #138). 7 accounts. Permissionless.\r\n *\r\n * 0. [writable] PositionNft PDA (closed)\r\n * 1. [] NFT mint (Token-2022 — supply must be 0)\r\n * 2. [writable] Portfolio account (escrow released to the last holder)\r\n * 3. [] Mint authority PDA (unwrap CPI signer)\r\n * 4. [] Per-market NftRegistry PDA\r\n * 5. [] Percolator wrapper program (unwrap CPI target)\r\n * 6. [writable] Recorded last-holder wallet (escrow + PDA-rent recipient)\r\n */\r\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\r\n \"w\", \"r\", \"w\", \"r\", \"r\", \"r\", \"w\",\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// PDA derivation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\nfunction u16Buf(value: number, label: string): Uint8Array {\r\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\r\n throw new Error(`${label} must be a u16`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, true);\r\n return buf;\r\n}\r\n\r\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\r\n const v = typeof value === \"bigint\" ? value : BigInt(value);\r\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\r\n throw new Error(`${label} must be a u64`);\r\n }\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, v, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive the PositionNft state PDA.\r\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n *\r\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\r\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\r\n * engine reuses across close/re-open of the same asset and which therefore\r\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\r\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\r\n * NFT's stored `marketIdAtMint` for any later op.\r\n */\r\nexport function deriveNftPda(\r\n portfolioAccount: PublicKey,\r\n marketId: bigint | number,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\r\n programId,\r\n );\r\n}\r\n\r\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\r\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\r\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\r\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\r\n\r\n/**\r\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\r\n */\r\nexport function deriveNftMint(\r\n _portfolioAccount: PublicKey,\r\n _assetIndex: number,\r\n _programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\r\n}\r\n\r\n/**\r\n * Derive the program-wide mint authority PDA.\r\n * Seeds: [\"mint_authority\"]\r\n */\r\nexport function deriveMintAuthority(\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"mint_authority\")],\r\n programId,\r\n );\r\n}\r\n\r\n/**\r\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\r\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\r\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\r\n * close it and refund its rent to the holder.\r\n */\r\nexport function deriveExtraAccountMetas(\r\n nftMint: PublicKey,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\r\n programId,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account parser\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\r\n *\r\n * [0..8] magic u64 (\"PERCNFT\\0\")\r\n * [8] version u8\r\n * [9] bump u8\r\n * [10..42] portfolio_account [u8; 32]\r\n * [42..74] nft_mint [u8; 32]\r\n * [74..78] asset_index u32 LE\r\n * [78] side_at_mint u8\r\n * [79..95] basis_pos_q_at_mint i128\r\n * [95..111] f_snap_at_mint i128\r\n * [111..119] market_id_at_mint u64\r\n * [119..127] epoch_snap_at_mint u64\r\n * [127..159] position_owner_at_mint [u8; 32]\r\n * [159..167] minted_at i64\r\n * [167..199] _reserved\r\n */\r\nexport const POSITION_NFT_STATE_LEN = 199;\r\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\r\nconst POSITION_NFT_VERSION = 2;\r\n\r\nexport interface PositionNftState {\r\n version: number;\r\n bump: number;\r\n portfolioAccount: PublicKey;\r\n nftMint: PublicKey;\r\n assetIndex: number;\r\n sideAtMint: number;\r\n basisPosQAtMint: bigint;\r\n fSnapAtMint: bigint;\r\n marketIdAtMint: bigint;\r\n epochSnapAtMint: bigint;\r\n positionOwnerAtMint: PublicKey;\r\n /** Backward-compatible alias for positionOwnerAtMint. */\r\n positionOwner: PublicKey;\r\n mintedAt: bigint;\r\n}\r\n\r\n/**\r\n * Read a little-endian signed i128 from a DataView at `offset`.\r\n *\r\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\r\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\r\n * value is set the result is negative and two's-complement sign extension is\r\n * applied explicitly.\r\n *\r\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\r\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\r\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\r\n * shifted high half collapses the sign bit into all high bits and corrupts the\r\n * result.\r\n *\r\n * @param view DataView wrapping the raw account bytes\r\n * @param offset Byte offset of the i128 field (little-endian)\r\n * @returns Signed BigInt in the range [-2^127, 2^127)\r\n */\r\nfunction readI128FromView(view: DataView, offset: number): bigint {\r\n const lo = view.getBigUint64(offset, true);\r\n const hi = view.getBigUint64(offset + 8, true);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Parse a PositionNft account from raw bytes.\r\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\r\n */\r\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\r\n if (data.length < POSITION_NFT_STATE_LEN) {\r\n throw new Error(\r\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\r\n );\r\n }\r\n\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n const magic = view.getBigUint64(0, true);\r\n if (magic !== POSITION_NFT_MAGIC) {\r\n throw new Error(\"PositionNft account has invalid magic\");\r\n }\r\n if (data[8] !== POSITION_NFT_VERSION) {\r\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\r\n }\r\n\r\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\r\n\r\n return {\r\n version: data[8],\r\n bump: data[9],\r\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\r\n nftMint: new PublicKey(data.subarray(42, 74)),\r\n assetIndex: view.getUint32(74, true),\r\n sideAtMint: data[78],\r\n basisPosQAtMint: readI128FromView(view, 79),\r\n fSnapAtMint: readI128FromView(view, 95),\r\n marketIdAtMint: view.getBigUint64(111, true),\r\n epochSnapAtMint: view.getBigUint64(119, true),\r\n positionOwnerAtMint,\r\n positionOwner: positionOwnerAtMint,\r\n mintedAt: view.getBigInt64(159, true),\r\n };\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\n/**\r\n * Read an environment variable safely. Returns `undefined` in browser\r\n * environments where `process` is not defined, avoiding a\r\n * `ReferenceError` crash at import time.\r\n */\r\nexport function safeEnv(key: string): string | undefined {\r\n try {\r\n return typeof process !== \"undefined\" && process?.env\r\n ? process.env[key]\r\n : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Centralized PROGRAM_ID configuration\r\n * \r\n * Default to environment variable, then fall back to network-specific defaults.\r\n * This prevents hard-coded program IDs scattered across the codebase.\r\n */\r\n\r\nexport const PROGRAM_IDS = {\r\n devnet: {\r\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\r\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\r\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n },\r\n mainnet: {\r\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\r\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\r\n },\r\n} as const;\r\nObject.freeze(PROGRAM_IDS.devnet);\r\nObject.freeze(PROGRAM_IDS.mainnet);\r\nObject.freeze(PROGRAM_IDS);\r\n\r\n/**\r\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\r\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\r\n * and upgraded in place at the same address).\r\n *\r\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\r\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\r\n * markets — they were not migrated in place, so anything still pointed at them\r\n * (e.g. the percolator-launch playground config, which hardcodes its own program\r\n * ID rather than reading this module) keeps working against the old markets until\r\n * it is explicitly cut over to this fresh triple. That playground cutover is a\r\n * separate, later step — NOT performed by this change.\r\n */\r\nexport const PROGRAM_IDS_V17 = {\r\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\r\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\r\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\r\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\r\n} as const;\r\nObject.freeze(PROGRAM_IDS_V17);\r\n\r\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\r\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\r\n\r\nexport type Network = \"devnet\" | \"mainnet\";\r\n\r\n/** Allowlist of legitimate percolator program addresses (all networks). */\r\nconst KNOWN_PROGRAM_IDS = new Set([\r\n PROGRAM_IDS.devnet.percolator,\r\n PROGRAM_IDS.mainnet.percolator,\r\n PROGRAM_IDS_V17.percolator,\r\n]);\r\n\r\n/** Allowlist of legitimate matcher program addresses (all networks). */\r\nconst KNOWN_MATCHER_IDS = new Set([\r\n PROGRAM_IDS.devnet.matcher,\r\n PROGRAM_IDS.mainnet.matcher,\r\n]);\r\n\r\n/**\r\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\r\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\r\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\r\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\r\n * during pre-deploy / devnet testing — which the allowlist alone would break.\r\n */\r\nfunction programOverrideOptIn(): boolean {\r\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\r\n}\r\n\r\n/**\r\n * Get the Percolator program ID for the current network\r\n * \r\n * Priority:\r\n * 1. PROGRAM_ID env var (explicit override)\r\n * 2. Network-specific default (NETWORK env var)\r\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\r\n */\r\nexport function getProgramId(network?: Network): PublicKey {\r\n // #249: an explicit `network` argument is authoritative and must NOT be silently\r\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\r\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\r\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\r\n if (network === undefined) {\r\n const override = safeEnv(\"PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\r\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].percolator;\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the Matcher program ID for the current network\r\n */\r\nexport function getMatcherProgramId(network?: Network): PublicKey {\r\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\r\n if (network === undefined) {\r\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\r\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].matcher;\r\n\r\n if (!programId) {\r\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\r\n }\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the current network from environment.\r\n *\r\n * SECURITY (PERC-697): Removed silent mainnet default.\r\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\r\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\r\n *\r\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\r\n * Production deployments always set NETWORK explicitly via Railway/env.\r\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\r\n * enforces FORCE_MAINNET=1.\r\n */\r\nexport function getCurrentNetwork(): Network {\r\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\r\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\r\n return \"mainnet\";\r\n }\r\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\r\n return \"devnet\";\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\n\r\n// =============================================================================\r\n// Browser-compatible read helpers using DataView\r\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\r\n// =============================================================================\r\n\r\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\n/** Read a single unsigned byte at `off`. */\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n if (off >= data.length) {\r\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\r\n }\r\n return data[off];\r\n}\r\n/** Read a little-endian u16 at `off`. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\n/** Read a little-endian u32 at `off`. */\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint32(off, true);\r\n}\r\n/** Read a little-endian u64 at `off` as a BigInt. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\n/** Read a little-endian signed i64 at `off` as a BigInt. */\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\n\r\n// =============================================================================\r\n// Helper: read signed/unsigned i128 from buffer\r\n// =============================================================================\r\n\r\n/**\r\n * Read a little-endian signed i128 at `offset`.\r\n * Composed from two u64 halves; sign-extends if the high bit is set.\r\n */\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// =============================================================================\r\n// Slab Layout Version Detection\r\n// =============================================================================\r\n// The deployed devnet program uses a different struct layout (V0) than the SDK\r\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\r\n// struct changes that have NOT been deployed to devnet yet.\r\n//\r\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\r\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\r\n// - RiskParams: 56 bytes (basic fields only)\r\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\r\n// - No partial liquidation field in Account (240 bytes)\r\n//\r\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\r\n// - InsuranceFund: expanded with isolation fields (72 bytes)\r\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\r\n// - Has mark_price, long_oi/short_oi, emergency fields\r\n// - Account has last_partial_liquidation_slot (248 bytes)\r\n// =============================================================================\r\n\r\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\r\n\r\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\r\nexport const SLAB_MAGIC = MAGIC;\r\n\r\n// Flag bits in header._padding[0] at offset 13\r\nconst FLAG_RESOLVED = 1 << 0;\r\n\r\n/**\r\n * Full slab layout descriptor. Returned by detectSlabLayout().\r\n * All engine field offsets are relative to engineOff.\r\n */\r\nexport interface SlabLayout {\r\n version: 0 | 1 | 2;\r\n headerLen: number;\r\n configOffset: number;\r\n configLen: number;\r\n reservedOff: number; // offset of _reserved in header\r\n engineOff: number;\r\n accountSize: number;\r\n maxAccounts: number;\r\n bitmapWords: number;\r\n accountsOff: number; // absolute offset of accounts array in slab\r\n\r\n // Engine field offsets (relative to engineOff)\r\n engineInsuranceOff: number;\r\n engineParamsOff: number;\r\n paramsSize: number;\r\n engineCurrentSlotOff: number;\r\n engineFundingIndexOff: number;\r\n engineLastFundingSlotOff: number;\r\n engineFundingRateBpsOff: number;\r\n engineMarkPriceOff: number; // -1 if not present (V0)\r\n engineLastCrankSlotOff: number;\r\n engineMaxCrankStalenessOff: number;\r\n engineTotalOiOff: number;\r\n engineLongOiOff: number; // -1 if not present (V0)\r\n engineShortOiOff: number; // -1 if not present (V0)\r\n engineCTotOff: number;\r\n enginePnlPosTotOff: number;\r\n engineLiqCursorOff: number;\r\n engineGcCursorOff: number;\r\n engineLastSweepStartOff: number;\r\n engineLastSweepCompleteOff: number;\r\n engineCrankCursorOff: number;\r\n engineSweepStartIdxOff: number;\r\n engineLifetimeLiquidationsOff: number;\r\n engineLifetimeForceClosesOff: number;\r\n engineNetLpPosOff: number;\r\n engineLpSumAbsOff: number;\r\n engineLpMaxAbsOff: number;\r\n engineLpMaxAbsSweepOff: number;\r\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\r\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\r\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\r\n engineBitmapOff: number; // relative to engineOff\r\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\r\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\r\n\r\n // Insurance fund layout\r\n hasInsuranceIsolation: boolean;\r\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\r\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\r\n\r\n // Optional fallback for engines without a stored mark_price field (v12.17+):\r\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\r\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\r\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\r\n // predate v12.17 and already expose a real engine.mark_price.\r\n configMarkEwmaOff?: number;\r\n}\r\n\r\n// ---- V0 layout constants (deployed devnet program) ----\r\nconst V0_HEADER_LEN = 72;\r\nconst V0_CONFIG_LEN = 408;\r\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\r\nconst V0_ACCOUNT_SIZE = 240;\r\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\r\n\r\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\r\n// V0 RiskParams: 56 bytes → runtime state at 104\r\nconst V0_ENGINE_PARAMS_OFF = 48;\r\nconst V0_PARAMS_SIZE = 56;\r\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\r\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\r\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\r\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\r\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\r\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\r\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\r\nconst V0_ENGINE_C_TOT_OFF = 176;\r\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\r\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\r\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\r\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\r\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\r\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\r\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\r\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\r\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\r\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\r\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\r\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\r\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\r\nconst V0_ENGINE_BITMAP_OFF = 320;\r\n\r\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\r\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\r\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\r\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\r\nconst V1_HEADER_LEN = 104;\r\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\r\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\r\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\r\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\r\nconst V1_ENGINE_OFF_LEGACY = 640;\r\nconst V1_ACCOUNT_SIZE = 248;\r\nconst V1_RESERVED_OFF = 80;\r\n\r\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\r\n// V1 RiskParams: 288 bytes → runtime state at 360\r\nconst V1_ENGINE_PARAMS_OFF = 72;\r\nconst V1_PARAMS_SIZE = 288;\r\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\r\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\r\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\r\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\r\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\r\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\r\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\r\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\r\nconst V1_ENGINE_LONG_OI_OFF = 456;\r\nconst V1_ENGINE_SHORT_OI_OFF = 472;\r\nconst V1_ENGINE_C_TOT_OFF = 488;\r\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\r\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\r\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\r\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\r\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\r\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\r\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\r\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\r\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\r\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\r\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\r\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\r\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\r\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\r\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\r\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\r\nconst V1_ENGINE_BITMAP_OFF = 656;\r\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\r\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\r\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\r\n// These corrected values must be used for actual byte-level parsing.\r\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\r\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\r\n\r\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\r\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\r\n// Key differences:\r\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\r\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\r\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\r\n// - Bitmap at engine+624 (not 656)\r\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\r\nconst V1D_CONFIG_LEN = 320;\r\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\r\nconst V1D_ACCOUNT_SIZE = 248;\r\n\r\n// V1D engine field offsets (relative to engineOff):\r\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\r\nconst V1D_ENGINE_INSURANCE_OFF = 16;\r\nconst V1D_ENGINE_PARAMS_OFF = 96;\r\nconst V1D_PARAMS_SIZE = 288;\r\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\r\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\r\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\r\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\r\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\r\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\r\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\r\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\r\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\r\nconst V1D_ENGINE_LONG_OI_OFF = 480;\r\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\r\nconst V1D_ENGINE_C_TOT_OFF = 512;\r\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\r\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\r\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\r\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\r\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\r\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\r\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\r\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\r\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\r\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\r\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\r\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\r\nconst V1D_ENGINE_BITMAP_OFF = 624;\r\n\r\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\r\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\r\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\r\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\r\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\r\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\r\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\r\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\r\nconst V2_HEADER_LEN = 104;\r\nconst V2_CONFIG_LEN = 496;\r\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\r\nconst V2_ACCOUNT_SIZE = 248;\r\nconst V2_ENGINE_BITMAP_OFF = 432;\r\n\r\n// V2 engine field offsets (relative to engineOff)\r\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\r\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\r\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\r\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\r\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\r\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\r\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\r\nconst V2_ENGINE_C_TOT_OFF = 424;\r\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\r\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\r\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\r\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\r\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\r\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\r\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\r\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\r\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\r\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\r\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\r\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\r\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\r\n\r\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\r\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\r\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\r\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\r\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\r\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\r\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\r\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\r\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\r\n//\r\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\r\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\r\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\r\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\r\n// Prior value of 1006 was an arithmetic transcription error.\r\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\r\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\r\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\r\n\r\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\r\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\r\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\r\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\r\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\r\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\r\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\r\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\r\n\r\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\r\nconst V_ADL_PARAMS_SIZE = 336;\r\n\r\n// V_ADL engine field offsets (relative to engineOff=624):\r\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\r\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\r\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\r\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\r\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\r\n// PERC-8270 new fields at 472-504:\r\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\r\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\r\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\r\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\r\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\r\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\r\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\r\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\r\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\r\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\r\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\r\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\r\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\r\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\r\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\r\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\r\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\r\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\r\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\r\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\r\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\r\n// ADL side state (PERC-8268, 224 bytes):\r\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\r\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\r\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\r\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\r\n// Then LP aggregates:\r\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\r\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\r\n// emergency fields:\r\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\r\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\r\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\r\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\r\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\r\n\r\n// V_ADL account field offsets (relative to account slot start):\r\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\r\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\r\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\r\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\r\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\r\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\r\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\r\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\r\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\r\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\r\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\r\n\r\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\r\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\r\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\r\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\r\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\r\n// dynamic fee tiers, fee splits).\r\n// Engine field ordering completely reorganized from V_ADL.\r\n// All values verified by cargo build-sbf compile-time assertions.\r\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\r\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\r\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\r\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\r\n// Those fields exist in percolator-core but NOT in the deployed binary.\r\n//\r\n// HOST constants below are for aarch64 test builds (percolator-core).\r\n// SBF constants are for the actual deployed program.\r\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\r\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\r\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\r\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\r\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\r\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\r\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\r\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\r\nconst V12_1_ENGINE_PARAMS_OFF = 96;\r\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\r\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\r\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\r\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\r\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\r\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\r\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\r\nconst V12_1_SBF_OFF_C_TOT = 248;\r\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\r\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\r\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\r\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\r\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\r\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\r\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\r\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\r\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\r\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\r\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\r\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\r\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\r\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\r\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\r\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\r\n// Bitmap (used field): 584\r\n// Fields NOT present in deployed program (return -1):\r\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\r\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\r\n//\r\n// HOST engine field offsets (percolator-core, for test builds):\r\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\r\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\r\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\r\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\r\nconst V12_1_ENGINE_C_TOT_OFF = 480;\r\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\r\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\r\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\r\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\r\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\r\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\r\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\r\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\r\n// HOST-only fields (percolator-core has these, deployed percolator does not):\r\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\r\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\r\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\r\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\r\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\r\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\r\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\r\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\r\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\r\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\r\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\r\n// V12_1 account field offsets (relative to account slot start):\r\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\r\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\r\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\r\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\r\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\r\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\r\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\r\n\r\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\r\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\r\n// SBF layout (u128 align=8):\r\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\r\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\r\n// → fees_earned_total(@272) = 288 bytes\r\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\r\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\r\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\r\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\r\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\r\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\r\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\r\n\r\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\r\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\r\n// explicitly sized, no pointer-derived alignment differences).\r\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\r\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\r\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\r\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\r\n// overflow_newest_present(u8@4384).\r\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\r\n// Field max_accounts moved to offset 24, insurance_floor at 144.\r\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\r\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\r\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\r\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\r\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\r\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\r\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\r\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\r\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\r\n\r\n// V12_15 account field offsets (relative to account slot start):\r\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\r\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\r\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\r\nconst V12_15_ACCT_PNL_OFF = 32; // i128\r\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\r\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\r\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\r\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\r\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\r\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\r\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\r\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\r\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\r\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\r\n\r\n// V12_15 RiskParams offsets (relative to params base):\r\n// sizeof(RiskParams) = 192\r\nconst V12_15_PARAMS_SIZE = 192;\r\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\r\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\r\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\r\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\r\n\r\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\r\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\r\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\r\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\r\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\r\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\r\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\r\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\r\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\r\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\r\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\r\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\r\nconst V12_15_ENGINE_BITMAP_OFF = 862;\r\n\r\n// V12_15 size map for layout detection\r\nconst V12_15_SIZES = new Map();\r\n\r\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\r\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\r\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\r\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\r\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\r\n// pending_present/remaining_q/horizon/created_slot.\r\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\r\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\r\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\r\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\r\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\r\n\r\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\r\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\r\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\r\n// _new_fields_pad, pending_admin[32]).\r\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\r\n// size_of::() = 512 (both native and SBF — u128 fields happen\r\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\r\n\r\n// Native (i128 align=16)\r\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\r\nconst V12_17_ACCOUNT_SIZE = 368;\r\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\r\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\r\nconst V12_17_RISK_BUF_LEN = 160;\r\n// Per-account generation table appended after RISK_BUF in percolator-prog.\r\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\r\nconst V12_17_GEN_TABLE_ENTRY = 8;\r\n\r\n// SBF (i128 align=8)\r\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\r\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\r\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\r\n\r\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\r\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\r\nconst V12_17_ACCT_KIND_OFF = 16; // u8\r\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\r\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\r\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\r\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\r\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\r\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\r\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\r\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\r\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\r\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\r\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\r\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\r\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\r\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\r\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\r\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\r\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\r\n\r\n// V12_17 RiskEngine field offsets (native, relative to engine start)\r\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\r\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\r\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\r\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\r\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\r\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\r\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\r\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\r\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\r\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\r\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\r\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\r\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\r\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\r\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\r\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\r\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\r\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\r\n\r\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\r\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\r\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\r\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\r\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\r\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\r\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\r\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\r\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\r\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\r\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\r\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\r\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\r\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_17 size map for layout detection\r\nconst V12_17_SIZES = new Map();\r\n\r\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\r\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\r\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\r\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\r\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\r\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\r\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\r\nconst V1M_ACCOUNT_SIZE = 248;\r\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\r\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\r\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\r\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\r\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\r\n\r\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\r\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\r\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\r\n// min_nonzero_im_req(u128=16) = +48 total\r\nconst V1M_PARAMS_SIZE = 336;\r\n\r\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\r\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\r\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\r\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\r\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\r\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\r\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\r\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\r\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\r\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\r\nconst V1M_ENGINE_LONG_OI_OFF = 504;\r\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\r\nconst V1M_ENGINE_C_TOT_OFF = 536;\r\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\r\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\r\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\r\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\r\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\r\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\r\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\r\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\r\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\r\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\r\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\r\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\r\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\r\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\r\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\r\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\r\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\r\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\r\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\r\n// which is invalid for a [u64; N] array under #[repr(C)].\r\nconst V1M_ENGINE_BITMAP_OFF = 720;\r\n\r\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\r\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\r\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\r\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\r\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\r\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\r\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\r\n// New runtime fields inserted between fundingRateBps and markPrice:\r\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\r\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\r\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\r\n// +504: lastCrankSlot, +512: maxCrankStaleness\r\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\r\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\r\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\r\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\r\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\r\n\r\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\r\n// (used by reinit-slab and other scripts). These refer to V1 layout.\r\nexport const ENGINE_OFF = V1_ENGINE_OFF;\r\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\r\n\r\n// ---- Known slab sizes per version and tier ----\r\n\r\n/**\r\n * Compute the total byte size of a slab given its layout parameters.\r\n * Used to pre-populate the known-size lookup maps at module load time.\r\n */\r\nfunction computeSlabSize(\r\n engineOff: number,\r\n bitmapOff: number,\r\n accountSize: number,\r\n maxAccounts: number,\r\n // postBitmap bytes immediately after the free-slot bitmap:\r\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\r\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\r\n postBitmap = 18,\r\n): number {\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return engineOff + accountsOff + maxAccounts * accountSize;\r\n}\r\n\r\nconst TIERS = [64, 256, 1024, 4096] as const;\r\n\r\n// Pre-compute known slab sizes for fast lookup\r\nconst V0_SIZES = new Map();\r\nconst V1_SIZES = new Map();\r\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\r\nconst V1_SIZES_LEGACY = new Map();\r\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\r\nconst V1D_SIZES = new Map();\r\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\r\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\r\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\r\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\r\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\r\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\r\nconst V2_SIZES = new Map();\r\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\r\nconst V1M_SIZES = new Map();\r\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\nconst V_ADL_SIZES = new Map();\r\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\r\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n// No disambiguation probe required — size-based detection works correctly.\r\nconst V1M2_SIZES = new Map();\r\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\r\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\r\nconst V_SETDEXPOOL_SIZES = new Map();\r\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\r\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\r\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\r\nconst V12_1_SIZES = new Map();\r\nconst V1D_SIZES_LEGACY = new Map();\r\nfor (const n of TIERS) {\r\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\r\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\r\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\r\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\r\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\r\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\r\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\r\n // Disambiguation requires peeking at the version field in the slab header.\r\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\r\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\r\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\r\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\r\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\r\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\r\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\r\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\r\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\r\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\r\n // e.g. n=4096 → 1288336 bytes.\r\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\r\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\r\n // Register BOTH host-computed and SBF-empirical sizes for detection.\r\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\r\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\r\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\r\n}\r\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\r\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\r\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\r\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\r\n\r\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\r\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\r\n// SBF: Account align=8 → accountsOff alignment is 8.\r\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\r\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\r\nconst V12_17_TIERS = [256, 1024, 4096] as const;\r\nfor (const n of V12_17_TIERS) {\r\n const bitmapWords = Math.ceil(n / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = n * 2;\r\n\r\n // Native (i128 align=16, Account align=16)\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(nativeSize, n);\r\n\r\n // SBF (i128 align=8, Account align=8)\r\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\r\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(sbfSize, n);\r\n}\r\n\r\n// ---- V12_19 layout constants ----\r\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\r\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\r\n// below comes from a Rust compile-error message that revealed the real SBF\r\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\r\n//\r\n// V12_19 vs V12_17 SBF differences:\r\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\r\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\r\n// - ENGINE_OFF: 584 -> 616\r\n// - ACCOUNT_SIZE: 352 -> 360\r\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\r\n// - RiskEngine grew substantially; accounts now inline within engine struct.\r\nconst V12_19_HEADER_LEN_SBF = 136;\r\nconst V12_19_CONFIG_LEN = 480;\r\nconst V12_19_ENGINE_OFF_SBF = 616;\r\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\r\nconst V12_19_SBF_RISK_BUF_LEN = 160;\r\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\r\n\r\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\r\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\r\n// MAX_ACCOUNTS; small (256) shown here.\r\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\r\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\r\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\r\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\r\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\r\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\r\n\r\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\r\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\r\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\r\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\r\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\r\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\r\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\r\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\r\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\r\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\r\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\r\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\r\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\r\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\r\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\r\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\r\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\r\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\r\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\r\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\r\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\r\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\r\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\r\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\r\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\r\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\r\n\r\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\r\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\r\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\r\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\r\n// + (8-byte align pad) + N*360 (accounts).\r\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\r\n// (mainnet probe-confirmed), medium=376432, large=1495024.\r\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\r\nconst V12_19_SIZES = new Map([\r\n [26872, 64], // --features micro (derived)\r\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\r\n [376432, 1024], // --features medium (derived)\r\n [1495024, 4096], // default features / large (derived)\r\n]);\r\n\r\n/**\r\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\r\n *\r\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\r\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\r\n * 736 area to same offset but the post-bitmap region now contains both\r\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\r\n * before the inline accounts.\r\n *\r\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\r\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\r\n * linearly with MAX_ACCOUNTS.\r\n */\r\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\r\n // Compute layout-dependent offsets for this tier.\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\r\n const freeHeadOff = numUsedOff + 2; // after num_used u16\r\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\r\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\r\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\r\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\r\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\r\n\r\n // Inherit Account-internal field offsets from V12_17 (they're the same since\r\n // the Account struct definition is identical between v12.17 and v12.19;\r\n // the +8 byte size diff is from trailing padding, not field reordering).\r\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\r\n\r\n return {\r\n ...base,\r\n headerLen: V12_19_HEADER_LEN_SBF,\r\n configLen: V12_19_CONFIG_LEN,\r\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\r\n engineOff: V12_19_ENGINE_OFF_SBF,\r\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\r\n accountsOff,\r\n bitmapWords,\r\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\r\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\r\n // V12_19-specific engine field offsets (probe-confirmed):\r\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\r\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\r\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\r\n // last_market_slot replaces V12_17 last_crank_slot semantics.\r\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\r\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\r\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\r\n };\r\n}\r\n\r\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\r\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\r\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\r\n// Bitmap at engine+584 (used field in RiskEngine).\r\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\r\nconst V12_1_SBF_ENGINE_OFF = 616;\r\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\r\n V12_1_SIZES.set(total, n);\r\n}\r\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\r\nconst V12_1_EP_SIZES = new Map();\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\r\n V12_1_EP_SIZES.set(total, n);\r\n}\r\n\r\n/**\r\n * V2 slab tier sizes (small and large) for discovery.\r\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\r\n */\r\nexport const SLAB_TIERS_V2 = Object.freeze({\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\r\n} as const);\r\n\r\n/**\r\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\r\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\r\n */\r\nexport const SLAB_TIERS_V1M: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M);\r\n\r\n/**\r\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\r\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\r\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\r\n */\r\nexport const SLAB_TIERS_V1M2: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M2);\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\r\n */\r\nexport const SLAB_TIERS_V_ADL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_ADL);\r\n\r\n/**\r\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\r\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\r\n */\r\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\r\n const isV0 = version === 0;\r\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\r\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\r\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\r\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\r\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\r\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\r\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\r\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\r\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\r\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\r\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version,\r\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\r\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\r\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\r\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: actualBitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: !isV0,\r\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\r\n * Uses correct field offsets derived from on-chain probing.\r\n *\r\n * @param maxAccounts - Number of account slots in the slab\r\n * @param postBitmap - Bytes after the bitmap before next_free array.\r\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\r\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\r\n */\r\n/**\r\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\r\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\r\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\r\n */\r\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\r\n const engineOff = V1D_ENGINE_OFF;\r\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\r\n const accountSize = V1D_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1D_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\r\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\r\n paramsSize: V1D_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: -1, // not present in deployed V1\r\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\r\n engineEmergencyOiModeOff: -1, // not present in deployed V1\r\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\r\n engineLastBreakerSlotOff: -1, // not present in deployed V1\r\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\r\n postBitmap,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\r\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V2 (BPF intermediate layout).\r\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\r\n */\r\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\r\n const engineOff = V2_ENGINE_OFF;\r\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\r\n const accountSize = V2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V2_HEADER_LEN,\r\n configOffset: V2_HEADER_LEN,\r\n configLen: V2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\r\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\r\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: -1, // V2 has no mark_price\r\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: -1, // V2 has no long_oi\r\n engineShortOiOff: -1, // V2 has no short_oi\r\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\r\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\r\n * and trade_twap runtime fields push the bitmap to offset 726.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\r\n */\r\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M_ENGINE_OFF;\r\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\r\n paramsSize: V1M_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\r\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\r\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\r\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\r\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\r\n */\r\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M2_ENGINE_OFF;\r\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\r\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n *\r\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\r\n * large (4096 accounts): 1288320 bytes\r\n * medium (1024 accounts): 323320 bytes\r\n * small (256 accounts): 82064 bytes\r\n */\r\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\r\n const engineOff = V_ADL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_ADL_CONFIG_LEN, // 520\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\r\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\r\n * e.g. large (4096 accts) = 1288336 bytes.\r\n */\r\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\r\n\r\n/**\r\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\r\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\r\n * Verified by cargo build-sbf compile-time assertions.\r\n */\r\nexport const SLAB_TIERS_V12_1: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_1);\r\n\r\n/**\r\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\r\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\r\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\r\n * Account layout completely redesigned with reserve cohort arrays.\r\n */\r\nexport const SLAB_TIERS_V12_15: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_15);\r\n\r\n/**\r\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\r\n * Uses SBF sizes (on-chain layout) for the dataSize values.\r\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\r\n * RISK_BUF_LEN=160 appended after engine.\r\n * Supported tiers: small(256), medium(1024), large(4096).\r\n */\r\nexport const SLAB_TIERS_V12_17: Record = {};\r\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\r\n const accountsOff = Math.ceil(preAcc / 8) * 8;\r\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_17);\r\n\r\n/**\r\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\r\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\r\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\r\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\r\n * fall through to the memcmp fallback path with no layout hint.\r\n *\r\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\r\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\r\n * exports consumed by discovery.ts.\r\n */\r\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\r\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\r\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\r\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\r\n});\r\n\r\n/**\r\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\r\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\r\n * All engine and account field offsets are identical to V_ADL.\r\n */\r\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\r\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\r\n paramsSize: V_ADL_PARAMS_SIZE,\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF vs host detection via size comparison.\r\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\r\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\r\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\r\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\r\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\r\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\r\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: isSbf ? 544 : 576,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\r\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\r\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\r\n // Fields that don't exist in the deployed program are set to -1 on SBF.\r\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\r\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\r\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\r\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\r\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\r\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\r\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\r\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\r\n\r\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\r\n // No isolated_balance or insurance_isolation_bps fields.\r\n hasInsuranceIsolation: !isSbf,\r\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\r\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\r\n */\r\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\r\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\r\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\r\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: 72,\r\n configOffset: 72,\r\n configLen: 544,\r\n reservedOff: 80, // V1_RESERVED_OFF\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\r\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\r\n // Engine offsets identical to V12_1 SBF\r\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\r\n engineFundingIndexOff: -1,\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\r\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\r\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\r\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\r\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\r\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\r\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\r\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\r\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\r\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\r\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\r\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\r\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\r\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\r\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\r\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\r\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\r\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\r\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\r\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\r\n *\r\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\r\n */\r\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\r\n const isSbf = dataLen === 237512;\r\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\r\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\r\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\r\n // SBF small has different bitmap/accounts offsets due to u128 align=8\r\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: 552, // SBF CONFIG_LEN for v12.15\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\r\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\r\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\r\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\r\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\r\n engineMarkPriceOff: -1, // not present in v12.15\r\n engineLastCrankSlotOff: -1, // not yet mapped\r\n engineMaxCrankStalenessOff: -1, // not yet mapped\r\n engineTotalOiOff: -1, // not present in v12.15 engine\r\n engineLongOiOff: -1, // not present in v12.15 engine\r\n engineShortOiOff: -1, // not present in v12.15 engine\r\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\r\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\r\n engineLiqCursorOff: -1, // not yet mapped\r\n engineGcCursorOff: -1, // not yet mapped\r\n engineLastSweepStartOff: -1, // not yet mapped\r\n engineLastSweepCompleteOff: -1, // not yet mapped\r\n engineCrankCursorOff: -1, // not yet mapped\r\n engineSweepStartIdxOff: -1, // not yet mapped\r\n engineLifetimeLiquidationsOff: -1, // not yet mapped\r\n engineLifetimeForceClosesOff: -1, // not present in v12.15\r\n engineNetLpPosOff: -1, // not present in v12.15\r\n engineLpSumAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\r\n engineEmergencyOiModeOff: -1, // not present in v12.15\r\n engineEmergencyStartSlotOff: -1, // not present in v12.15\r\n engineLastBreakerSlotOff: -1, // not present in v12.15\r\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\r\n postBitmap,\r\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\r\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\r\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\r\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\r\n * RISK_BUF_LEN=160 appended after engine.\r\n */\r\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\r\n // Detect SBF vs native from account size and engine offset.\r\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\r\n const isSbf = (() => {\r\n // Compute expected native size for this tier\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\r\n return dataLen !== nativeSize;\r\n })();\r\n\r\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\r\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\r\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const acctAlign = isSbf ? 8 : 16;\r\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\r\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\r\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\r\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\r\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\r\n configLen: 512,\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : 192,\r\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\r\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\r\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: -1,\r\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\r\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\r\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: -1, // removed in v12.17\r\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: -1,\r\n engineLastSweepCompleteOff: -1,\r\n engineCrankCursorOff: -1,\r\n engineSweepStartIdxOff: -1,\r\n engineLifetimeLiquidationsOff: -1,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap,\r\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n\r\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\r\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\r\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\r\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\r\n // so absolute offset in the slab is 72 + 304 = 376.\r\n configMarkEwmaOff: V0_HEADER_LEN + 304,\r\n };\r\n}\r\n\r\n/**\r\n * Detect the slab layout version from the raw account data length.\r\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\r\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\r\n *\r\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\r\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\r\n * V2 slabs have version===2 at offset 8 (u32 LE).\r\n *\r\n * @param dataLen - The slab account data length in bytes\r\n * @param data - Optional raw slab data for version-field disambiguation\r\n */\r\n/**\r\n * Assert that a built SlabLayout is internally consistent.\r\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\r\n * Used by layout builders to catch offset arithmetic bugs early.\r\n *\r\n * @param layout - Layout descriptor to validate.\r\n * @param dataLen - Actual byte length of the slab data buffer.\r\n * @returns The validated layout (identity function for chaining).\r\n */\r\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\r\n if (layout.accountsOff > dataLen) {\r\n throw new Error(\r\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\r\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\r\n );\r\n }\r\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\r\n if (bitmapEnd > dataLen) {\r\n throw new Error(\r\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\r\n );\r\n }\r\n return layout;\r\n}\r\n\r\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\r\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\r\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\r\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\r\n // deployed program only emits v12.19 going forward, so this priority\r\n // is correct for live mainnet reads.\r\n const v1219n = V12_19_SIZES.get(dataLen);\r\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\r\n\r\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\r\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\r\n const v1217n = V12_17_SIZES.get(dataLen);\r\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\r\n\r\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\r\n // Vastly larger account size — no collision with any earlier layout possible.\r\n const v1215n = V12_15_SIZES.get(dataLen);\r\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\r\n\r\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\r\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\r\n const v121epn = V12_1_EP_SIZES.get(dataLen);\r\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\r\n\r\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\r\n const v121n = V12_1_SIZES.get(dataLen);\r\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\r\n\r\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\r\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\r\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\r\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\r\n\r\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\r\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\r\n // works directly — no data-probe disambiguation required.\r\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n const v1m2n = V1M2_SIZES.get(dataLen);\r\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\r\n\r\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\r\n const vadln = V_ADL_SIZES.get(dataLen);\r\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\r\n\r\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\r\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\r\n const v1mn = V1M_SIZES.get(dataLen);\r\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\r\n\r\n // Check V0 sizes (deployed devnet V0 program)\r\n const v0n = V0_SIZES.get(dataLen);\r\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\r\n\r\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\r\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\r\n // When data is available, peek at the version field to disambiguate.\r\n const v1dn = V1D_SIZES.get(dataLen);\r\n if (v1dn !== undefined) {\r\n if (data && data.length >= 12) {\r\n const version = readU32LE(data, 8);\r\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\r\n }\r\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\r\n }\r\n\r\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\r\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\r\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\r\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\r\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\r\n\r\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\r\n const v1n = V1_SIZES.get(dataLen);\r\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\r\n\r\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\r\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\r\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\r\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\r\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\r\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Legacy detectLayout for backward compat.\r\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\r\n *\r\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\r\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\r\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\r\n */\r\nexport function detectLayout(dataLen: number) {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return null;\r\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\r\n}\r\n\r\n// =============================================================================\r\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\r\n// =============================================================================\r\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\r\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\r\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\r\nconst PARAMS_TRADING_FEE_OFF = 24;\r\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\r\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\r\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\r\n// riskReductionThreshold and liquidationBufferBps fields).\r\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\r\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\r\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\r\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\r\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\r\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\r\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\r\n\r\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\r\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\r\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\r\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\r\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\r\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\r\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\r\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\r\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\r\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\r\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\r\n\r\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\r\n// InitMarket wire payload for policy fields such as new_account_fee and\r\n// insurance_floor, but those fields are not stored inside engine RiskParams.\r\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\r\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\r\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\r\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\r\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\r\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\r\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\r\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\r\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\r\nconst V12_19_PARAMS_H_MIN_OFF = 104;\r\nconst V12_19_PARAMS_H_MAX_OFF = 112;\r\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\r\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\r\n\r\n// =============================================================================\r\n// Account Layout (240/248 bytes)\r\n// The first 240 bytes are identical in V0 and V1.\r\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\r\n// =============================================================================\r\nconst ACCT_ACCOUNT_ID_OFF = 0;\r\nconst ACCT_CAPITAL_OFF = 8;\r\nconst ACCT_KIND_OFF = 24;\r\nconst ACCT_PNL_OFF = 32;\r\nconst ACCT_RESERVED_PNL_OFF = 48;\r\nconst ACCT_WARMUP_STARTED_OFF = 56;\r\nconst ACCT_WARMUP_SLOPE_OFF = 64;\r\nconst ACCT_POSITION_SIZE_OFF = 80;\r\nconst ACCT_ENTRY_PRICE_OFF = 96;\r\nconst ACCT_FUNDING_INDEX_OFF = 104;\r\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\r\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\r\nconst ACCT_OWNER_OFF = 184;\r\nconst ACCT_FEE_CREDITS_OFF = 216;\r\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\r\n\r\n// =============================================================================\r\n// Interfaces\r\n// =============================================================================\r\n\r\nexport interface SlabHeader {\r\n magic: bigint;\r\n version: number;\r\n bump: number;\r\n flags: number;\r\n resolved: boolean;\r\n paused: boolean;\r\n admin: PublicKey;\r\n nonce: bigint;\r\n lastThrUpdateSlot: bigint;\r\n}\r\n\r\nexport interface MarketConfig {\r\n collateralMint: PublicKey;\r\n vaultPubkey: PublicKey;\r\n indexFeedId: PublicKey;\r\n maxStalenessSlots: bigint;\r\n confFilterBps: number;\r\n vaultAuthorityBump: number;\r\n invert: number;\r\n unitScale: number;\r\n fundingHorizonSlots: bigint;\r\n fundingKBps: bigint;\r\n fundingInvScaleNotionalE6: bigint;\r\n fundingMaxPremiumBps: bigint;\r\n fundingMaxBpsPerSlot: bigint;\r\n threshFloor: bigint;\r\n threshRiskBps: bigint;\r\n threshUpdateIntervalSlots: bigint;\r\n threshStepBps: bigint;\r\n threshAlphaBps: bigint;\r\n threshMin: bigint;\r\n threshMax: bigint;\r\n threshMinStep: bigint;\r\n oracleAuthority: PublicKey;\r\n authorityPriceE6: bigint;\r\n authorityTimestamp: bigint;\r\n oraclePriceCapE2bps: bigint;\r\n lastEffectivePriceE6: bigint;\r\n oiCapMultiplierBps: bigint;\r\n maxPnlCap: bigint;\r\n adaptiveFundingEnabled: boolean;\r\n adaptiveScaleBps: number;\r\n adaptiveMaxFundingBps: bigint;\r\n marketCreatedSlot: bigint;\r\n oiRampSlots: bigint;\r\n /**\r\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\r\n * Do not use for market-resolution logic until a parser is wired.\r\n */\r\n resolvedSlot: bigint;\r\n insuranceIsolationBps: number;\r\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\r\n oraclePhase: number;\r\n /** PERC-622: Cumulative trade volume in e6 format */\r\n cumulativeVolumeE6: bigint;\r\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\r\n phase2DeltaSlots: number;\r\n /**\r\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\r\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\r\n * SetDexPool has never been called (all-zero pubkey).\r\n * Non-null means the program will reject any UpdateHyperpMark that passes\r\n * a different pool account.\r\n */\r\n dexPool: PublicKey | null;\r\n}\r\n\r\nexport interface InsuranceFund {\r\n balance: bigint;\r\n feeRevenue: bigint;\r\n isolatedBalance: bigint;\r\n isolationBps: number;\r\n}\r\n\r\nexport interface RiskParams {\r\n /**\r\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\r\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\r\n */\r\n warmupPeriodSlots: bigint;\r\n maintenanceMarginBps: bigint;\r\n initialMarginBps: bigint;\r\n tradingFeeBps: bigint;\r\n maxAccounts: bigint;\r\n newAccountFee: bigint;\r\n riskReductionThreshold: bigint;\r\n maintenanceFeePerSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n liquidationFeeBps: bigint;\r\n liquidationFeeCap: bigint;\r\n liquidationBufferBps: bigint;\r\n minLiquidationAbs: bigint;\r\n /** Minimum initial deposit to open an account (V12_1+ only) */\r\n minInitialDeposit: bigint;\r\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\r\n minNonzeroMmReq: bigint;\r\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\r\n minNonzeroImReq: bigint;\r\n /** Insurance fund floor (V12_1+ only) */\r\n insuranceFloor: bigint;\r\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\r\n hMin: bigint;\r\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\r\n hMax: bigint;\r\n}\r\n\r\nexport interface EngineState {\r\n vault: bigint;\r\n insuranceFund: InsuranceFund;\r\n currentSlot: bigint;\r\n fundingIndexQpbE6: bigint;\r\n lastFundingSlot: bigint;\r\n /**\r\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\r\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\r\n */\r\n fundingRateBpsPerSlotLast: bigint;\r\n /**\r\n * Funding rate in e9 units (i128). v12.15+ only.\r\n * 0n on pre-v12.15 slabs.\r\n */\r\n fundingRateE9: bigint;\r\n /**\r\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\r\n */\r\n marketMode: 0 | 1 | null;\r\n lastCrankSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n totalOpenInterest: bigint;\r\n longOi: bigint;\r\n shortOi: bigint;\r\n cTot: bigint;\r\n pnlPosTot: bigint;\r\n /**\r\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\r\n */\r\n pnlMaturedPosTot: bigint;\r\n liqCursor: number;\r\n gcCursor: number;\r\n lastSweepStartSlot: bigint;\r\n lastSweepCompleteSlot: bigint;\r\n crankCursor: number;\r\n sweepStartIdx: number;\r\n lifetimeLiquidations: bigint;\r\n lifetimeForceCloses: bigint;\r\n netLpPos: bigint;\r\n lpSumAbs: bigint;\r\n lpMaxAbs: bigint;\r\n lpMaxAbsSweep: bigint;\r\n emergencyOiMode: boolean;\r\n emergencyStartSlot: bigint;\r\n lastBreakerSlot: bigint;\r\n numUsedAccounts: number;\r\n nextAccountId: bigint;\r\n markPriceE6: bigint;\r\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\r\n oraclePriceE6: bigint;\r\n\r\n // ---- V12_17 engine fields ----\r\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\r\n fLongNum: bigint;\r\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\r\n fShortNum: bigint;\r\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\r\n negPnlAccountCount: bigint;\r\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\r\n fundPxLast: bigint;\r\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\r\n resolvedKLongTerminalDelta: bigint;\r\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\r\n resolvedKShortTerminalDelta: bigint;\r\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\r\n resolvedLivePrice: bigint;\r\n}\r\n\r\nexport enum AccountKind {\r\n User = 0,\r\n LP = 1,\r\n}\r\n\r\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\r\nexport type ReserveCohortBytes = Uint8Array;\r\n\r\nexport interface Account {\r\n kind: AccountKind;\r\n accountId: bigint;\r\n capital: bigint;\r\n pnl: bigint;\r\n reservedPnl: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupStartedAtSlot: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupSlopePerStep: bigint;\r\n positionSize: bigint;\r\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\r\n entryPrice: bigint;\r\n fundingIndex: bigint;\r\n matcherProgram: PublicKey;\r\n matcherContext: PublicKey;\r\n owner: PublicKey;\r\n feeCredits: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n lastFeeSlot: bigint;\r\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\r\n feesEarnedTotal: bigint;\r\n /**\r\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\r\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\r\n */\r\n exactReserveCohorts: ReserveCohortBytes[] | null;\r\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\r\n exactCohortCount: number | null;\r\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowOlder: ReserveCohortBytes | null;\r\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\r\n overflowOlderPresent: boolean | null;\r\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowNewest: ReserveCohortBytes | null;\r\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\r\n overflowNewestPresent: boolean | null;\r\n\r\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\r\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\r\n fSnap: bigint;\r\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\r\n adlABasis: bigint;\r\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\r\n adlKSnap: bigint;\r\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\r\n adlEpochSnap: bigint;\r\n\r\n // Scheduled reserve bucket (older, matures linearly)\r\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\r\n schedPresent: boolean | null;\r\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\r\n schedRemainingQ: bigint | null;\r\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\r\n schedAnchorQ: bigint | null;\r\n /** Start slot for scheduled bucket. null on pre-v12.17. */\r\n schedStartSlot: bigint | null;\r\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\r\n schedHorizon: bigint | null;\r\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\r\n schedReleaseQ: bigint | null;\r\n\r\n // Pending reserve bucket (newest, does not mature while pending)\r\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\r\n pendingPresent: boolean | null;\r\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\r\n pendingRemainingQ: bigint | null;\r\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\r\n pendingHorizon: bigint | null;\r\n /** Creation slot for pending bucket. null on pre-v12.17. */\r\n pendingCreatedSlot: bigint | null;\r\n}\r\n\r\n// =============================================================================\r\n// Fetch\r\n// =============================================================================\r\n\r\nexport async function fetchSlab(\r\n connection: Connection,\r\n slabPubkey: PublicKey,\r\n expectedOwner?: PublicKey\r\n): Promise {\r\n const info = await connection.getAccountInfo(slabPubkey);\r\n if (!info) {\r\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\r\n }\r\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\r\n throw new Error(\r\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\r\n );\r\n }\r\n return new Uint8Array(info.data);\r\n}\r\n\r\n// =============================================================================\r\n// PERC-302: Market Maturity OI Ramp\r\n// =============================================================================\r\n\r\nexport const RAMP_START_BPS = 1000n;\r\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\r\n\r\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\r\n const target = config.oiCapMultiplierBps;\r\n if (target === 0n) return 0n;\r\n if (config.oiRampSlots === 0n) return target;\r\n if (target <= RAMP_START_BPS) return target;\r\n const elapsed = currentSlot > config.marketCreatedSlot\r\n ? currentSlot - config.marketCreatedSlot\r\n : 0n;\r\n if (elapsed >= config.oiRampSlots) return target;\r\n const range = target - RAMP_START_BPS;\r\n const rampAdd = (range * elapsed) / config.oiRampSlots;\r\n const result = RAMP_START_BPS + rampAdd;\r\n return result < target ? result : target;\r\n}\r\n\r\n// =============================================================================\r\n// Header helpers\r\n// =============================================================================\r\n\r\nexport function readNonce(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\r\n return readU64LE(data, roff);\r\n}\r\n\r\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\r\n return readU64LE(data, roff + 8);\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Parse slab header (first 72 bytes — layout-independent).\r\n */\r\nexport function parseHeader(data: Uint8Array): SlabHeader {\r\n if (data.length < V0_HEADER_LEN) {\r\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\r\n }\r\n\r\n const magic = readU64LE(data, 0);\r\n if (magic !== MAGIC) {\r\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\r\n }\r\n\r\n const version = readU32LE(data, 8);\r\n const bump = readU8(data, 12);\r\n const flags = readU8(data, 13);\r\n const admin = new PublicKey(data.subarray(16, 48));\r\n\r\n // Reserved field location depends on layout\r\n const layout = detectSlabLayout(data.length, data);\r\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\r\n const nonce = readU64LE(data, roff);\r\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\r\n\r\n return {\r\n magic,\r\n version,\r\n bump,\r\n flags,\r\n resolved: (flags & FLAG_RESOLVED) !== 0,\r\n paused: (flags & 0x02) !== 0,\r\n admin,\r\n nonce,\r\n lastThrUpdateSlot,\r\n };\r\n}\r\n\r\n/**\r\n * Parse market config. Layout-version aware.\r\n * For V0 slabs, fields beyond the basic config are read if present in the data,\r\n * otherwise defaults are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\n/**\r\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\r\n * SBF layout (u128 align=8, total size 512 bytes):\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_bps_per_slot i64\r\n * 144 oracle_authority [32]\r\n * 176 authority_price_e6 u64\r\n * 184 authority_timestamp i64\r\n * 192 oracle_price_cap_e2bps u64\r\n * 200 last_effective_price_e6 u64\r\n * 208 max_insurance_floor u128\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\r\n * 240 insurance_withdraw_cooldown_slots u64\r\n * 248 _iw_padding2 [u64;2]\r\n * 264 last_hyperp_index_slot u64\r\n * 272 last_mark_push_slot u128\r\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\r\n * 304 mark_ewma_e6 u64\r\n * 312 mark_ewma_last_slot u64\r\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\r\n * 336 permissionless_resolve_stale_slots u64\r\n * 344 last_good_oracle_slot u64\r\n * 352 maintenance_fee_per_slot u128\r\n * 368 last_fee_charge_slot u64 (+ 8 pad)\r\n * 384 mark_min_fee u64\r\n * 392 force_close_delay_slots u64\r\n * 400 dex_pool [32]\r\n * 432 max_pnl_cap u64\r\n * 440 last_audit_pause_slot u64\r\n * 448 oi_cap_multiplier_bps u64\r\n * 456 dispute_window_slots u64\r\n * 464 dispute_bond_amount u64\r\n * 472 lp_collateral_enabled u8\r\n * 473 _pad u8\r\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\r\n * 480 pending_admin [32]\r\n * 512 end\r\n */\r\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_17_BYTES = 512;\r\n if (data.length < configOff + MIN_V12_17_BYTES) {\r\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\r\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\r\n // currently surfaced by the MarketConfig type; read them when/if callers\r\n // need them. Only dex_pool is consumed downstream.\r\n\r\n const dexPoolBytes = data.subarray(b + 400, b + 432);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n, // removed in v12.17\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 448),\r\n maxPnlCap: readU64LE(data, b + 432),\r\n adaptiveFundingEnabled: false, // removed in v12.17\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\r\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\r\n * --features small) on 2026-04-28.\r\n *\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_e9_per_slot i64\r\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\r\n * 176 hyperp_mark_e6 u64 ← v12.19 only\r\n * 184 last_oracle_publish_time i64\r\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\r\n * 200 insurance_withdraw_max_bps u16\r\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\r\n * 204 _iw_padding [u8;4]\r\n * 208 insurance_withdraw_cooldown_slots u64\r\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 last_hyperp_index_slot u64\r\n * 240 last_mark_push_slot u128\r\n * 256 last_insurance_withdraw_slot u64\r\n * 264 _pad u64\r\n * 272 mark_ewma_e6 u64\r\n * 280 mark_ewma_last_slot u64\r\n * 288 mark_ewma_halflife_slots u64\r\n * 296 init_restart_slot u64\r\n * 304 permissionless_resolve_stale_slots u64\r\n * 312 last_good_oracle_slot u64\r\n * 320 maintenance_fee_per_slot u128\r\n * 336 fee_sweep_cursor_word u64\r\n * 344 fee_sweep_cursor_bit u64\r\n * 352 mark_min_fee u64\r\n * 360 force_close_delay_slots u64\r\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\r\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\r\n * 408 last_audit_pause_slot u64\r\n * 416 oi_cap_multiplier_bps u64\r\n * 424 dispute_window_slots u64\r\n * 432 dispute_bond_amount u64\r\n * 440 lp_collateral_enabled u8\r\n * 441 _pad u8\r\n * 442 lp_collateral_ltv_bps u16\r\n * 444 _pad [u8;4]\r\n * 448 pending_admin [32]\r\n * 480 end\r\n */\r\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_19_BYTES = 480;\r\n if (data.length < configOff + MIN_V12_19_BYTES) {\r\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\r\n\r\n const dexPoolBytes = data.subarray(b + 368, b + 400);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n,\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 416),\r\n maxPnlCap: readU64LE(data, b + 400),\r\n adaptiveFundingEnabled: false,\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseConfig: invalid slab magic');\r\n }\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\r\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\r\n\r\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\r\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\r\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_19) {\r\n return parseConfigV12_19(data, configOff);\r\n }\r\n\r\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\r\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\r\n // sequential code below covers pre-v12.17 layouts.\r\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\r\n if (isV12_17) {\r\n return parseConfigV12_17(data, configOff);\r\n }\r\n\r\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\r\n // V1 extended fields are optional and guarded by their own `remaining` checks.\r\n const MIN_CONFIG_BYTES = 376;\r\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\r\n }\r\n\r\n let off = configOff;\r\n\r\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const maxStalenessSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const confFilterBps = readU16LE(data, off);\r\n off += 2;\r\n\r\n const vaultAuthorityBump = readU8(data, off);\r\n off += 1;\r\n\r\n const invert = readU8(data, off);\r\n off += 1;\r\n\r\n const unitScale = readU32LE(data, off);\r\n off += 4;\r\n\r\n // Funding rate parameters\r\n const fundingHorizonSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingKBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\r\n off += 16;\r\n\r\n const fundingMaxPremiumBps = readI64LE(data, off);\r\n off += 8;\r\n\r\n const fundingMaxBpsPerSlot = readI64LE(data, off);\r\n off += 8;\r\n\r\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\r\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\r\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\r\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\r\n\r\n // Threshold parameters\r\n const threshFloor = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshRiskBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshUpdateIntervalSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshStepBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshAlphaBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshMin = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMax = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMinStep = readU128LE(data, off);\r\n off += 16;\r\n\r\n // Oracle authority fields\r\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const authorityPriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n const authorityTimestamp = readI64LE(data, off);\r\n off += 8;\r\n\r\n // Oracle price circuit breaker\r\n const oraclePriceCapE2bps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const lastEffectivePriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n // OI cap\r\n const oiCapMultiplierBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const maxPnlCap = readU64LE(data, off);\r\n off += 8;\r\n\r\n // Check if we have enough data for V1-only fields\r\n const remaining = configOff + configLen - off;\r\n\r\n let adaptiveFundingEnabled = false;\r\n let adaptiveScaleBps = 0;\r\n let adaptiveMaxFundingBps = 0n;\r\n let marketCreatedSlot = 0n;\r\n let oiRampSlots = 0n;\r\n let resolvedSlot = 0n;\r\n let insuranceIsolationBps = 0;\r\n let oraclePhase = 0;\r\n let cumulativeVolumeE6 = 0n;\r\n let phase2DeltaSlots = 0;\r\n\r\n if (remaining >= 40) {\r\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\r\n // market_created_slot(u64), oi_ramp_slots(u64),\r\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\r\n // _pad2(u32), adaptive_max_funding_bps(u64),\r\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\r\n marketCreatedSlot = readU64LE(data, off);\r\n off += 8;\r\n\r\n oiRampSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n adaptiveFundingEnabled = readU8(data, off) !== 0;\r\n off += 1;\r\n off += 1; // _adaptive_pad\r\n adaptiveScaleBps = readU16LE(data, off);\r\n off += 2;\r\n off += 4; // _adaptive_pad2\r\n adaptiveMaxFundingBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n if (remaining >= 42) {\r\n insuranceIsolationBps = readU16LE(data, off);\r\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\r\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\r\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\r\n if (remaining >= 56) { // 42 + 14 bytes padding\r\n const padOff = off + 2;\r\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\r\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\r\n // phase2_delta_slots is u24 LE (3 bytes)\r\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\r\n }\r\n }\r\n }\r\n\r\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\r\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\r\n // All-zero pubkey means SetDexPool was never called.\r\n let dexPool: PublicKey | null = null;\r\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\r\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\r\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\r\n // Return null if all-zero (SetDexPool never called)\r\n if (dexPoolBytes.some(b => b !== 0)) {\r\n dexPool = new PublicKey(dexPoolBytes);\r\n }\r\n }\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor,\r\n threshRiskBps,\r\n threshUpdateIntervalSlots,\r\n threshStepBps,\r\n threshAlphaBps,\r\n threshMin,\r\n threshMax,\r\n threshMinStep,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps,\r\n maxPnlCap,\r\n adaptiveFundingEnabled,\r\n adaptiveScaleBps,\r\n adaptiveMaxFundingBps,\r\n marketCreatedSlot,\r\n oiRampSlots,\r\n resolvedSlot,\r\n insuranceIsolationBps,\r\n oraclePhase,\r\n cumulativeVolumeE6,\r\n phase2DeltaSlots,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * Parse RiskParams from engine data. Layout-version aware.\r\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\r\n * not present on-chain, so defaults (0) are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\r\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\r\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\r\n const base = engineOff + paramsOff;\r\n\r\n // Validate we have enough data for the fields we'll actually read.\r\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\r\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\r\n if (data.length < base + MIN_PARAMS_BYTES) {\r\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\r\n }\r\n\r\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\r\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\r\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\r\n const isV12_19Params = layout !== null && layout !== undefined &&\r\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\r\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\r\n\r\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\r\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\r\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\r\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\r\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\r\n\r\n // Basic params present in all layouts (offsets 0-55 are identical)\r\n const result: RiskParams = {\r\n warmupPeriodSlots: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\r\n maintenanceMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\r\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\r\n initialMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 8)\r\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\r\n tradingFeeBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 16)\r\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\r\n maxAccounts: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\r\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\r\n newAccountFee: isV12_19Params\r\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\r\n : isV12_15Params\r\n ? readU128LE(data, base + 32) // offset 32 in v12.15\r\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\r\n // Extended params: defaults; overwritten below if layout supports them\r\n riskReductionThreshold: 0n,\r\n maintenanceFeePerSlot: 0n,\r\n maxCrankStalenessSlots: 0n,\r\n liquidationFeeBps: 0n,\r\n liquidationFeeCap: 0n,\r\n liquidationBufferBps: 0n,\r\n minLiquidationAbs: 0n,\r\n minInitialDeposit: 0n,\r\n minNonzeroMmReq: 0n,\r\n minNonzeroImReq: 0n,\r\n insuranceFloor: 0n,\r\n hMin: 0n,\r\n hMax: 0n,\r\n };\r\n\r\n if (isV12_19Params) {\r\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\r\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\r\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\r\n result.riskReductionThreshold = 0n;\r\n result.maintenanceFeePerSlot = 0n;\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = 0n;\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = 0n;\r\n } else if (isV12_15Params) {\r\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\r\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\r\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\r\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\r\n result.riskReductionThreshold = 0n; // removed in v12.15\r\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\r\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\r\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\r\n result.liquidationFeeBps = readU64LE(data, base + 56);\r\n result.liquidationFeeCap = readU128LE(data, base + 64);\r\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\r\n result.minLiquidationAbs = readU128LE(data, base + 80);\r\n result.minInitialDeposit = readU128LE(data, base + 96);\r\n result.minNonzeroMmReq = readU128LE(data, base + 112);\r\n result.minNonzeroImReq = readU128LE(data, base + 128);\r\n } else if (isV12_1Sbf) {\r\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\r\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n } else if (paramsSize >= 144) {\r\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\r\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\r\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\r\n */\r\nexport function parseEngine(data: Uint8Array): EngineState {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseEngine: invalid slab magic');\r\n }\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\r\n }\r\n if (data.length < layout.accountsOff) {\r\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\r\n }\r\n\r\n const base = layout.engineOff;\r\n\r\n // Detect layout versions\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\r\n\r\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\r\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\r\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\r\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_17 || isV12_19) {\r\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\r\n\r\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\r\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\r\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\r\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\r\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\r\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\r\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\r\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\r\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\r\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\r\n // resolved_k offsets: native 304/320, SBF 288/304\r\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\r\n const resolvedKLongOff = isV12_19 ? 288\r\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\r\n const resolvedKShortOff = isV12_19 ? 304\r\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\r\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\r\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\r\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\r\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\r\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\r\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\r\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\r\n\r\n const longOi = readU128LE(data, base + oiEffLongOff);\r\n const shortOi = readU128LE(data, base + oiEffShortOff);\r\n\r\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\r\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: 0n,\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + currentSlotOff),\r\n fundingIndexQpbE6: 0n, // replaced by per-side funding\r\n lastFundingSlot: 0n,\r\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\r\n fundingRateE9: 0n, // no stored funding rate in v12.17\r\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\r\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\r\n maxCrankStalenessSlots: 0n,\r\n totalOpenInterest: longOi + shortOi,\r\n longOi,\r\n shortOi,\r\n cTot: readU128LE(data, base + cTotOff),\r\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\r\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\r\n liqCursor: 0,\r\n gcCursor: readU16LE(data, base + gcCursorOff),\r\n lastSweepStartSlot: 0n,\r\n lastSweepCompleteSlot: 0n,\r\n crankCursor: 0,\r\n sweepStartIdx: 0,\r\n lifetimeLiquidations: 0n,\r\n lifetimeForceCloses: 0n,\r\n netLpPos: 0n,\r\n lpSumAbs: 0n,\r\n lpMaxAbs: 0n,\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n,\r\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\r\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\r\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\r\n\r\n // V12_17 fields\r\n fLongNum: readI128LE(data, base + fLongNumOff),\r\n fShortNum: readI128LE(data, base + fShortNumOff),\r\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\r\n fundPxLast: readU64LE(data, base + fundPxLastOff),\r\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\r\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\r\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\r\n };\r\n }\r\n\r\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\r\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\r\n const fundingRateBpsPerSlotLast = isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + layout.engineInsuranceOff),\r\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\r\n feeRevenue: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\r\n : 0n,\r\n isolatedBalance: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\r\n : 0n,\r\n isolationBps: layout.hasInsuranceIsolation\r\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\r\n : 0,\r\n },\r\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\r\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\r\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\r\n : readI128LE(data, base + layout.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\r\n fundingRateBpsPerSlotLast,\r\n fundingRateE9: isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : 0n,\r\n marketMode: isV12_15\r\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\r\n : null,\r\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\r\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\r\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\r\n totalOpenInterest: layout.engineTotalOiOff >= 0\r\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\r\n longOi: layout.engineLongOiOff >= 0\r\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\r\n shortOi: layout.engineShortOiOff >= 0\r\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\r\n cTot: readU128LE(data, base + layout.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\r\n pnlMaturedPosTot: isV12_15\r\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\r\n : 0n,\r\n liqCursor: layout.engineLiqCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\r\n gcCursor: layout.engineGcCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\r\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\r\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\r\n crankCursor: layout.engineCrankCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\r\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\r\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\r\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\r\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\r\n netLpPos: layout.engineNetLpPosOff >= 0\r\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\r\n lpSumAbs: layout.engineLpSumAbsOff >= 0\r\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\r\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\r\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\r\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\r\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\r\n : false,\r\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\r\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\r\n markPriceE6: layout.engineMarkPriceOff >= 0\r\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\r\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\r\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\r\n oraclePriceE6: isV12_15\r\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\r\n : 0n,\r\n numUsedAccounts: (() => {\r\n if (layout.postBitmap < 18) return 0;\r\n const bw = layout.bitmapWords;\r\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\r\n })(),\r\n nextAccountId: (() => {\r\n if (layout.postBitmap < 18) return 0n;\r\n const bw = layout.bitmapWords;\r\n const numUsedOff = layout.engineBitmapOff + bw * 8;\r\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\r\n })(),\r\n\r\n // V12_17 fields (not present in pre-v12.17)\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n };\r\n}\r\n\r\n/**\r\n * Read bitmap to get list of used account indices.\r\n */\r\n/**\r\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\r\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\r\n */\r\nexport function parseUsedIndices(data: Uint8Array): number[] {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n if (data.length < base + layout.bitmapWords * 8) {\r\n throw new Error(\"Slab data too short for bitmap\");\r\n }\r\n\r\n const used: number[] = [];\r\n for (let word = 0; word < layout.bitmapWords; word++) {\r\n const bits = readU64LE(data, base + word * 8);\r\n if (bits === 0n) continue;\r\n for (let bit = 0; bit < 64; bit++) {\r\n if ((bits >> BigInt(bit)) & 1n) {\r\n used.push(word * 64 + bit);\r\n }\r\n }\r\n }\r\n return used;\r\n}\r\n\r\n/**\r\n * Check if a specific account index is used.\r\n */\r\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) return false;\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n const word = Math.floor(idx / 64);\r\n const bit = idx % 64;\r\n const bits = readU64LE(data, base + word * 8);\r\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\r\n}\r\n\r\n/**\r\n * Calculate the maximum valid account index for a given slab size.\r\n */\r\nexport function maxAccountIndex(dataLen: number): number {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return 0;\r\n const accountsEnd = dataLen - layout.accountsOff;\r\n if (accountsEnd <= 0) return 0;\r\n return Math.floor(accountsEnd / layout.accountSize);\r\n}\r\n\r\n/**\r\n * Parse a single account by index.\r\n */\r\nexport function parseAccount(data: Uint8Array, idx: number): Account {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const maxIdx = maxAccountIndex(data.length);\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\r\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\r\n }\r\n\r\n const base = layout.accountsOff + idx * layout.accountSize;\r\n if (data.length < base + layout.accountSize) {\r\n throw new Error(\"Slab data too short for account\");\r\n }\r\n\r\n // Select layout-dependent account field offsets.\r\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\r\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\r\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\r\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\r\n // Pre-ADL (account_size<312): original offsets.\r\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\r\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\r\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\r\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\r\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\r\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\r\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\r\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\r\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\r\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\r\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\r\n\r\n if (isV12_17) {\r\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\r\n //\r\n // SBF vs native alignment delta:\r\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\r\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\r\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\r\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\r\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\r\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\r\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\r\n\r\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: 0n, // removed in v12.17\r\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\r\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\r\n warmupStartedAtSlot: 0n, // removed\r\n warmupSlopePerStep: 0n, // removed\r\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\r\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\r\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\r\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\r\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\r\n lastFeeSlot: 0n, // removed\r\n feesEarnedTotal: 0n, // removed in v12.17\r\n exactReserveCohorts: null, // replaced by two-bucket warmup\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // V12_17 fields\r\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\r\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\r\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\r\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\r\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\r\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\r\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\r\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\r\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\r\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\r\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\r\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\r\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\r\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\r\n };\r\n }\r\n\r\n if (isV12_15) {\r\n // V12_15 fast path: fixed offsets, all fields explicit.\r\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n // Parse the 62 reserve cohorts\r\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\r\n const exactReserveCohorts: ReserveCohortBytes[] = [];\r\n for (let i = 0; i < 62; i++) {\r\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\r\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\r\n }\r\n\r\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\r\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\r\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: 0n, // removed in v12.15\r\n warmupSlopePerStep: 0n, // removed in v12.15\r\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\r\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\r\n fundingIndex: 0n, // not present in v12.15 account struct\r\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\r\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\r\n lastFeeSlot: 0n, // removed in v12.15\r\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\r\n exactReserveCohorts,\r\n exactCohortCount: cohortCount,\r\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\r\n overflowOlderPresent,\r\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\r\n overflowNewestPresent,\r\n\r\n // v12.17 fields (not present in v12.15)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n }\r\n\r\n // Pre-v12.15 path\r\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\r\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\r\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\r\n 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));\r\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\r\n 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));\r\n 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));\r\n 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));\r\n 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));\r\n\r\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\r\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\r\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\r\n positionSize: readI128LE(data, base + positionSizeOff),\r\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\r\n // V12_1/V12_1_EP: funding_index not present in SBF layout\r\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\r\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\r\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\r\n feeCredits: readI128LE(data, base + feeCreditsOff),\r\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\r\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\r\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // v12.17 fields (not present in pre-v12.17)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\r\n//\r\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\r\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\r\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\r\n// is a full account-layout break — every v16-version market account is\r\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\r\n// =============================================================================\r\n\r\n/**\r\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\r\n * Stored at bytes [0..8] of every v17 percolator-owned account.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\n/**\r\n * v17 account version (u16 at offset 8).\r\n *\r\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\r\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\r\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\r\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\r\n */\r\nexport const V17_EXPECTED_VERSION = 17;\r\n\r\n/**\r\n * v17 account-kind byte (offset 10 of the 16-byte header).\r\n *\r\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\r\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\r\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\r\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\r\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\r\n * discovery — every other kind shares the same magic+version and would falsely\r\n * pass the looser {@link isV17Account} check (#264).\r\n */\r\nexport const V17_KIND_MARKET = 1;\r\n\r\n/** Byte offset of the v17 account-kind discriminator within the header. */\r\nexport const V17_KIND_OFF = 10;\r\n\r\n/**\r\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\r\n *\r\n * Growth history, each stage purely additive at the tail with all earlier\r\n * offsets UNCHANGED:\r\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\r\n * @432, `protocol_fee_accrued_atoms` u128 @464,\r\n * `protocol_fee_withdrawn_atoms` u128 @480.\r\n * 496 -> 576 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\r\n * @496/512/528/544, three u16 shares @560/562/564, then\r\n * `_padding_split` [u8;10] @566.\r\n *\r\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\r\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\r\n * it is u128-aligned; placing the u16 shares first would push the u128s to\r\n * offset 502 and force the compiler to insert implicit padding, failing the\r\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\r\n * padding out to the 16-byte alignment boundary.\r\n *\r\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\r\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\r\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\r\n * at line 1159.\r\n *\r\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\r\n * still carries the 496-byte layout. Reading a market created by that build\r\n * with this decoder will throw \"data too short\"; a 576-byte read against a\r\n * 496-byte account is a length error, not a silent misparse.\r\n */\r\nexport const V17_WRAPPER_CONFIG_LEN = 576;\r\n\r\n/**\r\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\r\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\r\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\r\n *\r\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\r\n * `_padding_split` tail at the only 8-aligned slot inside it, so\r\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\r\n * 592, and NO pre-existing offset moves. Growing the config instead would have\r\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\r\n * markets — a repeat of the 496→576 incident. If you ever find yourself\r\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\r\n *\r\n * Source of truth: percolator-prog `src/v16_program.rs` struct\r\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\r\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\r\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\r\n */\r\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\r\n\r\n/** v17 AssetOracleProfileV16 length (400 bytes). */\r\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\r\n\r\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\r\nexport const V17_HEADER_LEN = 16;\r\n\r\n/**\r\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\r\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\r\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\r\n * downstream offset in this file chains off it.\r\n */\r\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\r\n\r\n/**\r\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\r\n * verified against percolator-prog `cargo run --example dump_layout`.\r\n */\r\nexport const V17_MARKET_GROUP_LEN = 758;\r\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\r\n\r\n/**\r\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\r\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\r\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\r\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\r\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\r\n */\r\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\r\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\r\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\r\n }\r\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\r\n}\r\n\r\n/**\r\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\r\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\r\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\r\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\r\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\r\n */\r\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\r\n\r\n/**\r\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\r\n *\r\n * Field offsets follow SBF alignment (u128 align=8, not 16).\r\n * Full offset table (verified against v17 wrapper source v16_program.rs,\r\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\r\n * 0 marketauth [32]\r\n * 32 collateral_mint [32]\r\n * 64 secondary_collateral_mint [32]\r\n * 96 maintenance_fee_per_slot u128\r\n * 112 permissionless_market_init_fee u128\r\n * 128 trade_fee_base_bps u64\r\n * 136 permissionless_resolve_stale_slots u64\r\n * 144 force_close_delay_slots u64\r\n * 152 last_good_oracle_slot u64\r\n * 160 insurance_withdraw_deposit_remaining u128\r\n * 176 insurance_withdraw_max_bps u16\r\n * 178 liquidation_cranker_fee_share_bps u16\r\n * 180 maintenance_cranker_fee_share_bps u16\r\n * 182 backing_trade_fee_bps_long u16\r\n * 184 unit_scale u32\r\n * 188 conf_filter_bps u16\r\n * 190 backing_trade_fee_bps_short u16\r\n * 192 insurance_withdraw_deposits_only u8\r\n * 193 oracle_mode u8\r\n * 194 oracle_leg_count u8\r\n * 195 oracle_leg_flags u8\r\n * 196 invert u8\r\n * 197 _padding0 u8\r\n * 198 free_market_slot_count u16\r\n * 200 insurance_withdraw_cooldown_slots u64\r\n * 208 last_insurance_withdraw_slot u64\r\n * 216 max_staleness_secs u64\r\n * 224 hybrid_soft_stale_slots u64\r\n * 232 mark_ewma_e6 u64\r\n * 240 mark_ewma_last_slot u64\r\n * 248 mark_ewma_halflife_slots u64\r\n * 256 mark_min_fee u64\r\n * 264 oracle_target_price_e6 u64\r\n * 272 oracle_target_publish_time i64\r\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 400 oracle_leg_publish_times [i64;3] (24B)\r\n * 424 backing_trade_fee_policy_count u16\r\n * 426 backing_trade_fee_insurance_share_bps_long u16\r\n * 428 backing_trade_fee_insurance_share_bps_short u16\r\n * 430 fee_redirect_to_market_0_bps u16\r\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\r\n * 432 protocol_fee_authority [32]\r\n * 464 protocol_fee_accrued_atoms u128\r\n * 480 protocol_fee_withdrawn_atoms u128\r\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\r\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\r\n * 496 lp_fee_accrued_atoms u128\r\n * 512 lp_fee_withdrawn_atoms u128\r\n * 528 insurance_reserve_accrued_atoms u128\r\n * 544 insurance_reserve_withdrawn_atoms u128\r\n * 560 creator_share_bps u16\r\n * 562 lp_share_bps u16\r\n * 564 insurance_share_bps u16\r\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\r\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\r\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\r\n * Total: 576\r\n */\r\nexport interface WrapperConfigV17 {\r\n marketauth: PublicKey;\r\n collateralMint: PublicKey;\r\n secondaryCollateralMint: PublicKey;\r\n maintenanceFeePerSlot: bigint;\r\n permissionlessMarketInitFee: bigint;\r\n tradeFeeBps: bigint;\r\n permissionlessResolveStaleSlots: bigint;\r\n forceCloseDelaySlots: bigint;\r\n lastGoodOracleSlot: bigint;\r\n insuranceWithdrawDepositRemaining: bigint;\r\n insuranceWithdrawMaxBps: number;\r\n liquidationCrankerFeeShareBps: number;\r\n maintenanceCrankerFeeShareBps: number;\r\n backingTradeFeeBpsLong: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsShort: number;\r\n insuranceWithdrawDepositsOnly: number;\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n freeMarketSlotCount: number;\r\n insuranceWithdrawCooldownSlots: bigint;\r\n lastInsuranceWithdrawSlot: bigint;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n backingTradeFeePolicyCount: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n feeRedirectToMarket0Bps: number;\r\n /**\r\n * Destination pubkey for the protocol's accrued fee share. Set to a\r\n * hardcoded program-level constant at InitMarket; rotatable only via\r\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\r\n * by marketauth/insurance_authority/any creator-facing gate.\r\n */\r\n protocolFeeAuthority: PublicKey;\r\n /**\r\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\r\n * itself credited into any domain's insurance budget — tracks an\r\n * unbudgeted slice of header.insurance no insurance_operator can reach.\r\n */\r\n protocolFeeAccruedAtoms: bigint;\r\n /**\r\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\r\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\r\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\r\n */\r\n protocolFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\r\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\r\n * principal.\r\n *\r\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\r\n * it can be impaired by backing losses between crank and redemption.\r\n *\r\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\r\n * can never be cranked. Outstanding = accrued - withdrawn.\r\n */\r\n lpFeeAccruedAtoms: bigint;\r\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\r\n lpFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\r\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\r\n * bound stake pool's vault.\r\n *\r\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\r\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\r\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\r\n * unbudgeted by construction. Keepers should crank before resolution.\r\n */\r\n insuranceReserveAccruedAtoms: bigint;\r\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\r\n insuranceReserveWithdrawnAtoms: bigint;\r\n /**\r\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\r\n * (3600). Lands in insurance_domain_budget; claimed via\r\n * WithdrawInsuranceAsset (tag 57).\r\n */\r\n creatorShareBps: number;\r\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\r\n lpShareBps: number;\r\n /**\r\n * Insurance/staker share of T in bps. Default 1600, floor\r\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\r\n * split_trade_fee computes this leg as the remainder.\r\n */\r\n insuranceShareBps: number;\r\n /**\r\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\r\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\r\n *\r\n * This is the honest claimable balance a creator-claim UI should display.\r\n * Before the creator-fee-claim change the creator leg was credited into the\r\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\r\n * had no on-chain representation at all and a claim button was really a\r\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\r\n * alone.\r\n *\r\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\r\n * / insurance legs above, this is a single live balance: trades add to it and\r\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\r\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\r\n * claimable right now. (Forced by the 10-byte pad budget; see\r\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\r\n *\r\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\r\n * were explicit padding, so the value is well-defined rather than garbage,\r\n * and the counter simply accrues fresh after an in-place upgrade.\r\n */\r\n creatorFeeClaimableAtoms: bigint;\r\n}\r\n\r\n/**\r\n * Parse a v17 WrapperConfigV16 block from raw account data.\r\n *\r\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\r\n *\r\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\r\n * This function reads the 496-byte wrapper config block directly. It does NOT\r\n * validate the account header magic or version — callers must do that separately.\r\n *\r\n * @param data Raw bytes of the market group account.\r\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\r\n * @returns Parsed WrapperConfigV17 object.\r\n *\r\n * @example\r\n * ```ts\r\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\r\n * if (!accountInfo) throw new Error(\"account not found\");\r\n * const magic = readU64FromBytes(accountInfo.data, 0);\r\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\r\n * const config = parseWrapperConfigV17(accountInfo.data);\r\n * console.log(config.collateralMint.toBase58());\r\n * ```\r\n */\r\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\r\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = configOff;\r\n\r\n // Offsets from the WrapperConfigV16 offset table above\r\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\r\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\r\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\r\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\r\n const tradeFeeBps = readU64LE(data, b + 128);\r\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\r\n const forceCloseDelaySlots = readU64LE(data, b + 144);\r\n const lastGoodOracleSlot = readU64LE(data, b + 152);\r\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\r\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\r\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\r\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\r\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\r\n const unitScale = readU32LE(data, b + 184);\r\n const confFilterBps = readU16LE(data, b + 188);\r\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\r\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\r\n const oracleMode = readU8(data, b + 193);\r\n const oracleLegCount = readU8(data, b + 194);\r\n const oracleLegFlags = readU8(data, b + 195);\r\n const invert = readU8(data, b + 196);\r\n // _padding0 at b+197\r\n const freeMarketSlotCount = readU16LE(data, b + 198);\r\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\r\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\r\n const maxStalenessSecs = readU64LE(data, b + 216);\r\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\r\n const markEwmaE6 = readU64LE(data, b + 232);\r\n const markEwmaLastSlot = readU64LE(data, b + 240);\r\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\r\n const markMinFee = readU64LE(data, b + 256);\r\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\r\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\r\n\r\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\r\n const ORACLE_LEG_CAP = 3;\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\r\n }\r\n\r\n // oracle_leg_prices_e6: [u64;3] at b+376\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\r\n }\r\n\r\n // oracle_leg_publish_times: [i64;3] at b+400\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\r\n }\r\n\r\n // Tail policy fields at b+424\r\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\r\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\r\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\r\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\r\n\r\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\r\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\r\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\r\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\r\n\r\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\r\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\r\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\r\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\r\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\r\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\r\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\r\n const creatorShareBps = readU16LE(data, b + 560);\r\n const lpShareBps = readU16LE(data, b + 562);\r\n const insuranceShareBps = readU16LE(data, b + 564);\r\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\r\n\r\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\r\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\r\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\r\n\r\n return {\r\n marketauth,\r\n collateralMint,\r\n secondaryCollateralMint,\r\n maintenanceFeePerSlot,\r\n permissionlessMarketInitFee,\r\n tradeFeeBps,\r\n permissionlessResolveStaleSlots,\r\n forceCloseDelaySlots,\r\n lastGoodOracleSlot,\r\n insuranceWithdrawDepositRemaining,\r\n insuranceWithdrawMaxBps,\r\n liquidationCrankerFeeShareBps,\r\n maintenanceCrankerFeeShareBps,\r\n backingTradeFeeBpsLong,\r\n unitScale,\r\n confFilterBps,\r\n backingTradeFeeBpsShort,\r\n insuranceWithdrawDepositsOnly,\r\n oracleMode,\r\n oracleLegCount,\r\n oracleLegFlags,\r\n invert,\r\n freeMarketSlotCount,\r\n insuranceWithdrawCooldownSlots,\r\n lastInsuranceWithdrawSlot,\r\n maxStalenessSecs,\r\n hybridSoftStaleSlots,\r\n markEwmaE6,\r\n markEwmaLastSlot,\r\n markEwmaHalflifeSlots,\r\n markMinFee,\r\n oracleTargetPriceE6,\r\n oracleTargetPublishTime,\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n backingTradeFeePolicyCount,\r\n backingTradeFeeInsuranceShareBpsLong,\r\n backingTradeFeeInsuranceShareBpsShort,\r\n feeRedirectToMarket0Bps,\r\n protocolFeeAuthority,\r\n protocolFeeAccruedAtoms,\r\n protocolFeeWithdrawnAtoms,\r\n lpFeeAccruedAtoms,\r\n lpFeeWithdrawnAtoms,\r\n insuranceReserveAccruedAtoms,\r\n insuranceReserveWithdrawnAtoms,\r\n creatorShareBps,\r\n lpShareBps,\r\n insuranceShareBps,\r\n creatorFeeClaimableAtoms,\r\n };\r\n}\r\n\r\n/**\r\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\r\n *\r\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\r\n * 0 oracle_mode u8\r\n * 1 oracle_leg_count u8\r\n * 2 oracle_leg_flags u8\r\n * 3 invert u8\r\n * 4 unit_scale u32\r\n * 8 conf_filter_bps u16\r\n * 10 backing_trade_fee_bps_long u16\r\n * 12 backing_trade_fee_bps_short u16\r\n * 14 backing_trade_fee_insurance_share_bps_long u16\r\n * 16 backing_trade_fee_insurance_share_bps_short u16\r\n * 18 _padding0 [u8;6]\r\n * 24 insurance_authority [32]\r\n * 56 insurance_operator [32]\r\n * 88 backing_bucket_authority [32]\r\n * 120 oracle_authority [32]\r\n * 152 max_staleness_secs u64\r\n * 160 hybrid_soft_stale_slots u64\r\n * 168 mark_ewma_e6 u64\r\n * 176 mark_ewma_last_slot u64\r\n * 184 mark_ewma_halflife_slots u64\r\n * 192 mark_min_fee u64\r\n * 200 oracle_target_price_e6 u64\r\n * 208 oracle_target_publish_time i64\r\n * 216 last_good_oracle_slot u64\r\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 344 oracle_leg_publish_times [i64;3] (24B)\r\n * 368 asset_admin [32] ← v17 NEW\r\n * Total: 400\r\n */\r\nexport interface AssetOracleProfileV17 {\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsLong: number;\r\n backingTradeFeeBpsShort: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n insuranceAuthority: PublicKey;\r\n insuranceOperator: PublicKey;\r\n backingBucketAuthority: PublicKey;\r\n oracleAuthority: PublicKey;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n lastGoodOracleSlot: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n /** v17 NEW: asset_admin pubkey at offset 368. */\r\n assetAdmin: PublicKey;\r\n}\r\n\r\n/**\r\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\r\n *\r\n * @param data Raw bytes containing the profile block.\r\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\r\n * @returns Parsed AssetOracleProfileV17 object.\r\n */\r\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\r\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = profileOff;\r\n const ORACLE_LEG_CAP = 3;\r\n\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\r\n }\r\n\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\r\n }\r\n\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\r\n }\r\n\r\n return {\r\n oracleMode: readU8(data, b + 0),\r\n oracleLegCount: readU8(data, b + 1),\r\n oracleLegFlags: readU8(data, b + 2),\r\n invert: readU8(data, b + 3),\r\n unitScale: readU32LE(data, b + 4),\r\n confFilterBps: readU16LE(data, b + 8),\r\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\r\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\r\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\r\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\r\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\r\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\r\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\r\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\r\n maxStalenessSecs: readU64LE(data, b + 152),\r\n hybridSoftStaleSlots: readU64LE(data, b + 160),\r\n markEwmaE6: readU64LE(data, b + 168),\r\n markEwmaLastSlot: readU64LE(data, b + 176),\r\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\r\n markMinFee: readU64LE(data, b + 192),\r\n oracleTargetPriceE6: readU64LE(data, b + 200),\r\n oracleTargetPublishTime: readI64LE(data, b + 208),\r\n lastGoodOracleSlot: readU64LE(data, b + 216),\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\r\n };\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer contains a v17 percolator account.\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\r\n */\r\nexport function isV17Account(data: Uint8Array): boolean {\r\n if (data.length < 10) return false;\r\n const magic = readU64LE(data, 0);\r\n const version = readU16LE(data, 8);\r\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer is a v17 percolator MARKET account.\r\n *\r\n * Stricter than {@link isV17Account}: requires both that the account is a valid\r\n * v17 account (magic + version) AND that the kind byte at offset 10 is\r\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\r\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\r\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\r\n */\r\nexport function isV17MarketAccount(data: Uint8Array): boolean {\r\n if (data.length < V17_KIND_OFF + 1) return false;\r\n if (!isV17Account(data)) return false;\r\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\r\n}\r\n\r\n// =============================================================================\r\n// V17 OI parser\r\n// =============================================================================\r\n\r\n/**\r\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\r\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\r\n */\r\nconst V17_HEADER_INSURANCE_OFF = 301;\r\n\r\n/**\r\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\r\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\r\n */\r\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\r\n\r\n/**\r\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\r\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\r\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\r\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\r\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\r\n * oi_eff_short_q follows at 273 + 16 = 289\r\n */\r\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\r\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\r\n\r\n/**\r\n * Aggregated open-interest parsed from a v17 market group account.\r\n *\r\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\r\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\r\n * slots in the account and also returns per-asset breakdown.\r\n *\r\n * All quantities are in token micro-units (raw, not scaled by decimals).\r\n */\r\nexport interface V17MarketGroupOI {\r\n /** Group-level insurance reserve (u128, micro-units) */\r\n insuranceBalance: bigint;\r\n /** Sum of oi_eff_long_q across all asset slots */\r\n totalLongOiQ: bigint;\r\n /** Sum of oi_eff_short_q across all asset slots */\r\n totalShortOiQ: bigint;\r\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\r\n assets: Array<{\r\n assetIndex: number;\r\n oiEffLongQ: bigint;\r\n oiEffShortQ: bigint;\r\n }>;\r\n}\r\n\r\n/**\r\n * Parse open-interest fields from a v17 market group account.\r\n *\r\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\r\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\r\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\r\n * which follows the 512-byte wrapper T at the start of each slot).\r\n *\r\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\r\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\r\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\r\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are exact byte offsets.\r\n *\r\n * The absolute offsets below follow from the CURRENT wrapper layout —\r\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\r\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\r\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\r\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\r\n * - insurance: 592 + 301 = 893\r\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\r\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\r\n *\r\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\r\n * giving insurance @ 813. The CODE was always correct — it composes the named\r\n * constants — but the stated numbers were stale. Verified against the first real\r\n * v17 market on the new devnet deployment.)\r\n *\r\n * @param data Raw bytes of the v17 market group account.\r\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\r\n * @throws Error if the buffer is not a valid v17 market account or is too short.\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketGroupPk);\r\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\r\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\r\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\r\n * ```\r\n */\r\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\r\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\r\n const insuranceBalance = readU128LE(data, insuranceOff);\r\n\r\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\r\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\r\n const numSlots = Math.floor(\r\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\r\n );\r\n\r\n let totalLongOiQ = 0n;\r\n let totalShortOiQ = 0n;\r\n const assets: V17MarketGroupOI[\"assets\"] = [];\r\n\r\n for (let i = 0; i < numSlots; i++) {\r\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\r\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\r\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\r\n const longOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\r\n const shortOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\r\n\r\n // Guard against a truncated buffer (should not happen on well-formed accounts).\r\n if (shortOff + 16 > data.length) break;\r\n\r\n const oiEffLongQ = readU128LE(data, longOff);\r\n const oiEffShortQ = readU128LE(data, shortOff);\r\n\r\n totalLongOiQ += oiEffLongQ;\r\n totalShortOiQ += oiEffShortQ;\r\n\r\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\r\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\r\n }\r\n }\r\n\r\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\r\n}\r\n\r\n// =============================================================================\r\n// V17 account decoders (DESYNC fixes — new standalone account types)\r\n// =============================================================================\r\n\r\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\r\nconst V17_ACCOUNT_HEADER_LEN = 16;\r\nconst V17_KIND_PORTFOLIO = 2;\r\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\r\nconst V17_KIND_LP_REDEMPTION = 6;\r\n\r\nfunction assertV17StandaloneHeader(\r\n data: Uint8Array,\r\n parserName: string,\r\n expectedKind: number,\r\n): void {\r\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\r\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\r\n }\r\n const magic = readU64LE(data, 0);\r\n if (magic !== V17_MAGIC) {\r\n throw new Error(`${parserName}: invalid v17 magic`);\r\n }\r\n const version = readU16LE(data, 8);\r\n if (version !== V17_EXPECTED_VERSION) {\r\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\r\n }\r\n const kind = readU8(data, 10);\r\n if (kind !== expectedKind) {\r\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\r\n }\r\n}\r\n\r\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\r\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\r\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\r\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\r\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\r\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\r\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\r\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\r\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\r\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\r\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\r\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\r\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\r\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\r\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\r\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\r\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\r\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\r\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\r\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\r\n// PortfolioLegV16Account (144 bytes each):\r\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\r\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\r\nconst PF_LEG_SIZE = 144;\r\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\r\nconst PF_LEGS_COUNT = 16;\r\n// PortfolioSourceDomainV16Account (196 bytes each):\r\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\r\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\r\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\r\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\r\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\r\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\r\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\r\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\r\nconst PF_SOURCE_DOMAIN_SIZE = 196;\r\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\r\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\r\n// HealthCertV16Account (121 bytes):\r\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\r\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\r\n// CloseProgressLedgerV16Account (188 bytes):\r\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\r\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\r\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\r\n// ResolvedPayoutReceiptV16Account (66 bytes):\r\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\r\n\r\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\r\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\r\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\r\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\r\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\r\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\r\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\r\n// noted above (188) does not even match its own field breakdown (sums to 184; see\r\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\r\n// the same anchor-from-the-end offset).\r\nconst PF_MATCHER_CONFIG_LEN = 104;\r\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\r\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\r\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\r\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\r\n\r\n/** Per-leg decoded data returned by parsePortfolioV17. */\r\nexport interface PortfolioLegV17 {\r\n active: boolean;\r\n assetIndex: number;\r\n marketId: bigint;\r\n /** 0 = long, 1 = short */\r\n side: number;\r\n basisPosQ: bigint;\r\n aBasis: bigint;\r\n kSnap: bigint;\r\n fSnap: bigint;\r\n epochSnap: bigint;\r\n lossWeight: bigint;\r\n bSnap: bigint;\r\n bRem: bigint;\r\n bEpochSnap: bigint;\r\n bStale: boolean;\r\n stale: boolean;\r\n}\r\n\r\n/** Per source-domain slot returned by parsePortfolioV17. */\r\nexport interface PortfolioSourceDomainV17 {\r\n domain: number;\r\n sourceClaimMarketId: bigint;\r\n sourceClaimBoundNum: bigint;\r\n sourceClaimLienedNum: bigint;\r\n sourceClaimCounterpartyLienedNum: bigint;\r\n sourceClaimInsuranceLienedNum: bigint;\r\n sourceLienEffectiveReserved: bigint;\r\n sourceLienCounterpartyBackingNum: bigint;\r\n sourceLienInsuranceBackingNum: bigint;\r\n sourceLienFeeLastSlot: bigint;\r\n sourceClaimImpairedNum: bigint;\r\n sourceLienImpairedEffectiveReserved: bigint;\r\n sourceLienCapitalAtRiskFeeRevenue: bigint;\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\r\n}\r\n\r\n/** Decoded v17 PortfolioAccountV16Account. */\r\nexport interface PortfolioV17 {\r\n /** Market group this portfolio belongs to. */\r\n marketGroupId: PublicKey;\r\n /** Portfolio account identity pubkey (immutable PDA). */\r\n portfolioAccountId: PublicKey;\r\n /** Owner wallet pubkey from the provenance header. */\r\n provenanceOwner: PublicKey;\r\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\r\n owner: PublicKey;\r\n /** Collateral capital in atoms (u128). */\r\n capital: bigint;\r\n /** Unrealised P&L in atoms (i128). */\r\n pnl: bigint;\r\n /** Capital reserved for pending payout (u128). */\r\n reservedPnl: bigint;\r\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\r\n residualCrystallizedLossAtomsTotal: bigint;\r\n /** Genesis farming: cumulative spent principal atoms (u128). */\r\n residualSpentPrincipalAtomsTotal: bigint;\r\n /** Genesis farming: cumulative received atoms (u128). */\r\n residualReceivedAtomsTotal: bigint;\r\n /** Fee credits (i128, can be negative). */\r\n feeCredits: bigint;\r\n /** Cancel-deposit escrow holding (u128). */\r\n cancelDepositEscrow: bigint;\r\n /** Slot when fees were last accrued. */\r\n lastFeeSlot: bigint;\r\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\r\n activeBitmap: bigint;\r\n /** All 16 position leg slots (active or empty). */\r\n legs: PortfolioLegV17[];\r\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\r\n sourceDomains: PortfolioSourceDomainV17[];\r\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\r\n matcherProgram: PublicKey;\r\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\r\n matcherContext: PublicKey;\r\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\r\n matcherDelegate: PublicKey;\r\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\r\n matcherEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Parse a v17 PortfolioAccountV16Account from raw account data.\r\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\r\n *\r\n * @param data - Raw account bytes from `connection.getAccountInfo`.\r\n * @returns Decoded portfolio state.\r\n * @throws If data is too short or magic does not match.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(portfolioPubkey);\r\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\r\n * console.log('capital:', portfolio.capital);\r\n * ```\r\n */\r\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\r\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\r\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\r\n if (data.length < MIN_PORTFOLIO_BYTES) {\r\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\r\n }\r\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\r\n\r\n // Provenance header\r\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\r\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\r\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\r\n\r\n // Body fields\r\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\r\n const capital = readU128LE(data, PF_CAPITAL_OFF);\r\n const pnl = readI128LE(data, PF_PNL_OFF);\r\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\r\n\r\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\r\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\r\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\r\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\r\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\r\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\r\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\r\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\r\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\r\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\r\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\r\n\r\n // Legs\r\n const legs: PortfolioLegV17[] = [];\r\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\r\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\r\n if (data.length < b + PF_LEG_SIZE) break;\r\n legs.push({\r\n active: data[b] !== 0,\r\n assetIndex: readU32LE(data, b + 1),\r\n marketId: readU64LE(data, b + 5),\r\n side: data[b + 13],\r\n basisPosQ: readI128LE(data, b + 14),\r\n aBasis: readU128LE(data, b + 30),\r\n kSnap: readI128LE(data, b + 46),\r\n fSnap: readI128LE(data, b + 62),\r\n epochSnap: readU64LE(data, b + 78),\r\n lossWeight: readU128LE(data, b + 86),\r\n bSnap: readU128LE(data, b + 102),\r\n bRem: readU128LE(data, b + 118),\r\n bEpochSnap: readU64LE(data, b + 134),\r\n bStale: data[b + 142] !== 0,\r\n stale: data[b + 143] !== 0,\r\n });\r\n }\r\n\r\n // Source domains\r\n const sourceDomains: PortfolioSourceDomainV17[] = [];\r\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\r\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\r\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\r\n sourceDomains.push({\r\n domain: readU32LE(data, b + 0),\r\n sourceClaimMarketId: readU64LE(data, b + 4),\r\n sourceClaimBoundNum: readU128LE(data, b + 12),\r\n sourceClaimLienedNum: readU128LE(data, b + 28),\r\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\r\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\r\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\r\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\r\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\r\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\r\n sourceClaimImpairedNum: readU128LE(data, b + 132),\r\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\r\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\r\n });\r\n }\r\n\r\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\r\n : PublicKey.default;\r\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\r\n : PublicKey.default;\r\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\r\n : PublicKey.default;\r\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\r\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\r\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\r\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\r\n // for an account the program itself would refuse to operate on.\r\n let matcherEnabled = false;\r\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\r\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\r\n if (rawEnabled > 1n) {\r\n throw new Error(\r\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\r\n );\r\n }\r\n matcherEnabled = rawEnabled === 1n;\r\n }\r\n\r\n return {\r\n marketGroupId,\r\n portfolioAccountId,\r\n provenanceOwner,\r\n owner,\r\n capital,\r\n pnl,\r\n reservedPnl,\r\n residualCrystallizedLossAtomsTotal,\r\n residualSpentPrincipalAtomsTotal,\r\n residualReceivedAtomsTotal,\r\n feeCredits,\r\n cancelDepositEscrow,\r\n lastFeeSlot,\r\n activeBitmap,\r\n legs,\r\n sourceDomains,\r\n matcherProgram,\r\n matcherContext,\r\n matcherDelegate,\r\n matcherEnabled,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpVaultRegistryV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\r\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\r\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\r\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\r\n// _padding[6]+_reserved[16] = 160 bytes.\r\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\r\n\r\n/** Decoded v17 LpVaultRegistryV16 account. */\r\nexport interface LpVaultRegistryV17 {\r\n marketGroup: PublicKey;\r\n lpMint: PublicKey;\r\n totalLpSharesOutstanding: bigint;\r\n insuranceFeeSnapshotAtoms: bigint;\r\n feeDistributionTotalAtoms: bigint;\r\n epoch: bigint;\r\n redemptionCooldownSlots: bigint;\r\n feeShareBps: number;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n paused: boolean;\r\n version: number;\r\n bump: number;\r\n mintBump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\r\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP vault registry state.\r\n * @throws If data is shorter than 176 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(registryPubkey);\r\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\r\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\r\n * ```\r\n */\r\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\r\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\r\n throw new Error(\r\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\r\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\r\n totalLpSharesOutstanding: readU128LE(data, b + 64),\r\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\r\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\r\n epoch: readU64LE(data, b + 112),\r\n redemptionCooldownSlots: readU64LE(data, b + 120),\r\n feeShareBps: readU16LE(data, b + 128),\r\n oiReservationThresholdBps: readU16LE(data, b + 130),\r\n domain: readU16LE(data, b + 132),\r\n paused: data[b + 134] !== 0,\r\n version: data[b + 135],\r\n bump: data[b + 136],\r\n mintBump: data[b + 137],\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpRedemptionV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\r\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\r\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\r\n\r\n/** Decoded v17 LpRedemptionV16 account. */\r\nexport interface LpRedemptionV17 {\r\n registry: PublicKey;\r\n redeemer: PublicKey;\r\n /** LP shares requested for redemption (u128). */\r\n shares: bigint;\r\n /** Slot when RequestRedeemLpShares was called. */\r\n requestSlot: bigint;\r\n version: number;\r\n bump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpRedemptionV16 account from raw bytes.\r\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP redemption request state.\r\n * @throws If data is shorter than 112 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(redemptionPubkey);\r\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\r\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\r\n * ```\r\n */\r\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\r\n if (data.length < LP_REDEMPTION_TOTAL) {\r\n throw new Error(\r\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\r\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\r\n shares: readU128LE(data, b + 64),\r\n requestSlot: readU64LE(data, b + 80),\r\n version: data[b + 88],\r\n bump: data[b + 89],\r\n };\r\n}\r\n\r\n/**\r\n * Parse all used accounts.\r\n */\r\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\r\n const indices = parseUsedIndices(data);\r\n const maxIdx = maxAccountIndex(data.length);\r\n const validIndices = indices.filter(idx => idx < maxIdx);\r\n const droppedCount = indices.length - validIndices.length;\r\n if (droppedCount > 0) {\r\n console.warn(\r\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\r\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\r\n );\r\n }\r\n return validIndices.map(idx => ({\r\n idx,\r\n account: parseAccount(data, idx),\r\n }));\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Encode a u16 as a 2-byte little-endian buffer.\r\n * Used for PDA seed segments that include a domain/index as u16 LE.\r\n */\r\nfunction u16LE(value: number): Uint8Array {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isInteger(value) ||\r\n value < 0 ||\r\n value > 0xffff\r\n ) {\r\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive vault authority PDA.\r\n * Seeds: [\"vault\", slab_key]\r\n *\r\n * Mirrors `derive_vault_authority(program_id, market_key)` in\r\n * `percolator-prog/src/v16_program.rs:17339-17341`.\r\n */\r\nexport function deriveVaultAuthority(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"vault\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * SPL Associated Token Account program.\r\n *\r\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\r\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\r\n */\r\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\r\n);\r\n\r\n/**\r\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\r\n *\r\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\r\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\r\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\r\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\r\n * ATA's middle seed is always this program id.\r\n */\r\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n);\r\n\r\n/**\r\n * Derive the CANONICAL vault token account for a market + collateral mint.\r\n *\r\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\r\n *\r\n * ```text\r\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\r\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\r\n * ```\r\n *\r\n * Mirrors `canonical_vault_address(vault_authority, mint)`\r\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\r\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\r\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\r\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\r\n * without it an attacker could route deposits to a second `vault_authority`-owned account\r\n * and strand honest withdrawals against the canonical one.\r\n *\r\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\r\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\r\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\r\n * address with a detected token program would produce a key the program rejects with\r\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\r\n *\r\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\r\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\r\n * token path.\r\n *\r\n * @param programId - The Percolator wrapper program ID (the market's owner).\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\r\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketData);\r\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * ```\r\n */\r\nexport function deriveCanonicalVault(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\r\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\r\n}\r\n\r\n/**\r\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\r\n *\r\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\r\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\r\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\r\n *\r\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\r\n * @param mint - The market's collateral mint.\r\n * @returns `[vaultTokenAccount, bump]`\r\n *\r\n * @example\r\n * ```ts\r\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\r\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\r\n * ```\r\n */\r\nexport function deriveCanonicalVaultForAuthority(\r\n vaultAuthority: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n vaultAuthority.toBytes(),\r\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n ASSOCIATED_TOKEN_PROGRAM_ID\r\n );\r\n}\r\n\r\n/** Both halves of a market's vault, as required by tags 84 and 87. */\r\nexport interface MarketVaultAccounts {\r\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\r\n vaultAuthority: PublicKey;\r\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\r\n vaultAuthorityBump: number;\r\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\r\n vaultToken: PublicKey;\r\n /** Bump for `vaultToken`. */\r\n vaultTokenBump: number;\r\n /** The token program that must be passed alongside — always legacy SPL Token. */\r\n tokenProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\r\n *\r\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\r\n * the vault token account, the vault authority PDA and the token program as three separate\r\n * accounts that must agree with one another; deriving them together makes disagreement\r\n * impossible.\r\n *\r\n * Account positions:\r\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\r\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\r\n *\r\n * @param programId - The Percolator wrapper program ID.\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint.\r\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\r\n *\r\n * @example\r\n * ```ts\r\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * const keys = [\r\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\r\n * { pubkey: marketPk, isSigner: false, isWritable: true },\r\n * { pubkey: destToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\r\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\r\n * ];\r\n * ```\r\n */\r\nexport function deriveMarketVaultAccounts(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): MarketVaultAccounts {\r\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\r\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\r\n vaultAuthority,\r\n mint\r\n );\r\n return {\r\n vaultAuthority,\r\n vaultAuthorityBump,\r\n vaultToken,\r\n vaultTokenBump,\r\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\r\n };\r\n}\r\n\r\n/**\r\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\r\n * Seeds: [\"lp_vault_mint\", slab_key]\r\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\r\n */\r\nexport function deriveInsuranceLpMint(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\nconst LP_INDEX_U16_MAX = 0xffff;\r\n\r\n/**\r\n * Derive LP PDA for TradeCpi.\r\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\r\n */\r\nexport function deriveLpPda(\r\n programId: PublicKey,\r\n slab: PublicKey,\r\n lpIdx: number\r\n): [PublicKey, number] {\r\n if (\r\n typeof lpIdx !== \"number\" ||\r\n !Number.isInteger(lpIdx) ||\r\n lpIdx < 0 ||\r\n lpIdx > LP_INDEX_U16_MAX\r\n ) {\r\n throw new Error(\r\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\r\n );\r\n }\r\n const idxBuf = new Uint8Array(2);\r\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DEX Program IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/** PumpSwap AMM program ID. */\r\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\r\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\r\n);\r\n\r\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\r\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\r\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\r\n);\r\n\r\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\r\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\r\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth Push Oracle\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Pyth Push Oracle program on mainnet. */\r\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\r\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Creator Lock PDA (PERC-627)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Seed used to derive the creator lock PDA.\r\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\r\n */\r\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\r\n\r\n/**\r\n * Derive the creator lock PDA for a given slab.\r\n * Seeds: [\"creator_lock\", slab_key]\r\n *\r\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\r\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\r\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\r\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\r\n *\r\n * @param programId - The percolator program ID.\r\n * @param slab - The slab (market) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * ```\r\n */\r\nexport function deriveCreatorLockPda(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// LP Vault PDAs (v17 — tags 74-80)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the LP Vault registry PDA.\r\n * Seeds: [\"lp_vault\", marketGroup]\r\n *\r\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\r\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\r\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\r\n *\r\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpVaultRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP redemption ticket PDA for a specific redeemer.\r\n * Seeds: [\"lp_redemption\", registry, redeemer]\r\n *\r\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\r\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\r\n * @param redeemer - The wallet public key of the redeemer.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\r\n * ```\r\n */\r\nexport function deriveLpRedemption(\r\n programId: PublicKey,\r\n registry: PublicKey,\r\n redeemer: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_redemption\"),\r\n registry.toBytes(),\r\n redeemer.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP backing-domain ledger PDA.\r\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\r\n *\r\n * Required by: DepositToLpVault (tag 75) at accounts[7],\r\n * LpVaultCrankFees (tag 78) at accounts[3].\r\n *\r\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\r\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\r\n * (line 3127) — domain is encoded as 2-byte little-endian.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\r\n * ```\r\n */\r\nexport function deriveLpBackingLedger(\r\n programId: PublicKey,\r\n marketGroup: PublicKey,\r\n domainIdx: number\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_backing_ledger\"),\r\n marketGroup.toBytes(),\r\n u16LE(domainIdx),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP escrow SPL token account PDA.\r\n * Seeds: [\"lp_escrow\", marketGroup]\r\n *\r\n * The escrow is owned by the registry PDA and holds LP tokens during the\r\n * redemption window. Required by ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\r\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpEscrow(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NFT Registry PDA (v17 — tag 73)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the per-market NFT program-id registry PDA.\r\n * Seeds: [\"nft_registry\", marketGroup]\r\n *\r\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\r\n * (TransferPortfolioOwnership, tag 72).\r\n *\r\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\r\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveNftRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the matcher delegate PDA.\r\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\r\n * (all six seed segments are 32-byte public keys)\r\n *\r\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\r\n * The program signs CPI calls to the external matcher program using this PDA.\r\n *\r\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\r\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param market - The market (slab) public key.\r\n * @param accountB - The maker/LP portfolio account public key.\r\n * @param accountBOwner - The owner of accountB.\r\n * @param matcherProg - The external matcher program public key.\r\n * @param matcherCtx - The matcher context account public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [delegatePda] = deriveMatcherDelegate(\r\n * PROGRAM_ID,\r\n * marketKey,\r\n * accountBKey,\r\n * accountBOwnerKey,\r\n * matcherProgKey,\r\n * matcherCtxKey,\r\n * );\r\n * ```\r\n */\r\nexport function deriveMatcherDelegate(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n accountB: PublicKey,\r\n accountBOwner: PublicKey,\r\n matcherProg: PublicKey,\r\n matcherCtx: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"matcher\"),\r\n market.toBytes(),\r\n accountB.toBytes(),\r\n accountBOwner.toBytes(),\r\n matcherProg.toBytes(),\r\n matcherCtx.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\r\nconst PYTH_FEED_ID_HEX_LEN = 64;\r\n\r\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\r\n let s = feedIdHex.trim();\r\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\r\n s = s.slice(2);\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Derive the Pyth Push Oracle PDA for a given feed ID.\r\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\r\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\r\n */\r\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\r\n const normalized = normalizePythFeedIdHex(feedIdHex);\r\n if (!FEED_HEX_RE.test(normalized)) {\r\n throw new Error(\r\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\r\n }\r\n const feedId = new Uint8Array(32);\r\n for (let i = 0; i < 32; i++) {\r\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\r\n }\r\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\r\n return PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n PYTH_PUSH_ORACLE_PROGRAM_ID,\r\n );\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n getAssociatedTokenAddress,\r\n getAssociatedTokenAddressSync,\r\n getAccount,\r\n Account,\r\n TOKEN_PROGRAM_ID,\r\n} from \"@solana/spl-token\";\r\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\r\n\r\n/**\r\n * Get the associated token address for an owner and mint.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport async function getAta(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Synchronous version of getAta.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport function getAtaSync(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): PublicKey {\r\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Fetch token account info.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n * Throws if account doesn't exist.\r\n */\r\nexport async function fetchTokenAccount(\r\n connection: Connection,\r\n address: PublicKey,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAccount(connection, address, undefined, tokenProgramId);\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n parseHeader,\r\n parseConfig,\r\n parseParams,\r\n detectSlabLayout,\r\n isV17MarketAccount,\r\n parseWrapperConfigV17,\r\n SLAB_TIERS_V1M,\r\n SLAB_TIERS_V1M2,\r\n SLAB_TIERS_V2,\r\n SLAB_TIERS_V_ADL,\r\n SLAB_TIERS_V12_1,\r\n SLAB_TIERS_V12_15,\r\n SLAB_TIERS_V12_17,\r\n SLAB_TIERS_V12_19,\r\n SLAB_TIERS_V_SETDEXPOOL,\r\n type SlabHeader,\r\n type MarketConfig,\r\n type EngineState,\r\n type RiskParams,\r\n type SlabLayout,\r\n type WrapperConfigV17,\r\n} from \"./slab.js\";\r\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\r\nimport { type Network } from \"../config/program-ids.js\";\r\n\r\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\r\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\r\n/** V0 bitmap offset within engine struct (deployed devnet program) */\r\nconst ENGINE_BITMAP_OFF_V0 = 320;\r\n\r\n/**\r\n * A discovered Percolator market from on-chain program accounts.\r\n */\r\nexport interface DiscoveredMarket {\r\n slabAddress: PublicKey;\r\n /** The program that owns this slab account */\r\n programId: PublicKey;\r\n /**\r\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\r\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\r\n */\r\n header: SlabHeader;\r\n /**\r\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\r\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\r\n */\r\n config: MarketConfig;\r\n /**\r\n * v12.x engine state (bitmap, account counts).\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n engine: EngineState;\r\n /**\r\n * v12.x risk parameters.\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n params: RiskParams;\r\n /**\r\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\r\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\r\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\r\n * Absent for v12 slab accounts.\r\n *\r\n * Use `isV17Market(m)` to narrow the type:\r\n * ```ts\r\n * if (m.configV17) {\r\n * console.log(m.configV17.collateralMint.toBase58());\r\n * }\r\n * ```\r\n */\r\n configV17?: WrapperConfigV17;\r\n}\r\n\r\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\r\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\r\n * These are the first 8 bytes of every v17 percolator-owned market group account.\r\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\r\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\r\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\r\n */\r\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\r\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\r\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\r\n *\r\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\r\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\r\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\r\n *\r\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\r\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\r\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\r\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\r\n *\r\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\r\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\r\n * See GH #1109, GH #1112.\r\n *\r\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\r\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\r\n */\r\n/**\r\n * Default slab tiers for the current mainnet program (v12.17).\r\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\r\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\r\n */\r\nexport const SLAB_TIERS = {\r\n small: SLAB_TIERS_V12_17[\"small\"],\r\n medium: SLAB_TIERS_V12_17[\"medium\"],\r\n large: SLAB_TIERS_V12_17[\"large\"],\r\n} as const;\r\n\r\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\r\nexport const SLAB_TIERS_V0 = {\r\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\r\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\r\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\r\n} as const;\r\n\r\n/**\r\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\r\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\r\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\r\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\r\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\r\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\r\n * micro = 17,064 (64 slots)\r\n * small = 65,088 (256 slots)\r\n * medium = 257,184 (1,024 slots)\r\n * large = 1,025,568 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D = {\r\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\r\n} as const;\r\n\r\n/**\r\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\r\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\r\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\r\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\r\n * micro = 17,080 (64 slots)\r\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\r\n * medium = 257,200 (1,024 slots)\r\n * large = 1,025,584 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D_LEGACY = {\r\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\r\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\r\n} as const;\r\n\r\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\r\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\r\n */\r\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\r\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\r\n\r\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\r\n\r\n/** Calculate slab data size for arbitrary account count.\r\n *\r\n * Layout (SBF, u128 align = 8):\r\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\r\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\r\n * + bitmap: ceil(N/64)*8\r\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\r\n * + next_free: N*2\r\n * + pad to 8-byte alignment for Account array\r\n * + accounts: N*248\r\n *\r\n * Must match the on-chain program's SLAB_LEN exactly.\r\n */\r\nexport function slabDataSize(maxAccounts: number): number {\r\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\r\n const ENGINE_OFF_V0 = 480;\r\n const ENGINE_BITMAP_OFF_V0 = 320;\r\n const ACCOUNT_SIZE_V0 = 240;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\r\n}\r\n\r\n/**\r\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\r\n *\r\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\r\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\r\n * difference at high account counts or a post-PERC-118 struct addition in the\r\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\r\n * verified on-chain) over this formula for production use.\r\n */\r\nexport function slabDataSizeV1(maxAccounts: number): number {\r\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\r\n const ENGINE_BITMAP_OFF_V1 = 656;\r\n const ACCOUNT_SIZE_V1 = 248;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\r\n}\r\n\r\n/**\r\n * Validate that a slab data size matches one of the known tier sizes.\r\n * Use this to catch tier↔program mismatches early (PERC-277).\r\n *\r\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\r\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\r\n * @returns true if sizes match, false if there's a mismatch\r\n */\r\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\r\n return dataSize === programSlabLen;\r\n}\r\n\r\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\r\nconst ALL_SLAB_SIZES = [\r\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\r\n];\r\n\r\n/** Legacy constant for backward compat */\r\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\r\n\r\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\r\nconst HEADER_SLICE_LENGTH = 1940;\r\n\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\r\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\r\n *\r\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\r\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\r\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\r\n */\r\nexport function parseEngineLight(\r\n data: Uint8Array,\r\n layout: SlabLayout | null,\r\n maxAccounts: number = 4096,\r\n): EngineState {\r\n const isV0 = !layout || layout.version === 0;\r\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\r\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\r\n\r\n const minLen = base + bitmapOff;\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\r\n }\r\n\r\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\r\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\r\n\r\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\r\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\r\n\r\n if (isV0) {\r\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\r\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\r\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\r\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\r\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\r\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\r\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\r\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: readU128LE(data, base + 32),\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + 104),\r\n fundingIndexQpbE6: readI128LE(data, base + 112),\r\n lastFundingSlot: readU64LE(data, base + 128),\r\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: readU64LE(data, base + 144),\r\n maxCrankStalenessSlots: readU64LE(data, base + 152),\r\n totalOpenInterest: readU128LE(data, base + 160),\r\n longOi: 0n,\r\n shortOi: 0n,\r\n cTot: readU128LE(data, base + 176),\r\n pnlPosTot: readU128LE(data, base + 192),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: readU16LE(data, base + 208),\r\n gcCursor: readU16LE(data, base + 210),\r\n lastSweepStartSlot: readU64LE(data, base + 216),\r\n lastSweepCompleteSlot: readU64LE(data, base + 224),\r\n crankCursor: readU16LE(data, base + 232),\r\n sweepStartIdx: readU16LE(data, base + 234),\r\n lifetimeLiquidations: readU64LE(data, base + 240),\r\n lifetimeForceCloses: readU64LE(data, base + 248),\r\n netLpPos: readI128LE(data, base + 256),\r\n lpSumAbs: readU128LE(data, base + 272),\r\n lpMaxAbs: readU128LE(data, base + 288),\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n, // V0 engine has no mark_price field\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\r\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\r\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\r\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\r\n // (the currently-deployed mainnet tier line) were being routed through this branch's\r\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\r\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\r\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\r\n // per the layout-driven branch's own comment below, which already documents that it\r\n // covers V12_15/17/19 — that was the intended path all along.\r\n\r\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\r\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\r\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\r\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\r\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\r\n // that share engineOff=640 but have different internal struct sizes.\r\n if (layout !== null) {\r\n const l = layout;\r\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\r\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\r\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\r\n // struct for that tier has no such field, and `base + (-1)` would read\r\n // garbage straddling the byte before the engine region rather than failing.\r\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\r\n // below goes through these instead of reading the offset directly.\r\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\r\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\r\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\r\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\r\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + l.engineInsuranceOff),\r\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\r\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\r\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\r\n },\r\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\r\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\r\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\r\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\r\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\r\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\r\n : readI128LE(data, base + l.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\r\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\r\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\r\n totalOpenInterest: u128At(l.engineTotalOiOff),\r\n longOi: u128At(l.engineLongOiOff),\r\n shortOi: u128At(l.engineShortOiOff),\r\n cTot: readU128LE(data, base + l.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: u16At(l.engineLiqCursorOff),\r\n gcCursor: u16At(l.engineGcCursorOff),\r\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\r\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\r\n crankCursor: u16At(l.engineCrankCursorOff),\r\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\r\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\r\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\r\n netLpPos: i128At(l.engineNetLpPosOff),\r\n lpSumAbs: u128At(l.engineLpSumAbsOff),\r\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\r\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\r\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\r\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\r\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\r\n markPriceE6: u64At(l.engineMarkPriceOff),\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // layout === null: unrecognized slab format — callers should have skipped via the\r\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\r\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\r\n}\r\n\r\n/** Options for `discoverMarkets`. */\r\nexport interface DiscoverMarketsOptions {\r\n /**\r\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\r\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\r\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\r\n * Default: false (preserves original parallel behaviour).\r\n *\r\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\r\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\r\n */\r\n sequential?: boolean;\r\n /**\r\n * Delay in ms between sequential tier queries (only used when sequential=true).\r\n * Default: 200 ms.\r\n */\r\n interTierDelayMs?: number;\r\n /**\r\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\r\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\r\n */\r\n rateLimitBackoffMs?: number[];\r\n\r\n /**\r\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\r\n * at once to avoid accidental RPC storms from client code.\r\n *\r\n * Default: 6\r\n */\r\n maxParallelTiers?: number;\r\n\r\n /**\r\n * Hard cap on how many tier dataSize queries are attempted.\r\n * Default: all known tiers.\r\n */\r\n maxTierQueries?: number;\r\n\r\n /**\r\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\r\n *\r\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\r\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\r\n * mainnet RPCs that reject `getProgramAccounts`).\r\n *\r\n * The API returns slab addresses which are then fetched on-chain via\r\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\r\n *\r\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * });\r\n * ```\r\n */\r\n apiBaseUrl?: string;\r\n\r\n /**\r\n * Timeout in ms for the API fallback HTTP request.\r\n * Only used when `apiBaseUrl` is set.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n apiTimeoutMs?: number;\r\n\r\n /**\r\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\r\n *\r\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\r\n * `discoverMarkets` will fall back to a bundled static list of known slab\r\n * addresses for the specified network. The addresses are fetched on-chain\r\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * If not set, tier-3 fallback is disabled.\r\n *\r\n * The static list can be extended at runtime via `registerStaticMarkets()`.\r\n *\r\n * @see {@link registerStaticMarkets} to add addresses at runtime\r\n * @see {@link getStaticMarkets} to inspect the current static list\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * network: \"mainnet\", // enables tier-3 static fallback\r\n * });\r\n * ```\r\n */\r\n network?: Network;\r\n}\r\n\r\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\r\nfunction isRateLimitError(err: unknown): boolean {\r\n if (!err) return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return (\r\n msg.includes(\"429\") ||\r\n msg.toLowerCase().includes(\"rate limit\") ||\r\n msg.toLowerCase().includes(\"too many requests\")\r\n );\r\n}\r\n\r\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\r\nfunction withJitter(delayMs: number): number {\r\n const half = Math.floor(delayMs / 2);\r\n return half + Math.floor(Math.random() * (delayMs - half + 1));\r\n}\r\n\r\n/**\r\n * Discover all Percolator markets owned by the given program.\r\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\r\n *\r\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\r\n */\r\nexport async function discoverMarkets(\r\n connection: Connection,\r\n programId: PublicKey,\r\n options: DiscoverMarketsOptions = {},\r\n): Promise {\r\n const {\r\n sequential = false,\r\n interTierDelayMs = 200,\r\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\r\n maxParallelTiers = 6,\r\n } = options;\r\n\r\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\r\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\r\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\r\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\r\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\r\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\r\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\r\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\r\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\r\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\r\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\r\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\r\n //\r\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\r\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\r\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\r\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\r\n const ALL_TIERS_RAW = [\r\n ...Object.values(SLAB_TIERS), // v12.17 (default)\r\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\r\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\r\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\r\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\r\n ...Object.values(SLAB_TIERS_V0),\r\n ...Object.values(SLAB_TIERS_V1D),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\r\n ...Object.values(SLAB_TIERS_V2),\r\n ...Object.values(SLAB_TIERS_V1M),\r\n ...Object.values(SLAB_TIERS_V1M2),\r\n ...Object.values(SLAB_TIERS_V_ADL),\r\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\r\n ];\r\n const tierBySize = new Map();\r\n for (const tier of ALL_TIERS_RAW) {\r\n const existing = tierBySize.get(tier.dataSize);\r\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\r\n tierBySize.set(tier.dataSize, tier);\r\n }\r\n }\r\n const ALL_TIERS = [...tierBySize.values()];\r\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\r\n let rawAccounts: RawEntry[] = [];\r\n\r\n /**\r\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\r\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\r\n */\r\n async function fetchTierWithRetry(\r\n tier: { dataSize: number; maxAccounts: number },\r\n ): Promise {\r\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\r\n try {\r\n const results = await connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\r\n } catch (err) {\r\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\r\n const delay = withJitter(rateLimitBackoffMs[attempt]);\r\n console.warn(\r\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\r\n );\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n // Non-429 or exhausted retries\r\n console.warn(\r\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n return [];\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\r\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\r\n\r\n // Avoid accidental `0`/negative or NaN causing infinite loops.\r\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\r\n\r\n try {\r\n if (sequential) {\r\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\r\n for (let i = 0; i < tiersToQuery.length; i++) {\r\n const tier = tiersToQuery[i];\r\n const entries = await fetchTierWithRetry(tier);\r\n rawAccounts.push(...entries);\r\n if (i < tiersToQuery.length - 1) {\r\n await new Promise(r => setTimeout(r, interTierDelayMs));\r\n }\r\n }\r\n } else {\r\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\r\n // getProgramAccounts calls at once from a single client call.\r\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\r\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\r\n const queries = chunk.map(tier =>\r\n connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n }).then(results =>\r\n results.map(entry => ({\r\n ...entry,\r\n maxAccounts: tier.maxAccounts,\r\n dataSize: tier.dataSize,\r\n })),\r\n ),\r\n );\r\n\r\n const results = await Promise.allSettled(queries);\r\n for (const result of results) {\r\n if (result.status === \"fulfilled\") {\r\n for (const entry of result.value) {\r\n rawAccounts.push(entry as RawEntry);\r\n }\r\n } else {\r\n console.warn(\r\n \"[discoverMarkets] Tier query rejected:\",\r\n result.reason instanceof Error ? result.reason.message : result.reason,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\r\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\r\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\r\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\r\n try {\r\n const v17Results = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\r\n encoding: \"base64\",\r\n },\r\n },\r\n ],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n for (const e of v17Results) {\r\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\r\n }\r\n } catch {\r\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\r\n }\r\n\r\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\r\n // account size changed; RPC returns no error, so we must fallback on empty results too.\r\n if (rawAccounts.length === 0) {\r\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\r\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\r\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\r\n err instanceof Error ? err.message : err,\r\n );\r\n try {\r\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n } catch (memcmpErr) {\r\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\r\n console.warn(\r\n \"[discoverMarkets] memcmp fallback also failed:\",\r\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\r\n );\r\n }\r\n }\r\n\r\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\r\n // rejects it) and an API base URL is configured, fall back to the REST API to\r\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\r\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\r\n console.warn(\r\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\r\n );\r\n try {\r\n const apiResult = await discoverMarketsViaApi(\r\n connection,\r\n programId,\r\n options.apiBaseUrl,\r\n { timeoutMs: options.apiTimeoutMs },\r\n );\r\n if (apiResult.length > 0) {\r\n return apiResult;\r\n }\r\n // API returned 0 markets — fall through to tier 3\r\n console.warn(\r\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\r\n );\r\n } catch (apiErr) {\r\n console.warn(\r\n \"[discoverMarkets] API fallback also failed:\",\r\n apiErr instanceof Error ? apiErr.message : apiErr,\r\n );\r\n // Fall through to tier 3\r\n }\r\n }\r\n\r\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\r\n // the REST API failed (or returned 0 results) and a network hint is provided,\r\n // use the bundled static market list as a last-resort address directory.\r\n if (rawAccounts.length === 0 && options.network) {\r\n const staticEntries = getStaticMarkets(options.network);\r\n if (staticEntries.length > 0) {\r\n console.warn(\r\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\r\n );\r\n try {\r\n return await discoverMarketsViaStaticBundle(\r\n connection,\r\n programId,\r\n staticEntries,\r\n );\r\n } catch (staticErr) {\r\n console.warn(\r\n \"[discoverMarkets] Static bundle fallback also failed:\",\r\n staticErr instanceof Error ? staticErr.message : staticErr,\r\n );\r\n // Fall through to return empty array\r\n }\r\n } else {\r\n console.warn(\r\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\r\n );\r\n }\r\n }\r\n\r\n const accounts = rawAccounts;\r\n\r\n const markets: DiscoveredMarket[] = [];\r\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\r\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\r\n const seenPubkeys = new Set();\r\n\r\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\r\n const pkStr = pubkey.toBase58();\r\n if (seenPubkeys.has(pkStr)) continue;\r\n seenPubkeys.add(pkStr);\r\n const data = new Uint8Array(account.data);\r\n\r\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\r\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\r\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\r\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\r\n // memcmp fallback or if the account happens to match a tier size by coincidence.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\r\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\r\n // — are not mis-parsed as markets.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) continue;\r\n\r\n // Detect layout from actual slab size — not slice length — so parse functions\r\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\r\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\r\n const layout = detectSlabLayout(dataSize, data);\r\n\r\n if (!layout) {\r\n console.warn(\r\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n/**\r\n * Options for `getMarketsByAddress`.\r\n */\r\nexport interface GetMarketsByAddressOptions {\r\n /**\r\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\r\n * Solana limits a single call to 100 accounts; callers may lower this\r\n * to reduce per-request payload size or avoid 429s.\r\n *\r\n * Default: 100 (Solana maximum).\r\n */\r\n batchSize?: number;\r\n\r\n /**\r\n * Delay in ms between batches when the address list exceeds `batchSize`.\r\n * Helps avoid rate-limiting on public RPCs.\r\n *\r\n * Default: 0 (no delay).\r\n */\r\n interBatchDelayMs?: number;\r\n}\r\n\r\n/**\r\n * Fetch and parse Percolator markets by their known slab addresses.\r\n *\r\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\r\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\r\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\r\n *\r\n * Callers must already know the market slab addresses (e.g. from an indexer,\r\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param programId - The Percolator program that owns these slabs\r\n * @param addresses - Array of slab account public keys to fetch\r\n * @param options - Optional batching/delay configuration\r\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection, PublicKey } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const slabs = [\r\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n * // ... more known slab addresses\r\n * ];\r\n *\r\n * const markets = await getMarketsByAddress(connection, programId, slabs);\r\n * console.log(`Found ${markets.length} markets`);\r\n * ```\r\n */\r\nexport async function getMarketsByAddress(\r\n connection: Connection,\r\n programId: PublicKey,\r\n addresses: PublicKey[],\r\n options: GetMarketsByAddressOptions = {},\r\n): Promise {\r\n if (addresses.length === 0) return [];\r\n\r\n const {\r\n batchSize = 100,\r\n interBatchDelayMs = 0,\r\n } = options;\r\n\r\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\r\n\r\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\r\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\r\n const fetched: AccountResult[] = [];\r\n\r\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\r\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\r\n\r\n const response = await connection.getMultipleAccountsInfo(batch);\r\n\r\n for (let i = 0; i < batch.length; i++) {\r\n const info = response[i];\r\n if (info && info.data) {\r\n if (!info.owner.equals(programId)) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\r\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\r\n );\r\n continue;\r\n }\r\n fetched.push({ pubkey: batch[i], data: info.data });\r\n }\r\n }\r\n\r\n // Inter-batch delay to avoid rate-limiting\r\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\r\n await new Promise(r => setTimeout(r, interBatchDelayMs));\r\n }\r\n }\r\n\r\n // Parse each account into a DiscoveredMarket\r\n const markets: DiscoveredMarket[] = [];\r\n\r\n for (const entry of fetched) {\r\n if (!entry) continue;\r\n const { pubkey, data: rawData } = entry;\r\n const data = new Uint8Array(rawData);\r\n\r\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\r\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n // v17 accounts have no slab header/config/engine/params; supply defaults so\r\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\r\n // to detect a v17 market.\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n // Validate v12 magic bytes\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\r\n );\r\n continue;\r\n }\r\n\r\n // Detect layout from full account data length\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// REST API-based market discovery (GH#59 / PERC-8424)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Shape of a single market entry returned by the Percolator REST API\r\n * (`GET /markets`). Only the fields needed for discovery are typed here;\r\n * the full API response may contain additional statistics fields.\r\n */\r\nexport interface ApiMarketEntry {\r\n slab_address: string;\r\n symbol?: string;\r\n name?: string;\r\n decimals?: number;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Options for {@link discoverMarketsViaApi}. */\r\nexport interface DiscoverMarketsViaApiOptions {\r\n /**\r\n * Timeout in ms for the HTTP request to the REST API.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n timeoutMs?: number;\r\n\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets by first querying the REST API for slab addresses,\r\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\r\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\r\n *\r\n * This is the recommended discovery path for mainnet users who do not have a\r\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\r\n *\r\n * The REST API acts as an address directory only — all market data is verified\r\n * on-chain via `getMarketsByAddress`, so the caller gets the same\r\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\r\n *\r\n * @param connection - Solana RPC connection (any endpoint, including public)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param apiBaseUrl - Base URL of the Percolator REST API\r\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\r\n * @param options - Optional timeout and on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts discovered via the API\r\n *\r\n * @example\r\n * ```ts\r\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const markets = await discoverMarketsViaApi(\r\n * connection,\r\n * programId,\r\n * \"https://percolatorlaunch.com/api\",\r\n * );\r\n * console.log(`Discovered ${markets.length} markets via API fallback`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaApi(\r\n connection: Connection,\r\n programId: PublicKey,\r\n apiBaseUrl: string,\r\n options: DiscoverMarketsViaApiOptions = {},\r\n): Promise {\r\n const { timeoutMs = 10_000, onChainOptions } = options;\r\n\r\n // Normalise base URL — strip trailing slash to avoid double-slash in path\r\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\r\n const url = `${base}/markets`;\r\n\r\n // Fetch market list from REST API\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: \"GET\",\r\n headers: { Accept: \"application/json\" },\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\r\n );\r\n }\r\n\r\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\r\n const apiMarkets = body.markets;\r\n\r\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\r\n return [];\r\n }\r\n\r\n // Extract valid slab addresses\r\n const addresses: PublicKey[] = [];\r\n for (const entry of apiMarkets) {\r\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slab_address));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\r\n );\r\n\r\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\r\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Static bundle fallback (PERC-8435 — tier 3)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options for {@link discoverMarketsViaStaticBundle}. */\r\nexport interface DiscoverMarketsViaStaticBundleOptions {\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets from a static list of known slab addresses.\r\n *\r\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\r\n * a bundled list of known slab addresses and fetches their full account data\r\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * The static list acts as an address directory only — all market data is verified\r\n * on-chain, so stale entries are silently skipped (the account won't have valid\r\n * magic bytes or will have been closed).\r\n *\r\n * @param connection - Solana RPC connection (any endpoint)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\r\n * @param options - Optional on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import {\r\n * discoverMarketsViaStaticBundle,\r\n * getStaticMarkets,\r\n * getProgramId,\r\n * } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const entries = getStaticMarkets(\"mainnet\");\r\n *\r\n * const markets = await discoverMarketsViaStaticBundle(\r\n * connection,\r\n * programId,\r\n * entries,\r\n * );\r\n * console.log(`Recovered ${markets.length} markets from static bundle`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaStaticBundle(\r\n connection: Connection,\r\n programId: PublicKey,\r\n entries: StaticMarketEntry[],\r\n options: DiscoverMarketsViaStaticBundleOptions = {},\r\n): Promise {\r\n if (entries.length === 0) return [];\r\n\r\n // Extract valid slab addresses from static entries\r\n const addresses: PublicKey[] = [];\r\n for (const entry of entries) {\r\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slabAddress));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\r\n );\r\n\r\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\r\n}\r\n","/**\r\n * Static market registry — bundled list of known Percolator slab addresses.\r\n *\r\n * This is the tier-3 fallback for `discoverMarkets()`: when both\r\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\r\n * the SDK falls back to this bundled list to bootstrap market discovery.\r\n *\r\n * The addresses are fetched on-chain via `getMarketsByAddress`\r\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\r\n * list only provides the *address directory* — no cached market data is used.\r\n *\r\n * ## Maintenance\r\n *\r\n * Update this list when new markets are deployed or old ones are retired.\r\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\r\n * or the REST API.\r\n *\r\n * @module\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport type { Network } from \"../config/program-ids.js\";\r\n\r\n/**\r\n * A single entry in the static market registry.\r\n *\r\n * Only the slab address (base58) is required. Optional metadata fields\r\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\r\n * they are **not** used for on-chain data and may become stale.\r\n */\r\nexport interface StaticMarketEntry {\r\n /** Base58-encoded slab account address. */\r\n slabAddress: string;\r\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\r\n symbol?: string;\r\n /** Optional descriptive name. */\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Known mainnet market slab addresses.\r\n *\r\n * These are the markets deployed to the mainnet Percolator program\r\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\r\n *\r\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\r\n */\r\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\r\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\r\n];\r\n\r\n/**\r\n * Known devnet market slab addresses.\r\n *\r\n * These are discovered from the devnet Percolator program\r\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\r\n *\r\n * **Last updated:** 2026-04-04.\r\n */\r\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\r\n // Populated from prior discoverMarkets() runs on devnet.\r\n // These serve as the tier-3 safety net for devnet users.\r\n];\r\n\r\n/**\r\n * Full static registry indexed by network.\r\n */\r\nconst STATIC_REGISTRY: Record = {\r\n mainnet: MAINNET_MARKETS,\r\n devnet: DEVNET_MARKETS,\r\n};\r\n\r\n/**\r\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\r\n * Keyed by network.\r\n */\r\nconst USER_MARKETS: Record = {\r\n mainnet: [],\r\n devnet: [],\r\n};\r\n\r\n/**\r\n * Get the bundled static market list for a given network.\r\n *\r\n * Returns the built-in list merged with any entries added via\r\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\r\n * automatically — user-registered entries take precedence.\r\n *\r\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\r\n * @returns Array of static market entries (may be empty if no markets are known)\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * const markets = getStaticMarkets(\"mainnet\");\r\n * console.log(`${markets.length} known mainnet slab addresses`);\r\n * ```\r\n */\r\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\r\n const builtin = STATIC_REGISTRY[network] ?? [];\r\n const user = USER_MARKETS[network] ?? [];\r\n\r\n if (user.length === 0) return [...builtin];\r\n\r\n // Merge: user entries override builtin entries with same slabAddress\r\n const seen = new Map();\r\n for (const entry of builtin) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n for (const entry of user) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n return [...seen.values()];\r\n}\r\n\r\n/**\r\n * Register additional static market entries at runtime.\r\n *\r\n * Use this to inject known slab addresses before calling `discoverMarkets()`\r\n * so that tier-3 fallback has addresses to work with — especially useful\r\n * right after mainnet launch when the bundled list may be empty.\r\n *\r\n * Entries are deduplicated by `slabAddress` — calling this multiple times\r\n * with the same address is safe.\r\n *\r\n * @param network - Target network\r\n * @param entries - One or more static market entries to register\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * registerStaticMarkets(\"mainnet\", [\r\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\r\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\r\n * ]);\r\n * ```\r\n */\r\nexport function registerStaticMarkets(\r\n network: Network,\r\n entries: StaticMarketEntry[],\r\n): void {\r\n const existing = USER_MARKETS[network];\r\n const seen = new Set(existing.map(e => e.slabAddress));\r\n\r\n for (const entry of entries) {\r\n if (!entry.slabAddress) continue;\r\n if (seen.has(entry.slabAddress)) continue;\r\n // Validate that slabAddress is a valid base58 public key\r\n try {\r\n new PublicKey(entry.slabAddress);\r\n } catch {\r\n console.warn(\r\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\r\n );\r\n continue;\r\n }\r\n seen.add(entry.slabAddress);\r\n existing.push(entry);\r\n }\r\n}\r\n\r\n/**\r\n * Clear all user-registered static market entries for a network.\r\n *\r\n * Useful in tests or when resetting state.\r\n *\r\n * @param network - Target network to clear (omit to clear all networks)\r\n */\r\nexport function clearStaticMarkets(network?: Network): void {\r\n if (network) {\r\n USER_MARKETS[network] = [];\r\n } else {\r\n USER_MARKETS.mainnet = [];\r\n USER_MARKETS.devnet = [];\r\n }\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n PUMPSWAP_PROGRAM_ID,\r\n RAYDIUM_CLMM_PROGRAM_ID,\r\n METEORA_DLMM_PROGRAM_ID,\r\n} from \"./pda.js\";\r\n\r\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\r\n\r\nexport interface DexPoolInfo {\r\n dexType: DexType;\r\n poolAddress: PublicKey;\r\n baseMint: PublicKey;\r\n quoteMint: PublicKey;\r\n baseVault?: PublicKey; // PumpSwap only\r\n quoteVault?: PublicKey; // PumpSwap only\r\n}\r\n\r\n/**\r\n * Detect DEX type from the program that owns the pool account.\r\n *\r\n * @param ownerProgramId - The program ID that owns the pool account\r\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\r\n *\r\n * Supported DEX programs:\r\n * - PumpSwap (constant-product AMM)\r\n * - Raydium CLMM (concentrated liquidity)\r\n * - Meteora DLMM (discretized liquidity)\r\n */\r\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\r\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\r\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\r\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\r\n *\r\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\r\n * @param poolAddress - The on-chain address of the pool account\r\n * @param data - Raw account data bytes\r\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\r\n * @throws Error if data is too short for the given DEX type\r\n */\r\nexport function parseDexPool(\r\n dexType: DexType,\r\n poolAddress: PublicKey,\r\n data: Uint8Array,\r\n): DexPoolInfo {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n return parsePumpSwapPool(poolAddress, data);\r\n case \"raydium-clmm\":\r\n return parseRaydiumClmmPool(poolAddress, data);\r\n case \"meteora-dlmm\":\r\n return parseMeteoraPool(poolAddress, data);\r\n }\r\n}\r\n\r\n/**\r\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\r\n *\r\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\r\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\r\n * markets, prefer Pyth or Chainlink oracles.\r\n *\r\n * @param dexType - The type of DEX\r\n * @param data - Raw pool account data\r\n * @param vaultData - For PumpSwap only: base and quote vault account data\r\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\r\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\r\n * ignored for raydium-clmm (decimals are embedded in the pool account).\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\r\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\r\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\r\n * and for PumpSwap pools quoted in a non-WSOL mint.\r\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\r\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\r\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\r\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\r\n * price mislabeled as USD.\r\n * @throws Error if data is too short, required params are missing, or computation fails\r\n */\r\nexport function computeDexSpotPriceE6(\r\n dexType: DexType,\r\n data: Uint8Array,\r\n vaultData?: { base: Uint8Array; quote: Uint8Array },\r\n decimals?: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\r\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\r\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\r\n // MUST supply decimals (fetched from the base/quote mints), matching the\r\n // meteora-dlmm contract below.\r\n if (!decimals) {\r\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\r\n case \"raydium-clmm\":\r\n return computeRaydiumClmmPriceE6(data);\r\n case \"meteora-dlmm\":\r\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\r\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\r\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\r\n if (!decimals) {\r\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Mint decimals helper\r\n// ============================================================================\r\n\r\n/**\r\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\r\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\r\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\r\n * can read this field directly instead of duplicating the magic number.\r\n */\r\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\r\n\r\n/**\r\n * Read the `decimals` field of any SPL mint account (including native WSOL).\r\n *\r\n * This replaces `getMint(connection, mint).decimals` for callers that need to\r\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\r\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\r\n * because the system account is not a valid token-program mint; this function\r\n * reads raw account data and extracts byte 44 directly, which works for all\r\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param mint - The mint public key to query\r\n * @returns The `decimals` field value (0–255)\r\n * @throws Error if the account does not exist or is too short to hold a mint\r\n *\r\n * @example\r\n * ```ts\r\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\r\n *\r\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\r\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\r\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\r\n * base: baseDecimals,\r\n * quote: quoteDecimals,\r\n * });\r\n * ```\r\n */\r\nexport async function fetchMintDecimals(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) {\r\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\r\n }\r\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\r\n throw new Error(\r\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\r\n );\r\n }\r\n return info.data[SPL_MINT_DECIMALS_OFFSET];\r\n}\r\n\r\n// ============================================================================\r\n// PumpSwap\r\n// ============================================================================\r\n\r\n/**\r\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\r\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\r\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\r\n */\r\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\r\n\r\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\r\n// account layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8] pool_bump u8\r\n// [9:11] index u16\r\n// [11:43] creator Pubkey\r\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\r\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\r\n// [107:139] lp_mint Pubkey\r\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\r\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\r\n// [203:211] lp_supply u64\r\n// [211:243] coin_creator Pubkey\r\n//\r\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\r\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\r\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\r\n// pubkeys. Verified against the live ANSEM pool on mainnet\r\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\r\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\r\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\r\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\r\n// balance at verification time). Note the base vault (holding the pump.fun token)\r\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\r\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\r\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\r\n\r\n/**\r\n * Parse a PumpSwap constant-product AMM pool account.\r\n * @internal\r\n */\r\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"pumpswap\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(43, 75)),\r\n quoteMint: new PublicKey(data.slice(75, 107)),\r\n baseVault: new PublicKey(data.slice(139, 171)),\r\n quoteVault: new PublicKey(data.slice(171, 203)),\r\n };\r\n}\r\n\r\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\r\n\r\n/**\r\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\r\n * converted to USD.\r\n *\r\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\r\n *\r\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\r\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\r\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\r\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\r\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\r\n * at all unless multiplied by the SOL/USD rate.\r\n *\r\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\r\n * whether SOL→USD conversion applies)\r\n * @param vaultData - Base and quote vault (SPL token account) raw data\r\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\r\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\r\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\r\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\r\n * PumpSwap pool).\r\n * @internal\r\n */\r\nfunction computePumpSwapPriceE6(\r\n poolData: Uint8Array,\r\n vaultData: { base: Uint8Array; quote: Uint8Array },\r\n decimals: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n if (poolData.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\r\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\r\n\r\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\r\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\r\n\r\n const baseAmount = readU64LE(baseDv, 64);\r\n const quoteAmount = readU64LE(quoteDv, 64);\r\n\r\n if (baseAmount === 0n) return 0n;\r\n\r\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\r\n // the numerator by both the base-decimal correction AND the 1e6 output scale\r\n // before the single division, so low-priced tokens don't truncate to 0n.\r\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\r\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\r\n const baseScale = 10n ** BigInt(decimals.base);\r\n const quoteScale = 10n ** BigInt(decimals.quote);\r\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\r\n\r\n const quoteMint = new PublicKey(poolData.slice(75, 107));\r\n if (quoteMint.equals(WSOL_MINT)) {\r\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\r\n if (solPriceE6 === undefined) {\r\n throw new Error(\r\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\r\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\r\n );\r\n }\r\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\r\n }\r\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\r\n // already ~USD once decimal-adjusted — no further conversion needed.\r\n return quotePerBaseE6;\r\n}\r\n\r\n// ============================================================================\r\n// Raydium CLMM\r\n// ============================================================================\r\n\r\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\r\n\r\n/**\r\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\r\n * @internal\r\n */\r\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"raydium-clmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(73, 105)),\r\n quoteMint: new PublicKey(data.slice(105, 137)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\r\n *\r\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\r\n *\r\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\r\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\r\n *\r\n * @internal\r\n */\r\nconst MAX_TOKEN_DECIMALS = 24;\r\n\r\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\r\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n}\r\n\r\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n const decimals0 = data[233];\r\n const decimals1 = data[234];\r\n\r\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n\r\n const sqrtPriceX64 = readU128LE(dv, 253);\r\n\r\n if (sqrtPriceX64 === 0n) return 0n;\r\n\r\n // #210: defer truncation to a single shift at the very end. The previous form\r\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\r\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\r\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\r\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\r\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\r\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\r\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\r\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\r\n\r\n const decimalDiff = 6 + decimals0 - decimals1;\r\n const adjustedDiff = decimalDiff - 6;\r\n\r\n if (adjustedDiff >= 0) {\r\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\r\n } else {\r\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Meteora DLMM\r\n// ============================================================================\r\n\r\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8:40] parameters (StaticParameters, 32 bytes)\r\n// [40:72] v_parameters (VariableParameters, 32 bytes)\r\n// [72] bump_seed u8\r\n// [73:75] bin_step_seed [u8;2]\r\n// [75] pair_type u8\r\n// [76:80] active_id i32\r\n// [80:82] bin_step u16\r\n// [82] status u8\r\n// [83] require_base_factor_seed u8\r\n// [84:86] base_factor_seed [u8;2]\r\n// [86] activation_type u8\r\n// [87] creator_pool_on_off_control u8\r\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\r\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\r\n// [152:184] reserve_x Pubkey\r\n// [184:216] reserve_y Pubkey\r\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\r\n\r\n/**\r\n * Parse a Meteora DLMM (discretized liquidity) pool account.\r\n *\r\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\r\n * on-chain `LbPair` struct layout (verified against mainnet pool\r\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\r\n *\r\n * @internal\r\n */\r\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"meteora-dlmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(88, 120)),\r\n quoteMint: new PublicKey(data.slice(120, 152)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Meteora DLMM spot price from active_id and bin_step.\r\n *\r\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\r\n *\r\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\r\n * For negative active_id, computes the inverse.\r\n *\r\n * @internal\r\n */\r\nconst MAX_BIN_STEP = 10_000;\r\nconst MAX_ACTIVE_ID_ABS = 500_000;\r\n\r\nfunction computeMeteoraDlmmPriceE6(\r\n data: Uint8Array,\r\n decimalsBase: number,\r\n decimalsQuote: number,\r\n): bigint {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\r\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\r\n // They happen to encode the same integer for most pools (explaining why the\r\n // old code produced correct prices), but reading the correct field is required\r\n // for correctness once those fields diverge.\r\n const binStep = dv.getUint16(80, true);\r\n const activeId = dv.getInt32(76, true);\r\n\r\n if (binStep === 0) return 0n;\r\n if (binStep > MAX_BIN_STEP) {\r\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\r\n }\r\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\r\n throw new Error(\r\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\r\n );\r\n }\r\n\r\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\r\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\r\n\r\n const isNeg = activeId < 0;\r\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\r\n\r\n let result = SCALE;\r\n let b = base;\r\n\r\n while (exp > 0n) {\r\n if (exp & 1n) {\r\n result = (result * b) / SCALE;\r\n }\r\n exp >>= 1n;\r\n if (exp > 0n) {\r\n b = (b * b) / SCALE;\r\n }\r\n }\r\n\r\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\r\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\r\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\r\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\r\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\r\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\r\n // arbitrary-precision, so the intermediate products cannot overflow.\r\n const diff = decimalsBase - decimalsQuote;\r\n\r\n if (isNeg) {\r\n if (result === 0n) return 0n;\r\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\r\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\r\n if (diff >= 0) {\r\n return (num * 10n ** BigInt(diff)) / result;\r\n }\r\n return num / (result * 10n ** BigInt(-diff));\r\n } else {\r\n // price_e6 = (result / 1e12) * 10^diff\r\n if (diff >= 0) {\r\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\r\n }\r\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Read a little-endian u64 from a DataView. */\r\nfunction readU64LE(dv: DataView, offset: number): bigint {\r\n const lo = BigInt(dv.getUint32(offset, true));\r\n const hi = BigInt(dv.getUint32(offset + 4, true));\r\n return lo | (hi << 32n);\r\n}\r\n\r\n/** Read a little-endian u128 from a DataView. */\r\nfunction readU128LE(dv: DataView, offset: number): bigint {\r\n const lo = readU64LE(dv, offset);\r\n const hi = readU64LE(dv, offset + 8);\r\n return lo | (hi << 64n);\r\n}\r\n","/**\r\n * Oracle account parsing utilities.\r\n *\r\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\r\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\r\n * so that this parser and the on-chain program agree byte-for-byte:\r\n *\r\n * CHAINLINK_HEADER_SIZE = 192\r\n * offset 8: version (u8) CL_OFF_VERSION\r\n * offset 138: decimals (u8) CL_OFF_DECIMALS\r\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\r\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\r\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\r\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\r\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\r\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\r\n *\r\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\r\n *\r\n * These utilities validate oracle data BEFORE parsing to prevent silent\r\n * propagation of stale or malformed Chainlink data as price.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Minimum buffer size to read Chainlink price data.\r\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\r\n * The previous value (224) was smaller than the program's own floor, so the SDK\r\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\r\n * answer at offset 216.\r\n */\r\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\r\n\r\n/** Maximum reasonable decimals for a price feed */\r\nconst MAX_DECIMALS = 18;\r\n\r\n/** Offset of decimals field in Chainlink aggregator account */\r\nconst CHAINLINK_DECIMALS_OFFSET = 138;\r\n\r\n/**\r\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\r\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\r\n */\r\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\r\n\r\n/**\r\n * Offset of the latest answer.\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\r\n */\r\nconst CHAINLINK_ANSWER_OFFSET = 216;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface OraclePrice {\r\n price: bigint;\r\n decimals: number;\r\n /** Unix timestamp (seconds) of the last oracle update, if available. */\r\n updatedAt?: number;\r\n}\r\n\r\nexport interface ParseChainlinkOptions {\r\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\r\n maxStalenessSeconds?: number;\r\n /**\r\n * How far ahead of the local clock a publish timestamp may be before it is\r\n * treated as invalid rather than as clock skew. Defaults to 60s.\r\n * Only consulted when `maxStalenessSeconds` is set.\r\n */\r\n futureToleranceSeconds?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Browser-compatible read helpers using DataView\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n return data[off];\r\n}\r\n\r\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\r\n}\r\n\r\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\r\n}\r\n\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\r\n}\r\n\r\n/**\r\n * Default tolerance for a publish timestamp that appears to be in the future.\r\n *\r\n * The program compares the feed timestamp against the on-chain clock\r\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\r\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\r\n * between a user's machine and the cluster would otherwise reject a perfectly\r\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\r\n */\r\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse price data from a Chainlink aggregator account buffer.\r\n *\r\n * Validates:\r\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\r\n * program's own CHAINLINK_FEED_MIN_LEN)\r\n * - Decimals are in a reasonable range (0-18)\r\n * - Price is positive (non-zero)\r\n *\r\n * @param data - Raw account data from Chainlink aggregator\r\n * @param options - Optional staleness check (maxStalenessSeconds)\r\n * @returns Parsed oracle price with decimals and last-update timestamp\r\n * @throws if the buffer is invalid, contains unreasonable data, or (when\r\n * maxStalenessSeconds is set) the last update is older than that bound\r\n */\r\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\r\n if (data.length < CHAINLINK_MIN_SIZE) {\r\n throw new Error(\r\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\r\n );\r\n }\r\n\r\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\r\n if (decimals > MAX_DECIMALS) {\r\n throw new Error(\r\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\r\n );\r\n }\r\n\r\n // The program reads the answer as a full i128 LE (read_i128_le at\r\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\r\n // high (signed) halves rather than reading only the low 8 bytes, which would\r\n // silently truncate a large answer into a different price than the chain sees.\r\n //\r\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\r\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\r\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\r\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\r\n // on-chain. `price` is a bigint and holds the full i128 range.\r\n const answer =\r\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\r\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\r\n if (answer <= 0n) {\r\n throw new Error(\r\n `Oracle price is non-positive: ${answer}`\r\n );\r\n }\r\n const price = answer;\r\n\r\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\r\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\r\n\r\n if (options?.maxStalenessSeconds !== undefined) {\r\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\r\n // skipping the check: a zero timestamp means the feed has never published,\r\n // which is maximally stale, not exempt from staleness.\r\n if (updatedAt <= 0) {\r\n throw new Error(\r\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\r\n );\r\n }\r\n const now = Math.floor(Date.now() / 1000);\r\n const age = now - updatedAt;\r\n // The program rejects a negative age, but it measures against the on-chain\r\n // clock. We only have the local one, so a couple of seconds of ordinary skew\r\n // must not condemn a healthy feed — only an implausible jump ahead should.\r\n const futureTolerance =\r\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\r\n if (age < -futureTolerance) {\r\n throw new Error(\r\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\r\n `check the feed or the local clock`\r\n );\r\n }\r\n if (age > options.maxStalenessSeconds) {\r\n throw new Error(\r\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\r\n );\r\n }\r\n }\r\n\r\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\r\n}\r\n\r\n/**\r\n * Validate that a buffer looks like a valid Chainlink aggregator account.\r\n * Returns true if the buffer passes all validation checks, false otherwise.\r\n * Use this for non-throwing validation.\r\n */\r\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\r\n try {\r\n parseChainlinkPrice(data);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-export constants for consumers\r\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Token2022 (Token Extensions) program ID.\r\n */\r\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\r\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\r\n);\r\n\r\n/**\r\n * Detect which token program owns a given mint account.\r\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\r\n *\r\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\r\n * attacker-controlled account owned by an arbitrary program (or a non-mint\r\n * account) would be accepted and its owner propagated as the \"token program\",\r\n * letting a forged program be passed into a later token CPI. Now we branch on\r\n * the owner and accept ONLY the two real token programs, throwing otherwise.\r\n *\r\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\r\n * Token-2022.\r\n */\r\nexport async function detectTokenProgram(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\r\n\r\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\r\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\r\n\r\n throw new Error(\r\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\r\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\r\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\r\n );\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is Token2022.\r\n */\r\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is the standard SPL Token program.\r\n */\r\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\r\n}\r\n","/**\r\n * @module stake\r\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\r\n *\r\n * Program: percolator-stake (dcccrypto/percolator-stake)\r\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\r\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\r\n * `src/config/program-ids.ts`)\r\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\r\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\r\n * this writing; treat as a placeholder until DevOps confirms)\r\n *\r\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\r\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\r\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\r\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\r\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\r\n * do not use it for new integrations).\r\n */\r\n\r\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\r\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\r\nexport { TOKEN_2022_PROGRAM_ID };\r\nimport { safeEnv } from '../config/program-ids.js';\r\nimport { concatBytes } from '../abi/encode.js';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Known stake program addresses per network.\r\n *\r\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\r\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\r\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\r\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\r\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\r\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\r\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\r\n * module targets — see the module doc above.\r\n *\r\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\r\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\r\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\r\n * confirms.\r\n *\r\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\r\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\r\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\r\n * silently default to mainnet: an unconfigured browser caller would have resolved to\r\n * a real, executing mainnet program rather than failing safe.\r\n */\r\nexport const STAKE_PROGRAM_IDS = {\r\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\r\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\r\n} as const;\r\nObject.freeze(STAKE_PROGRAM_IDS);\r\n\r\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\r\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\r\n\r\n/**\r\n * Resolve the stake program ID for the given network.\r\n *\r\n * Priority:\r\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\r\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\r\n *\r\n * Throws a clear error on mainnet when no address is available so callers\r\n * surface the gap instead of silently hitting the devnet program.\r\n */\r\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\r\n // Only consult the env override when no explicit network arg is provided.\r\n // An explicit network argument always wins so tests and multi-network callers\r\n // are not silently redirected to a DevOps-set override address.\r\n if (!network) {\r\n const override = safeEnv('STAKE_PROGRAM_ID');\r\n if (override) {\r\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\r\n // ambient env poisoning while allowing fresh pre-deploy addresses).\r\n if (\r\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\r\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\r\n ) {\r\n throw new Error(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\r\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\r\n );\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n const detectedNetwork =\r\n network ??\r\n (() => {\r\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\r\n safeEnv('NETWORK')?.toLowerCase() ?? '';\r\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\r\n if (n === 'devnet') return 'devnet' as const;\r\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\r\n // i.e. in every browser bundle, where process.env is empty because env vars\r\n // are not inlined into third-party SDK code. An unconfigured frontend caller\r\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\r\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\r\n //\r\n // We deliberately do NOT substitute a devnet default here. Unlike\r\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\r\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\r\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\r\n // defaulting to devnet would merely defer it to the day mainnet launches and\r\n // a forgotten env var silently points a mainnet UI at the devnet vault.\r\n // Refuse to guess: the network must be explicit.\r\n // The message must not assert a cause it has not established. This fires in\r\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\r\n // with process.env fully available — so claiming \"browser bundle\" would send\r\n // a server-side caller chasing the wrong thing.\r\n throw new Error(\r\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\r\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\r\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\r\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\r\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\r\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\r\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\r\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\r\n 'for the wrong network.',\r\n );\r\n })();\r\n\r\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\r\n if (!id) {\r\n throw new Error(\r\n `Stake program not deployed on ${detectedNetwork}. ` +\r\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\r\n );\r\n }\r\n return new PublicKey(id);\r\n}\r\n\r\n/**\r\n * Default export — resolves for the current runtime network.\r\n * Use getStakeProgramId() with an explicit network argument where possible.\r\n *\r\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\r\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\r\n * resolving to the devnet address.\r\n */\r\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Tags — ADOPTED percolator-stake lineage\r\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\r\n//\r\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\r\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\r\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\r\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\r\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\r\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\r\n// side-by-side tag-delta table this was verified against. The comparison is now\r\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\r\n// NEW address that already runs the ADOPTED lineage below — there is no more\r\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport const STAKE_IX = {\r\n InitPool: 0,\r\n Deposit: 1,\r\n Withdraw: 2,\r\n FlushToInsurance: 3,\r\n UpdateConfig: 4,\r\n /**\r\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\r\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\r\n * zero pubkey CANCELS an outstanding proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\r\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\r\n * wrapper marketauth rotation (a completely different key, done via the\r\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\r\n *\r\n * Wire: tag(1) + new_admin(32) = 33 bytes.\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\n ProposeAdmin: 5,\r\n /**\r\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to take ownership; requires an outstanding proposal\r\n * and the signer to equal `pool.pending_admin`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\r\n * removed `AdminSetOracleAuthority` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\n AcceptAdmin: 6,\r\n /**\r\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\r\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\r\n * LP holders an exit window. A decrease/unchanged value is rejected here\r\n * (use UpdateConfig, which applies decreases immediately).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\r\n * removed `AdminSetRiskThreshold` (rejects on-chain).\r\n *\r\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n ProposeCooldownIncrease: 7,\r\n /**\r\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\r\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n CommitCooldownIncrease: 8,\r\n /**\r\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\r\n * proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\r\n * removed `AdminResolveMarket` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n CancelCooldownIncrease: 9,\r\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\r\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\r\n TransferAdmin: 5,\r\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\r\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\r\n AdminSetOracleAuthority: 6,\r\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\r\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\r\n AdminSetRiskThreshold: 7,\r\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\r\n * CommitCooldownIncrease. */\r\n AdminSetMaintenanceFee: 8,\r\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\r\n * CancelCooldownIncrease. */\r\n AdminResolveMarket: 9,\r\n /**\r\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\r\n * percolator-vault program: transfer withdrawn insurance back into the pool\r\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\r\n * books admin-ATA -> pool-vault).\r\n */\r\n ReturnInsurance: 10,\r\n /** @deprecated Legacy alias for ReturnInsurance. */\r\n AdminWithdrawInsurance: 10,\r\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\r\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\r\n AdminSetInsurancePolicy: 11,\r\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\r\n AccrueFees: 12,\r\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\r\n InitTradingPool: 13,\r\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\r\n AdminSetHwmConfig: 14,\r\n /**\r\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\r\n * tranches. Sets `junior_fee_mult_bps`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * below). Sending this payload against the DEPLOYED vault program would\r\n * execute BindInsuranceAuthority instead; only send it against the\r\n * ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n AdminSetTrancheConfig: 15,\r\n /**\r\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\r\n * Same account shape as Deposit (tag 1).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\n DepositJunior: 16,\r\n /**\r\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\r\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\r\n * binds both in one call, unlike the deployed vault program which only\r\n * bound insurance_authority. The human admin signs the outer tx as the\r\n * current authority/operator; vault_auth signs via invoke_signed.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n BindInsuranceAuthority: 19,\r\n /**\r\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\r\n * escape that moves the market's `insurance_authority` OFF our vault_auth\r\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\r\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\r\n * authority. NEW in the adopted lineage — no equivalent in the deployed\r\n * percolator-vault program (which has no un-bind escape at all).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceAuthority: 20,\r\n /**\r\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\r\n * has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\r\n */\r\n BurnAssetAdmin: 21,\r\n /**\r\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceOperator: 22,\r\n /**\r\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\r\n * insurance_operator, not asset_admin. `amount` capped to\r\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\r\n * NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\r\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\r\n * tokenProgram, percolatorProgram]\r\n */\r\n RecoverFlushedInsurance: 23,\r\n /**\r\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\r\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\r\n * without this proxy every stake-initialized market would be permanently\r\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\r\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\r\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\r\n * percolator-stake (see src/instruction.rs / src/processor.rs\r\n * `process_admin_resolve_market`, tag 24).\r\n *\r\n * NOTE on the name: the on-chain enum variant is literally\r\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\r\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\r\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\r\n * avoid re-using that already-claimed object key/export name — the tag-9\r\n * alias and this tag-24 instruction are unrelated aside from sharing an\r\n * on-chain name across two different lineages.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n */\r\n AdminResolveMarketCpi: 24,\r\n /**\r\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n SetMarketResolved: 18,\r\n /**\r\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\r\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\r\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\r\n * signs the CPI via invoke_signed.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\r\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\r\n * Custom(52)/Custom(51) through the CPI.\r\n */\r\n AdminUpdateFeeSplit: 25,\r\n /**\r\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\r\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\r\n * signer model as tag 25.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\r\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\r\n * `read_u128`.\r\n */\r\n AdminUpdateMaintenanceFeePerSlot: 26,\r\n /**\r\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\r\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\r\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\r\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\r\n *\r\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\r\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\r\n *\r\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n AdminUpdateBackingFeePolicy: 27,\r\n /**\r\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\r\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\r\n * model as tag 27.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\r\n * `read_u64`, wrapper tag 88 with `read_u128`.\r\n */\r\n AdminUpdateTradeFeePolicy: 28,\r\n} as const;\r\nObject.freeze(STAKE_IX);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * User-facing hint text for `StakeError` custom program error codes\r\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\r\n *\r\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\r\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\r\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\r\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\r\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\r\n * error\" for 25-27 despite them being named enum variants); the hints below\r\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\r\n * (missing) on-chain string.\r\n */\r\nexport const STAKE_ERRORS: Record = {\r\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\r\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\r\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\r\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\r\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\r\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\r\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\r\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\r\n 8: \"Market is resolved — no new deposits allowed after resolution\",\r\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\r\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\r\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\r\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\r\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\r\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\r\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\r\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\r\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\r\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\r\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\r\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\r\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\r\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\r\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\r\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\r\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\r\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\r\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\r\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\r\n};\r\nObject.freeze(STAKE_ERRORS);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PDA Derivation\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\n/** Derive the stake pool PDA for a given slab (market). */\r\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\r\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\r\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getBigUint64(off, /* littleEndian= */ true);\r\n}\r\n\r\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getUint16(off, /* littleEndian= */ true);\r\n}\r\n\r\nfunction requireDiscriminator(\r\n accountName: string,\r\n data: Uint8Array,\r\n offset: number,\r\n expected: Uint8Array,\r\n): void {\r\n for (let i = 0; i < expected.length; i += 1) {\r\n if (data[offset + i] !== expected[i]) {\r\n throw new Error(`${accountName} invalid discriminator`);\r\n }\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Encoders\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction u64Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\r\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\r\n const arr = new Uint8Array(8);\r\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\r\n}\r\n\r\nfunction u128Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\r\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\r\n const arr = new Uint8Array(16);\r\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\r\n view.setBigUint64(8, big >> 64n, true);\r\n return arr;\r\n}\r\n\r\nfunction u16Le(v: number): Uint8Array {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\r\n return arr;\r\n}\r\n\r\n/** Tag 0: InitPool — create stake pool for a slab. */\r\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\r\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\r\n}\r\n\r\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\r\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\r\n}\r\n\r\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\r\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\r\n}\r\n\r\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\r\nexport function encodeStakeUpdateConfig(\r\n newCooldownSlots?: bigint | number,\r\n newDepositCap?: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.UpdateConfig]),\r\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\r\n u64Le(newCooldownSlots ?? 0n),\r\n new Uint8Array([newDepositCap != null ? 1 : 0]),\r\n u64Le(newDepositCap ?? 0n),\r\n );\r\n}\r\n\r\nfunction removedStakeInstruction(name: string, tag: number): never {\r\n throw new Error(\r\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\r\n );\r\n}\r\n\r\n/**\r\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\r\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\r\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\r\n * proposal.\r\n *\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeAdmin]),\r\n newAdmin.toBytes(),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to become admin. Requires an outstanding proposal.\r\n *\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAcceptAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\r\n}\r\n\r\n/**\r\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\r\n * until CommitCooldownIncrease is called after the on-chain timelock has\r\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\r\n u64Le(newCooldownSlots),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\r\n * increase proposal.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\r\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\r\n * percolator-stake lineage this module targets, tag 5 is the two-step\r\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\r\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\r\n */\r\nexport function encodeStakeTransferAdmin(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\r\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\r\n void newAuthority;\r\n throw new Error(\r\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\r\n 'lineage — use encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\r\n void newThreshold;\r\n throw new Error(\r\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\r\n void newFee;\r\n throw new Error(\r\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\r\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ReturnInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\r\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\r\n return encodeStakeReturnInsurance(amount);\r\n}\r\n\r\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\r\nexport function encodeStakeAccrueFees(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AccrueFees]);\r\n}\r\n\r\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\r\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitTradingPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\r\nexport function encodeStakeAdminSetHwmConfig(\r\n enabled: boolean,\r\n hwmFloorBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\r\n new Uint8Array([enabled ? 1 : 0]),\r\n u16Le(hwmFloorBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\r\n * percolator-stake lineage; sending it against the currently-deployed vault\r\n * program would silently execute BindInsuranceAuthority instead.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\r\n u16Le(juniorFeeMultBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\r\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\r\n}\r\n\r\n/**\r\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeSetMarketResolved(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\r\n}\r\n\r\n/**\r\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\r\n * then kind=2) — a broader bind than the deployed vault program's\r\n * single-CPI version (insurance_authority only). Must be called once after\r\n * InitPool, before FlushToInsurance will work.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\r\n *\r\n * @returns 1-byte Uint8Array `[0x13]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBindInsuranceAuthority();\r\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\r\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\r\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\r\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BindInsuranceAuthorityAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * Account order matches src/processor.rs process_bind_insurance_authority\r\n * (adopted lineage — same account shape as the deployed vault program's tag\r\n * 15, only the tag byte moved):\r\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\r\n * [1] pool_pda writable (stake pool PDA)\r\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n *\r\n * @example\r\n * ```ts\r\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\r\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\r\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function bindInsuranceAuthorityAccounts(\r\n a: BindInsuranceAuthorityAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\r\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\r\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\r\n * the deployed percolator-vault program (which has no un-bind escape).\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceAuthority();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceOperator();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\r\n}\r\n\r\n/**\r\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\r\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA.\r\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\r\n * @param newTarget The successor authority/operator — co-signs the outer tx.\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RotateInsuranceAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n newTarget: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\r\n * (tag 22) — identical account order in both (src/processor.rs\r\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only\r\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\r\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\r\n * [4] slab writable (wrapper market; needed for CPI)\r\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function rotateInsuranceAccounts(\r\n a: RotateInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after\r\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBurnAssetAdmin();\r\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\r\n}\r\n\r\n/**\r\n * Account inputs for BurnAssetAdmin (tag 21).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\r\n * @param poolPda Stake pool PDA (writable — records the burn).\r\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BurnAssetAdminAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\r\n * process_burn_asset_admin:\r\n * [0] admin signer, writable (current asset_admin == pool.admin)\r\n * [1] pool_pda writable (records asset_admin_burned)\r\n * [2] vault_auth read-only (placeholder new_authority slot)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function burnAssetAdminAccounts(\r\n a: BurnAssetAdminAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\r\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\r\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\r\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\r\n * adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n *\r\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\r\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\r\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for RecoverFlushedInsurance (tag 23).\r\n *\r\n * @param caller Permissionless caller — no signer check required.\r\n * @param poolPda Stake pool PDA (writable).\r\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\r\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\r\n * @param wrapperMarket Wrapper market/slab account (writable).\r\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\r\n * @param wrapperVaultAuth Wrapper vault authority PDA.\r\n * @param tokenProgram Token program.\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RecoverFlushedInsuranceAccounts {\r\n caller: PublicKey;\r\n poolPda: PublicKey;\r\n poolVault: PublicKey;\r\n vaultAuth: PublicKey;\r\n wrapperMarket: PublicKey;\r\n wrapperVault: PublicKey;\r\n wrapperVaultAuth: PublicKey;\r\n tokenProgram: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\r\n * process_recover_flushed_insurance:\r\n * [0] caller (no signer check — permissionless)\r\n * [1] pool_pda writable\r\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\r\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\r\n * [4] market (wrapper) writable\r\n * [5] wrapper_vault writable (source — wrapper insurance vault)\r\n * [6] wrapper_vault_auth read-only\r\n * [7] token_program read-only\r\n * [8] percolator_program read-only\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function recoverFlushedInsuranceAccounts(\r\n a: RecoverFlushedInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.caller, isSigner: false, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\r\n * can call the wrapper's ResolveMarket directly; this instruction has the\r\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\r\n * the (human) admin can trigger resolution. Does not mutate any local\r\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\r\n * separately afterward for local bookkeeping.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n *\r\n * @returns 1-byte Uint8Array `[24]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminResolveMarketCpi();\r\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\r\n}\r\n\r\n/**\r\n * Account inputs for AdminResolveMarketCpi (tag 24).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\r\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface AdminResolveMarketCpiAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\r\n * process_admin_resolve_market:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\r\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function adminResolveMarketCpiAccounts(\r\n a: AdminResolveMarketCpiAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\r\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\r\n//\r\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\r\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\r\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\r\n// transaction, so the affected wrapper setters become reachable ONLY through a\r\n// stake-program CPI proxy. Before these four, exactly one proxy existed\r\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\r\n// wrapper handlers reachable — which is the mechanical reason the fee split\r\n// was unachievable on a staked market.\r\n//\r\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\r\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\r\n// VAULT_AUTH PDA signs.\r\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n//\r\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\r\n * whose length is not exactly 6 bytes after the tag.\r\n *\r\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\r\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\r\n *\r\n * Share validation happens in the WRAPPER, not here: a split that does not sum\r\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\r\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\r\n *\r\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\r\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\r\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\r\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateFeeSplit(\r\n creatorShareBps: number,\r\n lpShareBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\r\n u16Le(creatorShareBps),\r\n u16Le(lpShareBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\r\n * wrapper tag 88.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\r\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\r\n * u64 fails at the stake program before the CPI is even attempted.\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\r\n * 0 (maintenance fee disabled). The wrapper\r\n * range-checks against MAX_PROTOCOL_FEE_ABS.\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\r\n maintenanceFeePerSlot: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\r\n u128Le(maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\r\n * tag 51, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\r\n * = 7 bytes.\r\n *\r\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\r\n * @param feeBps Backing fee in bps (u16).\r\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\r\n * const keys = adminUpdateBackingFeePolicyAccounts({\r\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\r\n * });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateBackingFeePolicy(\r\n domain: number,\r\n feeBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\r\n u16Le(domain),\r\n u16Le(feeBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\r\n * 55, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\r\n * checks `rest.len() == 8`.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\r\n * values above the market's `max_trading_fee_bps` or\r\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateTradeFeePolicy(\r\n tradeFeeBaseBps: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\r\n u64Le(tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\r\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupAProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP A proxies — src/processor.rs\r\n * `process_admin_update_fee_split` (tag 25) and\r\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\r\n * identical layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\r\n * [2] slab writable (wrapper market; CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupAProxyAccounts(\r\n a: StakeGroupAProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\r\n\r\n/**\r\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\r\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\r\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\r\n * insurance_authority; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupBProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP B proxies — src/processor.rs\r\n * `process_admin_update_backing_fee_policy` (tag 27) and\r\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\r\n * layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\r\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; CPI target)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\r\n * difference from GROUP A, and getting it wrong makes the CPI fail its\r\n * authority check rather than fail loudly at the account level.\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupBProxyAccounts(\r\n a: StakeGroupBProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\r\nexport function encodeStakeAdminSetInsurancePolicy(\r\n authority: PublicKey,\r\n minWithdrawBase: bigint | number,\r\n maxWithdrawBps: number,\r\n cooldownSlots: bigint | number,\r\n): Uint8Array {\r\n void authority;\r\n void minWithdrawBase;\r\n void maxWithdrawBps;\r\n void cooldownSlots;\r\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// On-Chain State Layout — StakePool decoded fields\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\r\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\r\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\r\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\r\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\r\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\r\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\r\n * and PERC-303 (tranches).\r\n *\r\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\r\n * `_reserved` layout (verified against `state.rs` on\r\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\r\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\r\n * whatever bytes the program actually writes):\r\n *\r\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\r\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\r\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\r\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\r\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\r\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\r\n * (added later, #242) write into [10..18]/[18..26] regardless.\r\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\r\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\r\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\r\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\r\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\r\n * - This decoder reads both field sets as the raw bytes currently define\r\n * them (matching on-chain reality); it does NOT attempt to reconcile or\r\n * invalidate one set when the other is in use. Callers combining HWM and\r\n * the cooldown timelock on one pool should treat both `hwm*` and\r\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\r\n * against a direct on-chain read before trusting either.\r\n */\r\nexport interface StakePoolState {\r\n isInitialized: boolean;\r\n bump: number;\r\n vaultAuthorityBump: number;\r\n adminTransferred: boolean;\r\n marketResolved: boolean;\r\n\r\n slab: PublicKey;\r\n admin: PublicKey;\r\n collateralMint: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n\r\n totalDeposited: bigint;\r\n totalLpSupply: bigint;\r\n cooldownSlots: bigint;\r\n depositCap: bigint;\r\n totalFlushed: bigint;\r\n totalReturned: bigint;\r\n totalWithdrawn: bigint;\r\n\r\n percolatorProgram: PublicKey;\r\n\r\n /**\r\n * Pending admin for the two-step rotation (stake v2, offset 288).\r\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\r\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\r\n */\r\n pendingAdmin: PublicKey | null;\r\n\r\n // PERC-272: Fee yield fields\r\n totalFeesEarned: bigint;\r\n lastFeeAccrualSlot: bigint;\r\n lastVaultSnapshot: bigint;\r\n poolMode: number;\r\n\r\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\r\n // [0..8] discriminator\r\n // [8] version\r\n // [9] market_resolved\r\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\r\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\r\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\r\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\r\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\r\n // [24..32] PERC-313 hwm_last_epoch (u64)\r\n // [32] PERC-303 tranche_enabled\r\n // [33..41] PERC-303 junior_balance (u64)\r\n // [41..49] PERC-303 junior_total_lp (u64)\r\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\r\n // [51..59] N-realized_junior_loss (u64) — issue #161\r\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\r\n // [60..64] free\r\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\r\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\r\n\r\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\r\n hwmEnabled: boolean;\r\n epochHighWaterTvl: bigint;\r\n hwmFloorBps: number;\r\n hwmLastEpoch: bigint;\r\n\r\n // PERC-303: Tranche fields (from _reserved[32..51])\r\n trancheEnabled: boolean;\r\n juniorBalance: bigint;\r\n juniorTotalLp: bigint;\r\n juniorFeeMultBps: number;\r\n\r\n /**\r\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\r\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n pendingCooldownSlots: bigint;\r\n /**\r\n * #242 timelock: the slot at which the pending cooldown increase was\r\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n cooldownProposedAtSlot: bigint;\r\n /**\r\n * Cumulative insurance loss a fully-exited junior tranche permanently\r\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\r\n * total_pool_value() so recovered tokens don't windfall senior.\r\n */\r\n realizedJuniorLoss: bigint;\r\n /**\r\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\r\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\r\n * stay disabled — the wrapper roles cannot be moved back to an\r\n * admin-controlled key.\r\n */\r\n assetAdminBurned: boolean;\r\n /**\r\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\r\n * collateral actually recovered from the WRAPPER via the tag-23\r\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\r\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\r\n * insurance back out of the wrapper. Real struct field at offset 384..392\r\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\r\n *\r\n * Deliberately separate from `totalReturned`, which is also bumped by two\r\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\r\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\r\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\r\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\r\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\r\n */\r\n totalRecoveredFromWrapper: bigint | null;\r\n}\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v1 layout.\r\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\r\n * The _reserved block in v1 starts at offset 288; version byte = 1.\r\n *\r\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\r\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\r\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\r\n * migration is needed\"). v1/352-byte pools can only ever be observed as\r\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\r\n * redeploy (which abandons every existing market/pool wholesale — VERSION\r\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\r\n * detection exists purely to decode those pre-redeploy artifacts if you ever\r\n * need to; the ADOPTED program itself never creates a v1 pool.\r\n */\r\nexport const STAKE_POOL_SIZE_V1 = 352;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v2 layout.\r\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\r\n * The _reserved block in v2 starts at offset 320; version byte = 2.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\r\n * padding (every u64 field lands on an 8-aligned cumulative offset).\r\n *\r\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\r\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\r\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\r\n * still needs to construct a v2-shaped buffer explicitly.\r\n */\r\nexport const STAKE_POOL_SIZE_V2 = 384;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\r\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\r\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\r\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\r\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\r\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\r\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\r\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\r\n * instead of the broader (and gameable) `total_returned` counter — see\r\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\r\n * padding (the appended u64 lands on the already-8-aligned offset 384).\r\n */\r\nexport const STAKE_POOL_SIZE_V3 = 392;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\r\n * ADOPTED percolator-stake lineage creates. Currently equal to\r\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\r\n * constants in new code so a future version bump doesn't silently change the\r\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\r\n */\r\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\r\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\r\nexport const STAKE_POOL_CURRENT_VERSION = 3;\r\n\r\n/**\r\n * Decode a StakePool account from raw data buffer.\r\n *\r\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\r\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\r\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\r\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\r\n * v2 and v3). The layout version is detected from the data length before\r\n * reading the discriminator.\r\n *\r\n * v1/v2 support exists only to decode legacy pools created before the\r\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\r\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\r\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\r\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\r\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\r\n * on-chain `_reserved` layout collision).\r\n *\r\n * Uses DataView for all u64/u16 reads — browser-safe.\r\n */\r\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\r\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\r\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\r\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\r\n if (!isV3 && !isV2 && !isV1) {\r\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\r\n }\r\n\r\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\r\n // AFTER _reserved, not inside it, so the block start doesn't move again).\r\n const reservedOffset = isV1 ? 288 : 320;\r\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\r\n const version = data[reservedOffset + 8];\r\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\r\n if (version !== expectedVersion) {\r\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\r\n }\r\n\r\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\r\n let off = 0;\r\n const isInitialized = bytes[off] === 1; off += 1;\r\n const bump = bytes[off]; off += 1;\r\n const vaultAuthorityBump = bytes[off]; off += 1;\r\n const adminTransferred = bytes[off] === 1; off += 1;\r\n off += 4; // _padding\r\n\r\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n const totalDeposited = readU64LE(bytes, off); off += 8;\r\n const totalLpSupply = readU64LE(bytes, off); off += 8;\r\n const cooldownSlots = readU64LE(bytes, off); off += 8;\r\n const depositCap = readU64LE(bytes, off); off += 8;\r\n const totalFlushed = readU64LE(bytes, off); off += 8;\r\n const totalReturned = readU64LE(bytes, off); off += 8;\r\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\r\n\r\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n // PERC-272 fields (offset 256..288 in both v1 and v2)\r\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\r\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\r\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\r\n const poolMode = bytes[off]; off += 1;\r\n off += 7; // _mode_padding (off is now 288)\r\n\r\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\r\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\r\n let pendingAdmin: PublicKey | null = null;\r\n if (isV2 || isV3) {\r\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\r\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\r\n ? null\r\n : new PublicKey(pendingAdminBytes);\r\n }\r\n\r\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\r\n const reservedStart = off;\r\n // _reserved[8] = version (skipped)\r\n // _reserved[9] = market_resolved\r\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\r\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\r\n const marketResolved = bytes[reservedStart + 9] === 1;\r\n const hwmEnabled = bytes[reservedStart + 10] === 1;\r\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\r\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\r\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\r\n\r\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\r\n const trancheEnabled = bytes[reservedStart + 32] === 1;\r\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\r\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\r\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\r\n\r\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\r\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\r\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\r\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\r\n\r\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\r\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\r\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\r\n\r\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\r\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\r\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\r\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\r\n const totalRecoveredFromWrapper = isV3\r\n ? readU64LE(bytes, reservedStart + 64)\r\n : null;\r\n\r\n return {\r\n isInitialized,\r\n bump,\r\n vaultAuthorityBump,\r\n adminTransferred,\r\n marketResolved,\r\n slab,\r\n admin,\r\n collateralMint,\r\n lpMint,\r\n vault,\r\n totalDeposited,\r\n totalLpSupply,\r\n cooldownSlots,\r\n depositCap,\r\n totalFlushed,\r\n totalReturned,\r\n totalWithdrawn,\r\n percolatorProgram,\r\n pendingAdmin,\r\n totalFeesEarned,\r\n lastFeeAccrualSlot,\r\n lastVaultSnapshot,\r\n poolMode,\r\n hwmEnabled,\r\n epochHighWaterTvl,\r\n hwmFloorBps,\r\n hwmLastEpoch,\r\n trancheEnabled,\r\n juniorBalance,\r\n juniorTotalLp,\r\n juniorFeeMultBps,\r\n pendingCooldownSlots,\r\n cooldownProposedAtSlot,\r\n realizedJuniorLoss,\r\n assetAdminBurned,\r\n totalRecoveredFromWrapper,\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// StakeDeposit PDA decoder\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Size of StakeDeposit on-chain (bytes). */\r\nexport const STAKE_DEPOSIT_SIZE = 152;\r\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\r\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\r\n\r\n/** Decoded StakeDeposit PDA state. */\r\nexport interface StakeDepositState {\r\n isInitialized: boolean;\r\n bump: number;\r\n pool: PublicKey;\r\n user: PublicKey;\r\n lastDepositSlot: bigint;\r\n lpAmount: bigint;\r\n}\r\n\r\n/**\r\n * Decode a StakeDeposit PDA account from raw data.\r\n *\r\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\r\n * [0] is_initialized u8\r\n * [1] bump u8\r\n * [2..8] _padding\r\n * [8..40] pool [u8; 32]\r\n * [40..72] user [u8; 32]\r\n * [72..80] last_deposit_slot u64\r\n * [80..88] lp_amount u64\r\n * [88..152] _reserved\r\n */\r\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\r\n if (data.length < STAKE_DEPOSIT_SIZE) {\r\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\r\n }\r\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\r\n return {\r\n isInitialized: data[0] === 1,\r\n bump: data[1],\r\n pool: new PublicKey(data.subarray(8, 40)),\r\n user: new PublicKey(data.subarray(40, 72)),\r\n lastDepositSlot: readU64LE(data, 72),\r\n lpAmount: readU64LE(data, 80),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Account Specs (for building TransactionInstructions)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface StakeAccounts {\r\n /** InitPool accounts */\r\n initPool: {\r\n admin: PublicKey;\r\n slab: PublicKey;\r\n pool: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n collateralMint: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n /** Deposit accounts */\r\n deposit: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vault: PublicKey;\r\n lpMint: PublicKey;\r\n userLpAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** Withdraw accounts */\r\n withdraw: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userLpAta: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** FlushToInsurance accounts (CPI from stake → percolator) */\r\n flushToInsurance: {\r\n caller: PublicKey;\r\n pool: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n wrapperVault: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n}\r\n\r\n/**\r\n * Build account keys for InitPool instruction.\r\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\r\n *\r\n * @param a - Named accounts for the InitPool instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function initPoolAccounts(\r\n a: StakeAccounts['initPool'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Deposit instruction.\r\n *\r\n * @param a - Named accounts for the Deposit instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function depositAccounts(\r\n a: StakeAccounts['deposit'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Withdraw instruction.\r\n *\r\n * @param a - Named accounts for the Withdraw instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function withdrawAccounts(\r\n a: StakeAccounts['withdraw'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for FlushToInsurance instruction.\r\n *\r\n * @param a - Named accounts for the FlushToInsurance instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function flushToInsuranceAccounts(\r\n a: StakeAccounts['flushToInsurance'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.caller, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n","/**\r\n * @module adl\r\n * Percolator ADL (Auto-Deleveraging) client utilities.\r\n *\r\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\r\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\r\n * The most profitable positions on the dominant side are deleveraged first.\r\n *\r\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\r\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\r\n * instruction being structurally available to any signer.\r\n *\r\n * API surface:\r\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\r\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\r\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\r\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\r\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\r\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\r\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\r\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\r\n * - AdlRankingResult — full ranking with trigger status\r\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\r\n * - AdlApiRanking — single ranked position from /api/adl/rankings\r\n * - AdlApiResult — full result from /api/adl/rankings\r\n * - AdlSide — \"long\" | \"short\"\r\n */\r\n\r\nimport {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n} from \"@solana/web3.js\";\r\nimport {\r\n fetchSlab,\r\n parseAllAccounts,\r\n parseEngine,\r\n parseConfig,\r\n detectSlabLayout,\r\n AccountKind,\r\n Account,\r\n SlabLayout,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Position side derived from positionSize sign. */\r\nexport type AdlSide = \"long\" | \"short\";\r\n\r\nconst V17_ADL_UNSUPPORTED_MESSAGE =\r\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\r\n\r\n/**\r\n * A ranked open position for ADL purposes.\r\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\r\n * and will be deleveraged first.\r\n */\r\nexport interface AdlRankedPosition {\r\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\r\n idx: number;\r\n /** Owner public key. */\r\n owner: PublicKey;\r\n /** Raw position size (i128 — negative = short, positive = long). */\r\n positionSize: bigint;\r\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\r\n pnl: bigint;\r\n /** Capital at entry in lamports (u128). */\r\n capital: bigint;\r\n /**\r\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\r\n * pnlPct = pnl * 10_000 / capital.\r\n * Higher = more profitable = deleveraged first.\r\n */\r\n pnlPct: bigint;\r\n /** Long or short. */\r\n side: AdlSide;\r\n /**\r\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\r\n * `-1` if position size is zero (inactive).\r\n */\r\n adlRank: number;\r\n}\r\n\r\n/**\r\n * Result of `fetchAdlRankedPositions`.\r\n */\r\nexport interface AdlRankingResult {\r\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\r\n ranked: AdlRankedPosition[];\r\n /**\r\n * Longs ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\r\n */\r\n longs: AdlRankedPosition[];\r\n /**\r\n * Shorts ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\r\n * unrealised gain for the short-side holder).\r\n */\r\n shorts: AdlRankedPosition[];\r\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\r\n isTriggered: boolean;\r\n /** pnl_pos_tot from engine state. */\r\n pnlPosTot: bigint;\r\n /** max_pnl_cap from market config. */\r\n maxPnlCap: bigint;\r\n /**\r\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\r\n *\r\n * `null` when the side cannot be determined — either engine state could not be\r\n * parsed at all, OR the detected slab layout carries no open-interest fields.\r\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\r\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\r\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\r\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\r\n *\r\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\r\n * convention, not an on-chain guarantee — the deployed wrapper\r\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\r\n */\r\n dominantSide: AdlSide | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute PnL% in basis points for a position.\r\n * Returns 0n when capital is 0 to avoid division by zero.\r\n */\r\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\r\n if (capital === 0n) return 0n;\r\n return (pnl * 10_000n) / capital;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check whether ADL is currently triggered on a slab.\r\n *\r\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\r\n *\r\n * @param slabData - Raw slab account bytes.\r\n * @returns true if ADL is triggered.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = await fetchSlab(connection, slabKey);\r\n * if (isAdlTriggered(data)) {\r\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\r\n * }\r\n * ```\r\n */\r\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n if (!layout) return false;\r\n try {\r\n const engine = parseEngine(slabData);\r\n if (engine.pnlPosTot === 0n) return false;\r\n const config = parseConfig(slabData, layout);\r\n if (config.maxPnlCap === 0n) return false;\r\n return engine.pnlPosTot > config.maxPnlCap;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\r\n *\r\n * Positions are ranked separately per side:\r\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\r\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\r\n *\r\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\r\n * the position at rank 0 of the dominant side is deleveraged first.\r\n *\r\n * @param connection - Solana connection.\r\n * @param slab - Slab (market) public key.\r\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\r\n *\r\n * @example\r\n * ```ts\r\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\r\n * if (isTriggered && longs.length > 0) {\r\n * const target = longs[0]; // highest PnL long\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankedPositions(\r\n connection: Connection,\r\n slab: PublicKey\r\n): Promise {\r\n const data = await fetchSlab(connection, slab);\r\n return rankAdlPositions(data);\r\n}\r\n\r\n/**\r\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\r\n * Useful when you already have the slab data (e.g., from a subscription).\r\n */\r\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n\r\n let pnlPosTot = 0n;\r\n let dominantSide: AdlSide | null = null;\r\n try {\r\n const engine = parseEngine(slabData);\r\n pnlPosTot = engine.pnlPosTot;\r\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\r\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\r\n // comparing them would fabricate \"long\" from absent data.\r\n const hasOiFields =\r\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\r\n if (hasOiFields) {\r\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\r\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\r\n }\r\n } catch (err) {\r\n console.warn(\r\n `[rankAdlPositions] parseEngine failed:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n let maxPnlCap = 0n;\r\n let isTriggered = false;\r\n if (layout) {\r\n try {\r\n const config = parseConfig(slabData, layout);\r\n maxPnlCap = config.maxPnlCap;\r\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\r\n } catch {\r\n // If config parse fails, leave isTriggered=false; ranking still useful.\r\n }\r\n }\r\n\r\n // Parse all used accounts.\r\n const accounts = parseAllAccounts(slabData);\r\n\r\n // Build ranked position list (user accounts with non-zero position only).\r\n const positions: AdlRankedPosition[] = [];\r\n for (const { idx, account } of accounts) {\r\n if (account.kind !== AccountKind.User) continue;\r\n if (account.positionSize === 0n) continue;\r\n\r\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\r\n // For shorts, positionSize is negative — PnL computation is symmetric:\r\n // a short profits when price falls, so pnl stored in the slab already\r\n // reflects mark-to-market gain/loss for both sides.\r\n const pnlPct = computePnlPct(account.pnl, account.capital);\r\n\r\n positions.push({\r\n idx,\r\n owner: account.owner,\r\n positionSize: account.positionSize,\r\n pnl: account.pnl,\r\n capital: account.capital,\r\n pnlPct,\r\n side,\r\n adlRank: -1, // assigned below\r\n });\r\n }\r\n\r\n // Rank longs: descending pnlPct (most profitable first).\r\n const longs = positions\r\n .filter(p => p.side === \"long\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n longs.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\r\n // magnitude, but pnlPct can be negative; sort descending still puts\r\n // the \"least negative\" aka \"most profitable\" short first).\r\n const shorts = positions\r\n .filter(p => p.side === \"short\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n shorts.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\r\n const ranked = [...longs, ...shorts].sort(\r\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\r\n );\r\n\r\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\r\n}\r\n\r\n/**\r\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\r\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\r\n * utilities remain available.\r\n *\r\n * This function is kept as a deprecated compatibility stub so consumers get a\r\n * deterministic error instead of a lower-level removed-instruction throw.\r\n *\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key for this market.\r\n * @param programId - Percolator program ID.\r\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\r\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\r\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\r\n */\r\nexport function buildAdlInstruction(\r\n _caller: PublicKey,\r\n _slab: PublicKey,\r\n _oracle: PublicKey,\r\n _programId: PublicKey,\r\n targetIdx: number,\r\n _backupOracles: PublicKey[] = []\r\n): TransactionInstruction {\r\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\r\n throw new Error(\r\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\r\n );\r\n }\r\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\r\n}\r\n\r\n/**\r\n * Choose which ranked position an ADL should target.\r\n *\r\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\r\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\r\n * a test routed through it could not observe the choice.\r\n *\r\n * - An explicit `preferSide` always wins.\r\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\r\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\r\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\r\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\r\n * a candidate, nothing more.\r\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\r\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\r\n * rather than guessing a side.\r\n */\r\nexport function selectAdlTarget(\r\n ranking: Pick,\r\n preferSide?: AdlSide,\r\n): AdlRankedPosition | undefined {\r\n if (preferSide === \"long\") return ranking.longs[0];\r\n if (preferSide === \"short\") return ranking.shorts[0];\r\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\r\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\r\n return ranking.ranked[0];\r\n}\r\n\r\n/**\r\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\r\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\r\n *\r\n * Returns `null` when ADL is not triggered or no eligible positions exist.\r\n *\r\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\r\n * When a target IS found it calls `buildAdlInstruction`, which throws\r\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\r\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\r\n * revision of this note claimed it did, which was simply wrong.) It is kept for\r\n * v12 slabs and for when an equivalent v17 instruction lands; the target\r\n * selection in `selectAdlTarget` stays valid either way.\r\n *\r\n * @param connection - Solana connection.\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key.\r\n * @param programId - Percolator program ID.\r\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\r\n * If omitted, picks the dominant side's (greater net OI)\r\n * top-ranked position — or the overall top-ranked position\r\n * when dominantSide is null (engine unparseable, or a\r\n * layout with no OI fields such as V0/V2/v12.15).\r\n * @param backupOracles - Optional extra oracle accounts.\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = await buildAdlTransaction(\r\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\r\n * );\r\n * if (ix) {\r\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\r\n * }\r\n * ```\r\n */\r\nexport async function buildAdlTransaction(\r\n connection: Connection,\r\n caller: PublicKey,\r\n slab: PublicKey,\r\n oracle: PublicKey,\r\n programId: PublicKey,\r\n preferSide?: AdlSide,\r\n backupOracles: PublicKey[] = []\r\n): Promise {\r\n const ranking = await fetchAdlRankedPositions(connection, slab);\r\n\r\n if (!ranking.isTriggered) return null;\r\n\r\n const target = selectAdlTarget(ranking, preferSide);\r\n\r\n if (!target) return null;\r\n\r\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AdlEvent — on-chain log decoder (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\r\n *\r\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\r\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\r\n *\r\n * Fields:\r\n * - `tag` — always `0xAD1E_0001` (2970353665n)\r\n * - `targetIdx` — slab account index that was deleveraged\r\n * - `price` — oracle price used (in market price units, e.g. e6)\r\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\r\n *\r\n * @example\r\n * ```ts\r\n * const logs = tx.meta?.logMessages ?? [];\r\n * const event = parseAdlEvent(logs);\r\n * if (event) {\r\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\r\n * }\r\n * ```\r\n */\r\nexport interface AdlEvent {\r\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\r\n tag: bigint;\r\n /** Slab account index that was deleveraged. */\r\n targetIdx: number;\r\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\r\n price: bigint;\r\n /**\r\n * Absolute position size closed (reassembled from lo+hi u64).\r\n * This is the i128 absolute value — always non-negative.\r\n */\r\n closedAbs: bigint;\r\n}\r\n\r\n/** Magic discriminator for the ADL event log line. */\r\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\r\n\r\n/**\r\n * Parse the AdlEvent from a transaction's log messages.\r\n *\r\n * Searches for a \"Program log: \" line where the first\r\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\r\n *\r\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\r\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\r\n * by this program ID are accepted. Events from CPI-called programs (which can\r\n * produce identical `Program log:` lines) are silently ignored. Pass the\r\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\r\n * Omit only in contexts where the full log has already been filtered.\r\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\r\n *\r\n * @example\r\n * ```ts\r\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\r\n * if (event) {\r\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\r\n * }\r\n * ```\r\n */\r\nexport function parseAdlEvent(\r\n logs: string[],\r\n percolatorProgramId?: string,\r\n): AdlEvent | null {\r\n // Track whether we are currently inside a top-level Percolator invocation.\r\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\r\n let insidePercolator = percolatorProgramId === undefined;\r\n let cpiDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n if (percolatorProgramId !== undefined) {\r\n // Detect Percolator entry / exit.\r\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\r\n insidePercolator = true;\r\n cpiDepth = 0;\r\n continue;\r\n }\r\n if (\r\n line.startsWith(`Program ${percolatorProgramId} success`) ||\r\n line.startsWith(`Program ${percolatorProgramId} failed`)\r\n ) {\r\n insidePercolator = false;\r\n continue;\r\n }\r\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\r\n if (insidePercolator) {\r\n if (/^Program \\S+ invoke/.test(line)) {\r\n cpiDepth++;\r\n continue;\r\n }\r\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\r\n cpiDepth = Math.max(0, cpiDepth - 1);\r\n continue;\r\n }\r\n }\r\n // Skip log lines that are not inside Percolator or are from a CPI callee.\r\n if (!insidePercolator || cpiDepth > 0) continue;\r\n }\r\n\r\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\r\n const match = line.match(\r\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\r\n );\r\n if (!match) continue;\r\n\r\n let tag: bigint;\r\n try {\r\n tag = BigInt(match[1]);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (tag !== ADL_EVENT_TAG) continue;\r\n\r\n try {\r\n const targetIdx = Number(BigInt(match[2]));\r\n const price = BigInt(match[3]);\r\n const closedLo = BigInt(match[4]);\r\n const closedHi = BigInt(match[5]);\r\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\r\n const closedAbs = (closedHi << 64n) | closedLo;\r\n return { tag, targetIdx, price, closedAbs };\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A single ranked position as returned by the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiRanking {\r\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\r\n rank: number;\r\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\r\n idx: number;\r\n /** Absolute PnL (lamports) as a decimal string. */\r\n pnlAbs: string;\r\n /** Capital at entry (lamports) as a decimal string. */\r\n capital: string;\r\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\r\n pnlPctMillionths: string;\r\n}\r\n\r\n/**\r\n * Full result from the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiResult {\r\n slabAddress: string;\r\n /** pnl_pos_tot from slab engine state (decimal string). */\r\n pnlPosTot: string;\r\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\r\n maxPnlCap: string;\r\n /** Insurance fund balance (decimal string). */\r\n insuranceFundBalance: string;\r\n /** Insurance fund lifetime fee revenue (decimal string). */\r\n insuranceFundFeeRevenue: string;\r\n /** Insurance utilization in basis points (0–10000). */\r\n insuranceUtilizationBps: number;\r\n /** true if pnlPosTot > maxPnlCap. */\r\n capExceeded: boolean;\r\n /** true if insurance fund is fully depleted (balance == 0). */\r\n insuranceDepleted: boolean;\r\n /** true if utilization BPS exceeds the configured ADL threshold. */\r\n utilizationTriggered: boolean;\r\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\r\n adlNeeded: boolean;\r\n /** Excess PnL above cap (decimal string). */\r\n excess: string;\r\n /** Ranked positions (empty if adlNeeded=false). */\r\n rankings: AdlApiRanking[];\r\n}\r\n\r\n/**\r\n * Fetch ADL rankings from the Percolator API.\r\n *\r\n * Calls `GET /api/adl/rankings?slab=
` and returns the\r\n * parsed result. Use this from the frontend or keeper to determine ADL\r\n * trigger status and pick the target index.\r\n *\r\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\r\n * @param slab - Slab (market) public key or base58 address string.\r\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\r\n * @returns Parsed `AdlApiResult`.\r\n * @throws On HTTP error or JSON parse failure.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\r\n * if (result.adlNeeded && result.rankings.length > 0) {\r\n * const target = result.rankings[0]; // rank 1 = highest PnL%\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankings(\r\n apiBase: string,\r\n slab: PublicKey | string,\r\n fetchFn: typeof fetch = fetch,\r\n): Promise {\r\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\r\n const base = apiBase.replace(/\\/$/, \"\");\r\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\r\n\r\n const res = await fetchFn(url);\r\n if (!res.ok) {\r\n let body = \"\";\r\n try { body = await res.text(); } catch { /* ignore */ }\r\n throw new Error(\r\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\r\n );\r\n }\r\n\r\n const json: unknown = await res.json();\r\n\r\n // Runtime validation — the API response shape is not guaranteed\r\n if (typeof json !== \"object\" || json === null) {\r\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\r\n }\r\n const obj = json as Record;\r\n if (!Array.isArray(obj.rankings)) {\r\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\r\n }\r\n if (typeof obj.adlNeeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\r\n }\r\n if (typeof obj.capExceeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\r\n }\r\n if (typeof obj.slabAddress !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\r\n }\r\n if (typeof obj.pnlPosTot !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\r\n }\r\n if (typeof obj.maxPnlCap !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\r\n }\r\n for (const entry of obj.rankings) {\r\n if (typeof entry !== \"object\" || entry === null) {\r\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\r\n }\r\n const r = entry as Record;\r\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\r\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\r\n }\r\n }\r\n\r\n return json as AdlApiResult;\r\n}\r\n","/**\r\n * @module backing-bucket\r\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\r\n *\r\n * ## Why this module exists\r\n *\r\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\r\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\r\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\r\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\r\n * predicate.\r\n *\r\n * ## Why lapsing is routine, not exceptional\r\n *\r\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\r\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\r\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\r\n * bucket and only computes a fresh horizon once the bucket is no longer\r\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\r\n * far-future expiry defers the lapse; it does not prevent it.\r\n *\r\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\r\n *\r\n * | Attempt against a lapsed domain | Result |\r\n * |---|---|\r\n * | settle a **loss** | `EngineLockActive` Custom(21) |\r\n * | settle a **gain** | `EngineStale` Custom(19) |\r\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\r\n *\r\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\r\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\r\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\r\n * keeper duty, alongside the fee crank.\r\n *\r\n * ## Layout provenance\r\n *\r\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\r\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\r\n *\r\n * ```\r\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\r\n * BackingBucketV16Account size=97\r\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\r\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\r\n * 88 expiry_slot 96 status\r\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\r\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\r\n * ```\r\n *\r\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\r\n */\r\n\r\nimport {\r\n V17_MARKET_GROUP_OFF,\r\n V17_MARKET_GROUP_LEN,\r\n V17_MARKET_ASSET_SLOT_LEN,\r\n isV17MarketAccount,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Little-endian readers (module-local, matching slab.ts's private helpers)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8At(data: Uint8Array, off: number): number {\r\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\r\n return data[off]!;\r\n}\r\n\r\nfunction readU32LEAt(data: Uint8Array, off: number): number {\r\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\r\n}\r\n\r\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\r\n}\r\n\r\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\r\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\r\n const lo = dv.getBigUint64(0, true);\r\n const hi = dv.getBigUint64(8, true);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Layout constants — all verified with offset_of! (see module doc)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\r\nexport const V17_GROUP_CONFIG_REL = 32;\r\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\r\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\r\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\r\nexport const V17_GROUP_MODE_REL = 626;\r\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\r\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\r\n\r\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\r\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\r\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\r\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\r\n/** `size_of::()`. */\r\nexport const V17_BACKING_BUCKET_LEN = 97;\r\n\r\n// BackingBucketV16Account field offsets, relative to the bucket start.\r\nconst BB_MARKET_ID = 0;\r\nconst BB_FRESH_UNLIENED = 8;\r\nconst BB_VALID_LIENED = 24;\r\nconst BB_CONSUMED_LIENED = 40;\r\nconst BB_IMPAIRED_LIENED = 56;\r\nconst BB_UTILIZATION_FEE = 72;\r\nconst BB_EXPIRY_SLOT = 88;\r\nconst BB_STATUS = 96;\r\n\r\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\r\nexport const V17_MARKET_MODE_LIVE = 0;\r\n\r\n/**\r\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\r\n * serialized as a single `u8` in declaration order.\r\n *\r\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\r\n */\r\nexport enum BackingBucketStatus {\r\n Empty = 0,\r\n Fresh = 1,\r\n Expired = 2,\r\n Impaired = 3,\r\n}\r\n\r\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\r\nexport function backingBucketStatusName(status: number): string {\r\n switch (status) {\r\n case BackingBucketStatus.Empty:\r\n return \"Empty\";\r\n case BackingBucketStatus.Fresh:\r\n return \"Fresh\";\r\n case BackingBucketStatus.Expired:\r\n return \"Expired\";\r\n case BackingBucketStatus.Impaired:\r\n return \"Impaired\";\r\n default:\r\n return `Unknown(${status})`;\r\n }\r\n}\r\n\r\n/** One source-domain backing bucket, decoded from a v17 market account. */\r\nexport interface BackingBucketV17 {\r\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\r\n domain: number;\r\n /** `domain / 2` — the asset slot this domain belongs to. */\r\n assetIndex: number;\r\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\r\n side: \"long\" | \"short\";\r\n /** `BackingBucketV16Account::market_id`. */\r\n marketId: bigint;\r\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\r\n freshUnlienedBackingNum: bigint;\r\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\r\n validLienedBackingNum: bigint;\r\n /** Principal already consumed by settlement. */\r\n consumedLienedBackingNum: bigint;\r\n /** Principal whose lien has been impaired. */\r\n impairedLienedBackingNum: bigint;\r\n /** Utilization fees accrued to this bucket. */\r\n utilizationFeeEarnings: bigint;\r\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\r\n expirySlot: bigint;\r\n /** Raw status byte. */\r\n status: number;\r\n /** `backingBucketStatusName(status)`. */\r\n statusName: string;\r\n /**\r\n * `status === Fresh && nowSlot >= expirySlot`.\r\n *\r\n * This is the *deadlock* condition — settlement against this domain fails in both\r\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\r\n * which additionally applies the wrapper's mode and domain-bound gates.\r\n */\r\n lapsed: boolean;\r\n /**\r\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\r\n * See {@link isBackingBucketExpirable} for the full derivation.\r\n */\r\n expirable: boolean;\r\n}\r\n\r\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\r\nexport interface BackingBucketMarketState {\r\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\r\n mode: number;\r\n /** `header.current_slot` — the engine's own monotone slot counter. */\r\n headerCurrentSlot: bigint;\r\n /**\r\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\r\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\r\n */\r\n nowSlot: bigint;\r\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\r\n maxMarketSlots: number;\r\n /** Asset slots physically present in the account buffer. */\r\n physicalAssetSlots: number;\r\n /**\r\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\r\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\r\n * this index are never expirable; see {@link isBackingBucketExpirable}.\r\n */\r\n addressableDomainCount: number;\r\n /** One entry per addressable domain, ascending by `domain`. */\r\n buckets: BackingBucketV17[];\r\n}\r\n\r\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\r\nexport interface BackingBucketExpiryContext {\r\n /** `header.mode`. */\r\n mode: number;\r\n /** `max(chainSlot, header.current_slot)`. */\r\n nowSlot: bigint;\r\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\r\n addressableDomainCount: number;\r\n}\r\n\r\n/**\r\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\r\n *\r\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\r\n * program rather than from prose. In order of evaluation on chain:\r\n *\r\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\r\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\r\n * market reaches the same transition through the engine's own\r\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\r\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\r\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\r\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\r\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\r\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\r\n * may be *configured* for more slots than its account was *sized* for.\r\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\r\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\r\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\r\n * both deadlocked and expirable, and the two boundaries agree\r\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\r\n *\r\n * `now_slot` is never caller-supplied — the program computes\r\n * `max(Clock::get().slot, header.current_slot)` itself\r\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\r\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\r\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\r\n * bricked. It cannot produce a false positive, because the program recomputes the same\r\n * `max` and no caller can lower it.\r\n *\r\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\r\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\r\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\r\n * two more u128 reads to defend against something that indicates corruption anyway.\r\n *\r\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\r\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\r\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\r\n *\r\n * @example\r\n * ```ts\r\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\r\n * for (const b of state.buckets) {\r\n * if (isBackingBucketExpirable(b, state)) {\r\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isBackingBucketExpirable(\r\n bucket: Pick,\r\n ctx: BackingBucketExpiryContext,\r\n): boolean {\r\n // (1) Live-only mode gate.\r\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\r\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\r\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\r\n // (4) The lapse condition, exactly as the engine states it.\r\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\r\n return ctx.nowSlot >= bucket.expirySlot;\r\n}\r\n\r\n/** Options for {@link parseBackingBucketsV17}. */\r\nexport interface ParseBackingBucketsOptions {\r\n /**\r\n * The current chain slot (`connection.getSlot()`).\r\n *\r\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\r\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\r\n * lapses, never over-report them) but a keeper should always supply it — a market whose\r\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\r\n * bricked.\r\n */\r\n chainSlot?: bigint | number;\r\n}\r\n\r\n/**\r\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\r\n *\r\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\r\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\r\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\r\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\r\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketPk);\r\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\r\n * chainSlot: await connection.getSlot(),\r\n * });\r\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\r\n * ```\r\n */\r\nexport function parseBackingBucketsV17(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): BackingBucketMarketState {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n const groupOff = V17_MARKET_GROUP_OFF;\r\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\r\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\r\n const maxMarketSlots = readU32LEAt(\r\n data,\r\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\r\n );\r\n\r\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\r\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\r\n const chainSlot =\r\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\r\n if (chainSlot < 0n) {\r\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\r\n }\r\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\r\n\r\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\r\n const physicalAssetSlots = Math.max(\r\n 0,\r\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\r\n );\r\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\r\n const addressableDomainCount = addressableAssetSlots * 2;\r\n\r\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\r\n const buckets: BackingBucketV17[] = [];\r\n\r\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\r\n const engineBase =\r\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\r\n for (const side of [\"long\", \"short\"] as const) {\r\n const bucketOff =\r\n engineBase +\r\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\r\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\r\n\r\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\r\n const status = readU8At(data, bucketOff + BB_STATUS);\r\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\r\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\r\n\r\n const bucket: BackingBucketV17 = {\r\n domain,\r\n assetIndex,\r\n side,\r\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\r\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\r\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\r\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\r\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\r\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\r\n expirySlot,\r\n status,\r\n statusName: backingBucketStatusName(status),\r\n lapsed,\r\n expirable: false,\r\n };\r\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\r\n buckets.push(bucket);\r\n }\r\n }\r\n\r\n return {\r\n mode,\r\n headerCurrentSlot,\r\n nowSlot,\r\n maxMarketSlots,\r\n physicalAssetSlots,\r\n addressableDomainCount,\r\n buckets,\r\n };\r\n}\r\n\r\n/**\r\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\r\n *\r\n * Returns domain indices in ascending order, ready to feed straight into\r\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\r\n * common case on a healthy market, and the case in which a keeper must send nothing.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns Ascending list of expirable domain indices; empty when none are due.\r\n *\r\n * @example\r\n * ```ts\r\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\r\n * for (const domain of domains) {\r\n * tx.add(new TransactionInstruction({\r\n * programId: WRAPPER_ID,\r\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\r\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\r\n * }));\r\n * }\r\n * ```\r\n */\r\nexport function findExpirableBackingDomains(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): number[] {\r\n return parseBackingBucketsV17(data, opts)\r\n .buckets.filter((b) => b.expirable)\r\n .map((b) => b.domain);\r\n}\r\n","import {\r\n Connection,\r\n type Commitment,\r\n type ConnectionConfig,\r\n} from \"@solana/web3.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Configuration for exponential-backoff retry on RPC calls.\r\n *\r\n * @example\r\n * ```ts\r\n * const retryConfig: RetryConfig = {\r\n * maxRetries: 3,\r\n * baseDelayMs: 500,\r\n * maxDelayMs: 10_000,\r\n * retryableStatusCodes: [429, 502, 503],\r\n * };\r\n * ```\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts after the initial request fails.\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Base delay in ms for exponential backoff.\r\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\r\n * @default 500\r\n */\r\n baseDelayMs?: number;\r\n\r\n /**\r\n * Maximum delay in ms (backoff cap).\r\n * @default 10_000\r\n */\r\n maxDelayMs?: number;\r\n\r\n /**\r\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\r\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\r\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\r\n * jitter entirely (deterministic backoff).\r\n * @default 0.25\r\n */\r\n jitterFactor?: number;\r\n\r\n /**\r\n * HTTP status codes considered retryable.\r\n * Errors matching these codes (or containing their string representation)\r\n * will be retried.\r\n * @default [429, 502, 503, 504]\r\n */\r\n retryableStatusCodes?: number[];\r\n}\r\n\r\n/**\r\n * Configuration for a single RPC endpoint in the pool.\r\n *\r\n * @example\r\n * ```ts\r\n * const endpoint: RpcEndpointConfig = {\r\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\r\n * weight: 10,\r\n * label: \"helius-primary\",\r\n * };\r\n * ```\r\n */\r\nexport interface RpcEndpointConfig {\r\n /** RPC endpoint URL. */\r\n url: string;\r\n\r\n /**\r\n * Relative weight for round-robin selection.\r\n * Higher weight = more requests routed here.\r\n * @default 1\r\n */\r\n weight?: number;\r\n\r\n /**\r\n * Human-readable label for logging / diagnostics.\r\n * @default url hostname\r\n */\r\n label?: string;\r\n\r\n /**\r\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\r\n * merged into the Solana `Connection` constructor for this endpoint.\r\n */\r\n connectionConfig?: ConnectionConfig;\r\n}\r\n\r\n/**\r\n * Strategy for selecting the next RPC endpoint from the pool.\r\n *\r\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\r\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\r\n */\r\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\r\n\r\n/**\r\n * Full configuration for the RPC connection pool.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3, baseDelayMs: 500 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Use like a Connection — same surface\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n * ```\r\n */\r\nexport interface RpcPoolConfig {\r\n /**\r\n * One or more RPC endpoints. At least one is required.\r\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\r\n */\r\n endpoints: (RpcEndpointConfig | string)[];\r\n\r\n /**\r\n * How to pick the next endpoint.\r\n * @default \"failover\"\r\n */\r\n strategy?: SelectionStrategy;\r\n\r\n /**\r\n * Retry config applied to every `call()`.\r\n * Set to `false` to disable retries entirely.\r\n * @default { maxRetries: 3, baseDelayMs: 500 }\r\n */\r\n retry?: RetryConfig | false;\r\n\r\n /**\r\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\r\n * calls where supported, and is used as a deadline for the health probe.\r\n * @default 30_000\r\n */\r\n requestTimeoutMs?: number;\r\n\r\n /**\r\n * Default Solana commitment level for connections.\r\n * @default \"confirmed\"\r\n */\r\n commitment?: Commitment;\r\n\r\n /**\r\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n\r\n /**\r\n * Time in ms after which a continuously unhealthy endpoint is automatically\r\n * restored to healthy so it can be retried. Set to 0 to disable time-based\r\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\r\n * endpoints are exhausted).\r\n * @default 60_000\r\n */\r\n recoveryAfterMs?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Health Probe\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Result of an RPC health probe.\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\r\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\r\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\r\n * ```\r\n */\r\nexport interface RpcHealthResult {\r\n /** The endpoint that was probed. */\r\n endpoint: string;\r\n /** Whether the probe succeeded (getSlot returned without error). */\r\n healthy: boolean;\r\n /** Round-trip latency in milliseconds (0 if unhealthy). */\r\n latencyMs: number;\r\n /** Current slot height (0 if unhealthy). */\r\n slot: number;\r\n /** Error message if the probe failed. */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\r\n *\r\n * @param endpoint - RPC URL to probe\r\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\r\n * @returns Health result with latency and slot height\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\r\n * if (result.healthy) {\r\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\r\n * } else {\r\n * console.error(`RPC down: ${result.error}`);\r\n * }\r\n * ```\r\n */\r\nexport async function checkRpcHealth(\r\n endpoint: string,\r\n timeoutMs: number = 5_000,\r\n): Promise {\r\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\r\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\r\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\r\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\r\n const start = performance.now();\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: 1,\r\n method: \"getSlot\",\r\n params: [{ commitment: \"processed\" }],\r\n }),\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n const latencyMs = Math.round(performance.now() - start);\r\n if (!res.ok) {\r\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\r\n }\r\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\r\n if (json?.error || typeof json?.result !== \"number\") {\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: json?.error?.message ?? \"invalid getSlot response\",\r\n };\r\n }\r\n return { endpoint, healthy: true, latencyMs, slot: json.result };\r\n } catch (err) {\r\n const latencyMs = Math.round(performance.now() - start);\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved defaults for RetryConfig. */\r\ninterface ResolvedRetryConfig {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n jitterFactor: number;\r\n retryableStatusCodes: number[];\r\n}\r\n\r\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\r\n if (cfg === false) return null;\r\n const c = cfg ?? {};\r\n return {\r\n maxRetries: c.maxRetries ?? 3,\r\n baseDelayMs: c.baseDelayMs ?? 500,\r\n maxDelayMs: c.maxDelayMs ?? 10_000,\r\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\r\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\r\n };\r\n}\r\n\r\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\r\n if (typeof ep === \"string\") return { url: ep };\r\n return ep;\r\n}\r\n\r\nfunction endpointLabel(ep: RpcEndpointConfig): string {\r\n if (ep.label) return ep.label;\r\n try {\r\n return new URL(ep.url).hostname;\r\n } catch {\r\n return ep.url.slice(0, 40);\r\n }\r\n}\r\n\r\nfunction isRetryable(err: unknown, codes: number[]): boolean {\r\n if (!err) return false;\r\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\r\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\r\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\r\n // error shapes by name BEFORE any substring match below.\r\n const errName = (err as { name?: unknown })?.name;\r\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n for (const code of codes) {\r\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\r\n let timer: ReturnType;\r\n const promise = new Promise((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(message)), ms);\r\n });\r\n return { promise, cancel: () => clearTimeout(timer!) };\r\n}\r\n\r\n/** Sleep utility. */\r\nfunction sleep(ms: number): Promise {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\r\n * key, password) from a URL so it is safe for logging / status output.\r\n */\r\nfunction redactUrl(raw: string): string {\r\n try {\r\n const u = new URL(raw);\r\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\r\n for (const k of [...u.searchParams.keys()]) {\r\n if (sensitive.test(k)) {\r\n u.searchParams.set(k, \"***\");\r\n }\r\n }\r\n return u.toString();\r\n } catch {\r\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\r\n return raw;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// RpcPool\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-endpoint tracked state. */\r\ninterface EndpointState {\r\n config: RpcEndpointConfig;\r\n connection: Connection;\r\n label: string;\r\n weight: number;\r\n /** Consecutive failure count. Resets on success. */\r\n failures: number;\r\n /** Whether this endpoint is considered healthy. */\r\n healthy: boolean;\r\n /** Last probe latency (ms), -1 if never probed. */\r\n lastLatencyMs: number;\r\n /**\r\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\r\n * failure streak. Cleared on success or manual recovery. Used by the\r\n * time-based auto-recovery logic in `selectEndpoint`.\r\n */\r\n unhealthySince?: number;\r\n}\r\n\r\n/**\r\n * RPC connection pool with retry, failover, and round-robin support.\r\n *\r\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\r\n * that automatically retries transient errors and fails over to alternate\r\n * endpoints when one goes down.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Execute any Connection method through the pool\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n *\r\n * // Or get a raw connection for one-off use\r\n * const conn = pool.getConnection();\r\n *\r\n * // Health check all endpoints\r\n * const results = await pool.healthCheck();\r\n * ```\r\n */\r\nexport class RpcPool {\r\n private readonly endpoints: EndpointState[];\r\n private readonly strategy: SelectionStrategy;\r\n private readonly retryConfig: ResolvedRetryConfig | null;\r\n private readonly requestTimeoutMs: number;\r\n private readonly verbose: boolean;\r\n /** Time-based recovery window in ms (0 = disabled). */\r\n private readonly recoveryAfterMs: number;\r\n\r\n /** Round-robin index tracker. */\r\n private rrIndex: number = 0;\r\n\r\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\r\n private static readonly UNHEALTHY_THRESHOLD = 3;\r\n\r\n /** Minimum endpoints before auto-recovery is attempted. */\r\n private static readonly MIN_HEALTHY = 1;\r\n\r\n constructor(config: RpcPoolConfig) {\r\n if (!config.endpoints || config.endpoints.length === 0) {\r\n throw new Error(\"RpcPool: at least one endpoint is required\");\r\n }\r\n\r\n this.strategy = config.strategy ?? \"failover\";\r\n this.retryConfig = resolveRetryConfig(config.retry);\r\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\r\n this.verbose = config.verbose ?? true;\r\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\r\n\r\n const commitment = config.commitment ?? \"confirmed\";\r\n\r\n this.endpoints = config.endpoints.map(raw => {\r\n const ep = normalizeEndpoint(raw);\r\n const connConfig: ConnectionConfig = {\r\n commitment,\r\n ...ep.connectionConfig,\r\n };\r\n return {\r\n config: ep,\r\n connection: new Connection(ep.url, connConfig),\r\n label: endpointLabel(ep),\r\n weight: Math.max(1, ep.weight ?? 1),\r\n failures: 0,\r\n healthy: true,\r\n lastLatencyMs: -1,\r\n };\r\n });\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Public API\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Execute a function against a pooled connection with automatic retry\r\n * and failover.\r\n *\r\n * @param fn - Async function that receives a `Connection` and returns a result.\r\n * @returns The result of `fn`.\r\n * @throws The last error if all retries and failovers are exhausted.\r\n *\r\n * @example\r\n * ```ts\r\n * const balance = await pool.call(c => c.getBalance(pubkey));\r\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\r\n * ```\r\n */\r\n async call(fn: (connection: Connection) => Promise): Promise {\r\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\r\n let lastError: unknown;\r\n\r\n // Track which endpoints we have tried in this call to avoid infinite loops.\r\n const triedEndpoints = new Set();\r\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\r\n const maxTotalIterations = maxAttempts + this.endpoints.length;\r\n let totalIterations = 0;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (++totalIterations > maxTotalIterations) break;\r\n const epIdx = this.selectEndpoint(triedEndpoints);\r\n if (epIdx === -1) {\r\n // All endpoints exhausted\r\n break;\r\n }\r\n const ep = this.endpoints[epIdx];\r\n\r\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\r\n try {\r\n const result = await Promise.race([\r\n fn(ep.connection),\r\n timeout.promise,\r\n ]);\r\n\r\n // Success — reset failure count\r\n ep.failures = 0;\r\n ep.healthy = true;\r\n ep.unhealthySince = undefined;\r\n return result;\r\n } catch (err) {\r\n lastError = err;\r\n ep.failures++;\r\n\r\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\r\n ep.healthy = false;\r\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\r\n );\r\n }\r\n }\r\n\r\n const retryable = this.retryConfig\r\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\r\n : false;\r\n\r\n if (!retryable) {\r\n // For non-retryable errors in failover mode, try the next endpoint\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n // Don't count this as a retry attempt — just failover\r\n attempt--;\r\n if (triedEndpoints.size >= this.endpoints.length) break;\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Retryable error\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n // In failover mode, try next endpoint before retrying same one\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n }\r\n\r\n // Backoff before retry\r\n if (attempt < maxAttempts - 1 && this.retryConfig) {\r\n const delay = computeDelay(attempt, this.retryConfig);\r\n await sleep(delay);\r\n }\r\n } finally {\r\n timeout.cancel();\r\n }\r\n }\r\n\r\n // All attempts exhausted — try recovery before giving up\r\n this.maybeRecoverEndpoints();\r\n\r\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\r\n }\r\n\r\n /**\r\n * Get a raw `Connection` from the current preferred endpoint.\r\n * Useful when you need to pass a Connection to external code.\r\n *\r\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\r\n *\r\n * @returns Solana Connection from the current preferred endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const conn = pool.getConnection();\r\n * const balance = await conn.getBalance(pubkey);\r\n * ```\r\n */\r\n getConnection(): Connection {\r\n const idx = this.selectEndpoint();\r\n if (idx === -1) {\r\n // All marked unhealthy — reset and use first\r\n this.maybeRecoverEndpoints();\r\n return this.endpoints[0].connection;\r\n }\r\n return this.endpoints[idx].connection;\r\n }\r\n\r\n /**\r\n * Run a health check against all endpoints in the pool.\r\n *\r\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\r\n * @returns Array of health results, one per endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await pool.healthCheck();\r\n * for (const r of results) {\r\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\r\n * }\r\n * ```\r\n */\r\n async healthCheck(timeoutMs: number = 5_000): Promise {\r\n const results = await Promise.all(\r\n this.endpoints.map(async (ep) => {\r\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\r\n ep.lastLatencyMs = result.latencyMs;\r\n ep.healthy = result.healthy;\r\n if (result.healthy) {\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n result.endpoint = redactUrl(result.endpoint);\r\n return result;\r\n }),\r\n );\r\n return results;\r\n }\r\n\r\n /**\r\n * Get the number of endpoints in the pool.\r\n */\r\n get size(): number {\r\n return this.endpoints.length;\r\n }\r\n\r\n /**\r\n * Get the number of currently healthy endpoints.\r\n */\r\n get healthyCount(): number {\r\n return this.endpoints.filter(ep => ep.healthy).length;\r\n }\r\n\r\n /**\r\n * Get endpoint labels and their current status.\r\n *\r\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\r\n */\r\n status(): Array<{\r\n label: string;\r\n url: string;\r\n healthy: boolean;\r\n failures: number;\r\n lastLatencyMs: number;\r\n }> {\r\n return this.endpoints.map(ep => ({\r\n label: ep.label,\r\n url: redactUrl(ep.config.url),\r\n healthy: ep.healthy,\r\n failures: ep.failures,\r\n lastLatencyMs: ep.lastLatencyMs,\r\n }));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Internals\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Select the next endpoint based on strategy.\r\n * Returns -1 if no endpoint is available.\r\n */\r\n private selectEndpoint(exclude?: Set): number {\r\n // Time-based auto-recovery: restore endpoints that have been unhealthy\r\n // for longer than recoveryAfterMs so they can be retried.\r\n if (this.recoveryAfterMs > 0) {\r\n const now = Date.now();\r\n for (const ep of this.endpoints) {\r\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n if (this.verbose) {\r\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthy = this.endpoints\r\n .map((ep, i) => ({ ep, i }))\r\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\r\n\r\n if (healthy.length === 0) {\r\n // No healthy endpoints — try all non-excluded\r\n const remaining = this.endpoints\r\n .map((_, i) => i)\r\n .filter(i => !(exclude?.has(i)));\r\n return remaining.length > 0 ? remaining[0] : -1;\r\n }\r\n\r\n if (this.strategy === \"failover\") {\r\n // Return first healthy (by insertion order)\r\n return healthy[0].i;\r\n }\r\n\r\n // Weighted round-robin\r\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\r\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\r\n\r\n let cumulative = 0;\r\n for (const { ep, i } of healthy) {\r\n cumulative += ep.weight;\r\n if (this.rrIndex < cumulative) return i;\r\n }\r\n\r\n return healthy[healthy.length - 1].i;\r\n }\r\n\r\n /**\r\n * If all endpoints are unhealthy, reset them so we at least try again.\r\n */\r\n private maybeRecoverEndpoints(): void {\r\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\r\n if (healthyCount < RpcPool.MIN_HEALTHY) {\r\n if (this.verbose) {\r\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\r\n }\r\n for (const ep of this.endpoints) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone retry wrapper (for use without a full pool)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute an async function with exponential-backoff retry.\r\n *\r\n * Use this when you already have a `Connection` and just want retry logic\r\n * without a full pool.\r\n *\r\n * @param fn - Async function to execute\r\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\r\n * @returns Result of `fn`\r\n * @throws The last error if all retries are exhausted\r\n *\r\n * @example\r\n * ```ts\r\n * import { withRetry } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const slot = await withRetry(\r\n * () => conn.getSlot(),\r\n * { maxRetries: 3, baseDelayMs: 1000 },\r\n * );\r\n * ```\r\n */\r\nexport async function withRetry(\r\n fn: () => Promise,\r\n config?: RetryConfig,\r\n): Promise {\r\n const resolved = resolveRetryConfig(config) ?? {\r\n maxRetries: 3,\r\n baseDelayMs: 500,\r\n maxDelayMs: 10_000,\r\n jitterFactor: 0.25,\r\n retryableStatusCodes: [429, 502, 503, 504],\r\n };\r\n\r\n let lastError: unknown;\r\n const maxAttempts = resolved.maxRetries + 1;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (err) {\r\n lastError = err;\r\n\r\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\r\n throw err;\r\n }\r\n\r\n if (attempt < maxAttempts - 1) {\r\n const delay = computeDelay(attempt, resolved);\r\n await sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-export helpers for testing\r\n// ---------------------------------------------------------------------------\r\n\r\n/** @internal — exposed for unit tests only */\r\nexport const _internal = {\r\n isRetryable,\r\n computeDelay,\r\n resolveRetryConfig,\r\n normalizeEndpoint,\r\n endpointLabel,\r\n} as const;\r\n","import {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n Transaction,\r\n Keypair,\r\n SendOptions,\r\n Commitment,\r\n AccountMeta,\r\n ComputeBudgetProgram,\r\n} from \"@solana/web3.js\";\r\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\r\n\r\n/**\r\n * Rank of the three cluster confirmation levels the RPC reports in\r\n * `SignatureStatus.confirmationStatus`.\r\n */\r\nconst CONFIRMATION_RANK = {\r\n processed: 0,\r\n confirmed: 1,\r\n finalized: 2,\r\n} as const;\r\n\r\n/**\r\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\r\n * The deprecated aliases map onto their modern equivalents exactly as\r\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\r\n * recent -> processed.\r\n */\r\nfunction requiredConfirmationRank(commitment: Commitment): number {\r\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\r\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\r\n // aliases as:\r\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\r\n // 'finalized' | 'max' | 'root' -> requires finalized\r\n // everything else ('processed', 'recent') -> requires >= processed\r\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\r\n // meant a caller asking for `singleGossip` and observing only a `processed`\r\n // status was told the transaction had SETTLED — reintroducing exactly the\r\n // premature-settlement bug this function exists to prevent.\r\n switch (commitment) {\r\n case \"confirmed\":\r\n case \"single\":\r\n case \"singleGossip\":\r\n return CONFIRMATION_RANK.confirmed;\r\n case \"finalized\":\r\n case \"max\":\r\n case \"root\":\r\n return CONFIRMATION_RANK.finalized;\r\n case \"processed\":\r\n case \"recent\":\r\n default:\r\n return CONFIRMATION_RANK.processed;\r\n }\r\n}\r\n\r\n/**\r\n * True when an observed signature status is at least as strong as the level the\r\n * caller asked for. A merely \"processed\" transaction can still be dropped or\r\n * rolled back, so treating it as settled would reintroduce exactly the premature\r\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\r\n */\r\nfunction meetsCommitment(\r\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\r\n required: Commitment\r\n): boolean {\r\n if (!observed) return false;\r\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\r\n}\r\n\r\nexport interface BuildIxParams {\r\n programId: PublicKey;\r\n keys: AccountMeta[];\r\n data: Uint8Array | Buffer;\r\n}\r\n\r\n/**\r\n * Build a transaction instruction.\r\n */\r\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\r\n return new TransactionInstruction({\r\n programId: params.programId,\r\n keys: params.keys,\r\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\r\n // Cast to avoid Buffer polyfill issues in the browser.\r\n data: params.data as Buffer,\r\n });\r\n}\r\n\r\nexport interface TxResult {\r\n signature: string;\r\n slot: number;\r\n err: string | null;\r\n hint?: string;\r\n logs: string[];\r\n unitsConsumed?: number;\r\n}\r\n\r\nexport interface SimulateOrSendParams {\r\n connection: Connection;\r\n ix: TransactionInstruction;\r\n signers: Keypair[];\r\n simulate: boolean;\r\n commitment?: Commitment;\r\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\r\n /**\r\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\r\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\r\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\r\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\r\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\r\n * multiple of 1024 in [32768, 262144].\r\n */\r\n heapFrameBytes?: number;\r\n}\r\n\r\n/**\r\n * Simulate or send a transaction.\r\n * Returns consistent output for both modes.\r\n */\r\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\r\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\r\n\r\n/**\r\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\r\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\r\n */\r\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\r\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\r\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\r\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\r\n\r\nexport async function simulateOrSend(\r\n params: SimulateOrSendParams\r\n): Promise {\r\n const {\r\n connection,\r\n ix,\r\n signers,\r\n simulate,\r\n commitment,\r\n computeUnitLimit,\r\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\r\n } = params;\r\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\r\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\r\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\r\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\r\n\r\n if (typeof simulate !== \"boolean\") {\r\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\r\n }\r\n\r\n if (!signers.length) {\r\n throw new Error(\"simulateOrSend: at least one signer is required\");\r\n }\r\n\r\n if (computeUnitLimit !== undefined) {\r\n if (\r\n typeof computeUnitLimit !== \"number\" ||\r\n !Number.isInteger(computeUnitLimit) ||\r\n computeUnitLimit < 1 ||\r\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\r\n ) {\r\n throw new Error(\r\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\r\n );\r\n }\r\n }\r\n\r\n if (heapFrameBytes !== 0) {\r\n if (\r\n typeof heapFrameBytes !== \"number\" ||\r\n !Number.isInteger(heapFrameBytes) ||\r\n heapFrameBytes % 1024 !== 0 ||\r\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\r\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\r\n ) {\r\n throw new Error(\r\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\r\n );\r\n }\r\n }\r\n\r\n const tx = new Transaction();\r\n\r\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\r\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\r\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\r\n if (heapFrameBytes !== 0) {\r\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\r\n }\r\n\r\n // Add compute budget instruction if custom limit is specified\r\n if (computeUnitLimit !== undefined) {\r\n tx.add(\r\n ComputeBudgetProgram.setComputeUnitLimit({\r\n units: computeUnitLimit,\r\n })\r\n );\r\n }\r\n\r\n tx.add(ix);\r\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\r\n tx.recentBlockhash = latestBlockhash.blockhash;\r\n tx.feePayer = signers[0].publicKey;\r\n\r\n if (simulate) {\r\n try {\r\n tx.sign(...signers);\r\n const result = await connection.simulateTransaction(tx, signers);\r\n const logs = result.value.logs ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (result.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(result.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature: \"(simulated)\",\r\n slot: result.context.slot,\r\n err,\r\n hint,\r\n logs,\r\n unitsConsumed: result.value.unitsConsumed ?? undefined,\r\n };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"(simulated)\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n }\r\n\r\n // Send\r\n const options: SendOptions = {\r\n skipPreflight: false,\r\n preflightCommitment: effectiveCommitment,\r\n };\r\n\r\n // sendTransaction is its own try/catch: only here is it true that no\r\n // signature was ever produced, so signature: \"\" is the correct result.\r\n let signature: string;\r\n try {\r\n signature = await connection.sendTransaction(tx, signers, options);\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n\r\n // Fetch logs at the same finality level used for confirmation.\r\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\r\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\r\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\r\n\r\n try {\r\n const confirmation = await connection.confirmTransaction(\r\n {\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n },\r\n effectiveCommitment\r\n );\r\n\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (confirmation.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(confirmation.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature,\r\n slot: txInfo?.slot ?? 0,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n } catch (e: unknown) {\r\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\r\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\r\n // only that we didn't observe confirmation in time. Previously this branch discarded\r\n // the real signature obtained above and returned signature: \"\", which left the caller\r\n // with no way to check whether it's safe to retry — for a non-idempotent operation\r\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\r\n // transaction that had actually already landed. Check the real on-chain status before\r\n // reporting failure, and always return the real signature so the caller can verify\r\n // it themselves even if this fallback check also fails.\r\n const message = e instanceof Error ? e.message : String(e);\r\n try {\r\n const status = await connection.getSignatureStatus(signature, {\r\n searchTransactionHistory: true,\r\n });\r\n // Only treat the fallback lookup as authoritative when the observed level\r\n // actually satisfies the commitment the caller asked for. `status.value`\r\n // being non-null merely means the cluster has SEEN the transaction — at\r\n // \"processed\" it can still be dropped or rolled back, and reporting that\r\n // as a settled success would be the same premature-settlement bug #311 fixed.\r\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n if (status.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(status.value.err);\r\n }\r\n }\r\n return {\r\n signature,\r\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\r\n // `status.context.slot` is the RPC's head slot at query time — a\r\n // different, much later number — so it must not be used as the tx slot.\r\n slot: txInfo?.slot ?? status.value.slot,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n }\r\n if (status.value) {\r\n // Seen, but weaker than requested. Report it as unresolved rather than\r\n // settled, while still handing back the signature and the real landing slot.\r\n const observed = status.value.confirmationStatus ?? \"unknown\";\r\n return {\r\n signature,\r\n slot: status.value.slot,\r\n err:\r\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\r\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\r\n `Check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n } catch {\r\n // Status lookup itself failed too — fall through to the ambiguous result below,\r\n // which still carries the real signature instead of discarding it.\r\n }\r\n return {\r\n signature,\r\n slot: 0,\r\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Format transaction result for output.\r\n */\r\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\r\n if (jsonMode) {\r\n return JSON.stringify(result, null, 2);\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n if (result.err) {\r\n lines.push(`Error: ${result.err}`);\r\n if (result.hint) {\r\n lines.push(`Hint: ${result.hint}`);\r\n }\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.logs.length > 0) {\r\n lines.push(\"Logs:\");\r\n result.logs.forEach((log) => lines.push(` ${log}`));\r\n }\r\n } else {\r\n lines.push(`Signature: ${result.signature}`);\r\n lines.push(`Slot: ${result.slot}`);\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.signature !== \"(simulated)\") {\r\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * @module lighthouse\r\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\r\n *\r\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\r\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\r\n * scanning service. It adds assertion instructions to transactions that verify account\r\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\r\n * X lamports\").\r\n *\r\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\r\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\r\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\r\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\r\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\r\n * logic is correct.\r\n *\r\n * **Solution:** The SDK provides utilities to:\r\n * 1. Detect Lighthouse instructions in a transaction\r\n * 2. Strip them before sending\r\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\r\n * 4. Provide clear, actionable error messages for end users\r\n *\r\n * @example\r\n * ```ts\r\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\r\n *\r\n * // Before sending: strip injected Lighthouse IXs\r\n * const cleanIxs = stripLighthouseInstructions(instructions);\r\n *\r\n * // After error: classify and give user-friendly message\r\n * if (isLighthouseError(error)) {\r\n * console.warn(\"Wallet middleware blocked the transaction\");\r\n * }\r\n * ```\r\n */\r\n\r\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\r\n *\r\n * This is an immutable Anchor program deployed at slot 294,179,293.\r\n * Wallets like Phantom inject instructions from this program into user\r\n * transactions to enforce Blowfish security assertions.\r\n */\r\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\r\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\r\n);\r\n\r\n/** Base58 string form for fast comparison without PublicKey instantiation. */\r\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\r\n\r\n/**\r\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\r\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\r\n * when an account constraint check fails.\r\n */\r\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\r\n\r\n/**\r\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\r\n * All are in the Anchor error range (0x1770–0x1900+).\r\n */\r\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\r\n 0x1770, // InstructionMissing\r\n 0x1771, // InstructionFallbackNotFound\r\n 0x1772, // InstructionDidNotDeserialize\r\n 0x1773, // InstructionDidNotSerialize\r\n 0x1780, // IdlInstructionStub\r\n 0x1790, // ConstraintMut\r\n 0x1791, // ConstraintHasOne\r\n 0x1792, // ConstraintSigner\r\n 0x1793, // ConstraintRaw\r\n 0x1794, // ConstraintOwner\r\n 0x1795, // ConstraintRentExempt\r\n 0x1796, // ConstraintSeeds\r\n 0x1797, // ConstraintExecutable\r\n 0x1798, // ConstraintState\r\n 0x1799, // ConstraintAssociated\r\n 0x179a, // ConstraintAssociatedInit\r\n 0x179b, // ConstraintClose\r\n 0x1900, // ConstraintAddress (the one we hit most often)\r\n] as const);\r\n\r\n// ============================================================================\r\n// Detection\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a TransactionInstruction is from the Lighthouse program.\r\n *\r\n * @param ix - A Solana transaction instruction.\r\n * @returns `true` if the instruction's programId is Lighthouse.\r\n *\r\n * @example\r\n * ```ts\r\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\r\n * ```\r\n */\r\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\r\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if an error message or error object indicates a Lighthouse assertion failure.\r\n *\r\n * Detects:\r\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\r\n * - References to the Lighthouse program ID in error text\r\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\r\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\r\n * failing program is Lighthouse (identified by program ID in logs)\r\n *\r\n * @param error - An Error object, error message string, or transaction logs array.\r\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await sendTransaction(tx);\r\n * } catch (e) {\r\n * if (isLighthouseError(e)) {\r\n * // Retry with skipPreflight or notify user about wallet middleware\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isLighthouseError(error: unknown): boolean {\r\n const msg = extractErrorMessage(error);\r\n if (!msg) return false;\r\n\r\n // Direct program ID reference\r\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\r\n\r\n // 0x1900 hex error code (case-insensitive)\r\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\r\n\r\n // JSON InstructionError format: {\"Custom\": 6400}\r\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if transaction logs contain evidence of a Lighthouse failure.\r\n *\r\n * More precise than `isLighthouseError` on a string — examines the program\r\n * invocation chain to confirm the error originates from Lighthouse, not from\r\n * a Percolator instruction that happens to return a similar code.\r\n *\r\n * @param logs - Array of transaction log lines from `getTransaction()`.\r\n * @returns `true` if logs show a Lighthouse program failure.\r\n */\r\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\r\n if (!Array.isArray(logs)) return false;\r\n\r\n let lighthouseDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n // Track Lighthouse program invocation depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\r\n lighthouseDepth++;\r\n continue;\r\n }\r\n\r\n // Lighthouse program returned success — decrement depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\r\n if (lighthouseDepth > 0) lighthouseDepth--;\r\n continue;\r\n }\r\n\r\n // Only report failure when the Lighthouse program itself explicitly fails\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// Stripping / Mitigation\r\n// ============================================================================\r\n\r\n/**\r\n * Remove all Lighthouse assertion instructions from an instruction array.\r\n *\r\n * Call this before building a Transaction to prevent Lighthouse assertion\r\n * failures. Safe to call even if no Lighthouse instructions are present.\r\n *\r\n * @param instructions - Array of transaction instructions.\r\n * @returns Filtered array with Lighthouse instructions removed.\r\n *\r\n * @example\r\n * ```ts\r\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\r\n *\r\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\r\n * const clean = stripLighthouseInstructions(instructions);\r\n * const tx = new Transaction().add(...clean);\r\n * ```\r\n */\r\nexport function stripLighthouseInstructions(\r\n instructions: TransactionInstruction[],\r\n percolatorProgramId?: PublicKey,\r\n): TransactionInstruction[] {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions — prevents misuse on\r\n // arbitrary transactions where Lighthouse guards are legitimate protection.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) {\r\n return instructions; // no Percolator instructions — leave guards intact\r\n }\r\n }\r\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\r\n}\r\n\r\n/**\r\n * Strip Lighthouse instructions from an already-built Transaction.\r\n *\r\n * Creates a new Transaction with the same recentBlockhash and feePayer\r\n * but without any Lighthouse instructions. The returned transaction is\r\n * unsigned and must be re-signed.\r\n *\r\n * @param transaction - A Transaction (signed or unsigned).\r\n * @returns A new Transaction without Lighthouse instructions, or the same\r\n * transaction if no Lighthouse instructions were found.\r\n *\r\n * @example\r\n * ```ts\r\n * const signed = await wallet.signTransaction(tx);\r\n * if (hasLighthouseInstructions(signed)) {\r\n * const clean = stripLighthouseFromTransaction(signed);\r\n * const reSigned = await wallet.signTransaction(clean);\r\n * await connection.sendRawTransaction(reSigned.serialize());\r\n * }\r\n * ```\r\n */\r\nexport function stripLighthouseFromTransaction(\r\n transaction: Transaction,\r\n percolatorProgramId?: PublicKey,\r\n): Transaction {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = transaction.instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) return transaction;\r\n }\r\n\r\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\r\n if (!hasLighthouse) return transaction;\r\n\r\n const clean = new Transaction();\r\n clean.recentBlockhash = transaction.recentBlockhash;\r\n clean.feePayer = transaction.feePayer;\r\n\r\n for (const ix of transaction.instructions) {\r\n if (!isLighthouseInstruction(ix)) {\r\n clean.add(ix);\r\n }\r\n }\r\n\r\n return clean;\r\n}\r\n\r\n/**\r\n * Count Lighthouse instructions in an instruction array or transaction.\r\n *\r\n * @param ixsOrTx - Array of instructions or a Transaction.\r\n * @returns Number of Lighthouse instructions found.\r\n */\r\nexport function countLighthouseInstructions(\r\n ixsOrTx: TransactionInstruction[] | Transaction,\r\n): number {\r\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\r\n return instructions.filter(isLighthouseInstruction).length;\r\n}\r\n\r\n// ============================================================================\r\n// User-facing error messages\r\n// ============================================================================\r\n\r\n/**\r\n * User-friendly error message for Lighthouse assertion failures.\r\n *\r\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\r\n */\r\nexport const LIGHTHOUSE_USER_MESSAGE =\r\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\r\n \"This is a known compatibility issue — the transaction itself is valid. \" +\r\n \"Try one of these workarounds:\\n\" +\r\n \"1. Disable transaction simulation in your wallet settings\\n\" +\r\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\r\n \"3. The SDK will automatically retry without the guard\";\r\n\r\n/**\r\n * Classify an error and return an appropriate user-facing message.\r\n *\r\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\r\n * Otherwise returns `null` (callers should use their own error display).\r\n *\r\n * @param error - An Error, string, or logs array.\r\n * @returns User-facing message string, or `null` if not a Lighthouse error.\r\n */\r\nexport function classifyLighthouseError(error: unknown): string | null {\r\n if (isLighthouseError(error)) {\r\n return LIGHTHOUSE_USER_MESSAGE;\r\n }\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Internal helpers\r\n// ============================================================================\r\n\r\nfunction extractErrorMessage(error: unknown): string | null {\r\n if (!error) return null;\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n if (typeof error === \"object\" && \"message\" in error) {\r\n return String((error as { message: unknown }).message);\r\n }\r\n try {\r\n return JSON.stringify(error);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Coin-margined perpetual trade math utilities.\r\n *\r\n * On-chain PnL formula:\r\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\r\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\r\n *\r\n * All prices are in e6 format (1 USD = 1_000_000).\r\n * All token amounts are in native units (e.g. lamports).\r\n */\r\n\r\n/**\r\n * Compute mark-to-market PnL for an open position.\r\n */\r\nexport function computeMarkPnl(\r\n positionSize: bigint,\r\n entryPrice: bigint,\r\n oraclePrice: bigint,\r\n): bigint {\r\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n const diff =\r\n positionSize > 0n\r\n ? oraclePrice - entryPrice\r\n : entryPrice - oraclePrice;\r\n return (diff * absPos) / oraclePrice;\r\n}\r\n\r\n/**\r\n * Compute liquidation price given entry, capital, position and maintenance margin.\r\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\r\n */\r\nexport function computeLiqPrice(\r\n entryPrice: bigint,\r\n capital: bigint,\r\n positionSize: bigint,\r\n maintenanceMarginBps: bigint,\r\n): bigint {\r\n if (positionSize === 0n || entryPrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n // capitalPerUnit scaled by 1e6 for precision\r\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\r\n\r\n if (positionSize > 0n) {\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\r\n const liq = entryPrice - adjusted;\r\n return liq > 0n ? liq : 0n;\r\n } else {\r\n // Guard: short positions liquidate when price rises above liq price.\r\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\r\n // meaning the position can never be liquidated. Return max u64 to signal this.\r\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\r\n return entryPrice + adjusted;\r\n }\r\n}\r\n\r\n/**\r\n * Compute estimated liquidation price BEFORE opening a trade.\r\n * Accounts for trading fees reducing effective capital.\r\n */\r\nexport function computePreTradeLiqPrice(\r\n oracleE6: bigint,\r\n margin: bigint,\r\n posSize: bigint,\r\n maintBps: bigint,\r\n feeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\r\n const absPos = posSize < 0n ? -posSize : posSize;\r\n const signedPos = direction === \"long\" ? absPos : -absPos;\r\n // Fee adjusts the effective entry price, not the capital.\r\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\r\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\r\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\r\n let adjustedEntry: bigint;\r\n if (direction === \"long\") {\r\n adjustedEntry = oracleE6 + feeAdjust;\r\n } else {\r\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\r\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\r\n // feeBps >= 10000, misleading the UI into showing the position is safe.\r\n const shortEntry = oracleE6 - feeAdjust;\r\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\r\n }\r\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\r\n}\r\n\r\n/**\r\n * Compute trading fee from notional value and fee rate in bps.\r\n */\r\nexport function computeTradingFee(\r\n notional: bigint,\r\n tradingFeeBps: bigint,\r\n): bigint {\r\n return (notional * tradingFeeBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Dynamic fee tier configuration.\r\n */\r\nexport interface FeeTierConfig {\r\n /** Base trading fee (Tier 1) in bps */\r\n baseBps: bigint;\r\n /** Tier 2 fee in bps (0 = disabled) */\r\n tier2Bps: bigint;\r\n /** Tier 3 fee in bps (0 = disabled) */\r\n tier3Bps: bigint;\r\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\r\n tier2Threshold: bigint;\r\n /** Notional threshold to enter Tier 3 */\r\n tier3Threshold: bigint;\r\n}\r\n\r\n/**\r\n * Compute the effective fee rate in bps using the tiered fee schedule.\r\n *\r\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\r\n * - notional < tier2Threshold → baseBps (Tier 1)\r\n * - notional < tier3Threshold → tier2Bps (Tier 2)\r\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\r\n *\r\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\r\n */\r\nexport function computeDynamicFeeBps(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n if (config.tier2Threshold === 0n) return config.baseBps;\r\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\r\n if (notional >= config.tier2Threshold) return config.tier2Bps;\r\n return config.baseBps;\r\n}\r\n\r\n/**\r\n * Compute the dynamic trading fee for a given notional and tier config.\r\n *\r\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\r\n * via micro-trades).\r\n */\r\nexport function computeDynamicTradingFee(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n const feeBps = computeDynamicFeeBps(notional, config);\r\n if (notional <= 0n || feeBps <= 0n) return 0n;\r\n return (notional * feeBps + 9999n) / 10000n;\r\n}\r\n\r\n/**\r\n * Fee split configuration.\r\n */\r\nexport interface FeeSplitConfig {\r\n /** LP vault share in bps (0–10_000) */\r\n lpBps: bigint;\r\n /** Protocol treasury share in bps */\r\n protocolBps: bigint;\r\n /** Market creator share in bps */\r\n creatorBps: bigint;\r\n}\r\n\r\n/**\r\n * Compute fee split for a total fee amount.\r\n *\r\n * Returns [lpShare, protocolShare, creatorShare].\r\n * If all split params are 0, 100% goes to LP (legacy behavior).\r\n * Creator gets the rounding remainder to ensure total is preserved.\r\n */\r\nexport function computeFeeSplit(\r\n totalFee: bigint,\r\n config: FeeSplitConfig,\r\n): [bigint, bigint, bigint] {\r\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\r\n return [totalFee, 0n, 0n];\r\n }\r\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\r\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\r\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\r\n }\r\n if (totalBps !== 10000n) {\r\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\r\n }\r\n\r\n const lp = (totalFee * config.lpBps) / 10000n;\r\n const protocol = (totalFee * config.protocolBps) / 10000n;\r\n const creator = totalFee - lp - protocol;\r\n return [lp, protocol, creator];\r\n}\r\n\r\n/**\r\n * Compute PnL as a percentage of capital.\r\n *\r\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\r\n * Number(bigint) silently truncates values above 2^53, which can produce\r\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\r\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\r\n */\r\nexport function computePnlPercent(\r\n pnlTokens: bigint,\r\n capital: bigint,\r\n): number {\r\n if (capital === 0n) return 0;\r\n const scaledPct = (pnlTokens * 10_000n) / capital;\r\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\r\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\r\n // unhandled exceptions from crashing the UI on large positions.\r\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\r\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\r\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\r\n return Number(scaledPct) / 100;\r\n}\r\n\r\n/**\r\n * Estimate entry price including fee impact (slippage approximation).\r\n */\r\nexport function computeEstimatedEntryPrice(\r\n oracleE6: bigint,\r\n tradingFeeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n) return 0n;\r\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\r\n if (direction === \"long\") return oracleE6 + feeImpact;\r\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\r\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\r\n // when fee >= 100%, misleading the UI.\r\n const shortEntry = oracleE6 - feeImpact;\r\n return shortEntry > 0n ? shortEntry : 1n;\r\n}\r\n\r\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\r\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\r\n\r\n/**\r\n * Convert per-slot funding rate (bps) to annualized percentage.\r\n */\r\nexport function computeFundingRateAnnualized(\r\n fundingRateBpsPerSlot: bigint,\r\n): number {\r\n // Clamp rather than throw: extreme funding rates are display-only values;\r\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\r\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\r\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\r\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\r\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\r\n return (bpsPerSlot * slotsPerYear) / 100;\r\n}\r\n\r\n/**\r\n * Compute margin required for a given notional and initial margin bps.\r\n */\r\nexport function computeRequiredMargin(\r\n notional: bigint,\r\n initialMarginBps: bigint,\r\n): bigint {\r\n return (notional * initialMarginBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, as an exact ratio.\r\n *\r\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\r\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\r\n * {@link computeMaxLeverageFloor} instead.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\r\n }\r\n // Use floating-point division so fractional leverage is preserved.\r\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\r\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\r\n return 10000 / Number(initialMarginBps);\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, floored to a whole\r\n * multiplier — the conservative integer form used by risk/sizing math.\r\n *\r\n * Kept separate from {@link computeMaxLeverage} because that one is a display\r\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\r\n * DOWN also keeps client-side caps at or below what the program enforces, so a\r\n * caller can never build a position the chain would reject on leverage.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\r\n }\r\n return 10000n / initialMarginBps;\r\n}\r\n","/**\r\n * Warmup leverage cap utilities.\r\n *\r\n * During the market warmup period, capital is released linearly over\r\n * `warmupPeriodSlots` slots, which constrains the effective leverage\r\n * and maximum position size available to traders.\r\n */\r\n\r\nimport { computeMaxLeverageFloor } from \"./trading.js\";\r\n\r\n// =============================================================================\r\n// Warmup leverage cap utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Compute unlocked capital during the warmup period.\r\n *\r\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\r\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\r\n * warmup period is 0, all capital is considered unlocked.\r\n *\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The amount of capital currently unlocked.\r\n */\r\nexport function computeWarmupUnlockedCapital(\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n // No warmup configured or not started → all capital available\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\r\n if (totalCapital <= 0n) return 0n;\r\n\r\n const elapsed = currentSlot > warmupStartSlot\r\n ? currentSlot - warmupStartSlot\r\n : 0n;\r\n\r\n // Warmup complete\r\n if (elapsed >= warmupPeriodSlots) return totalCapital;\r\n\r\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\r\n return (totalCapital * elapsed) / warmupPeriodSlots;\r\n}\r\n\r\n/**\r\n * Compute the effective maximum leverage during the warmup period.\r\n *\r\n * During warmup, only unlocked capital can be used as margin. The effective\r\n * leverage relative to *total* capital is therefore capped at:\r\n *\r\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\r\n *\r\n * This returns a floored integer value (leverage is always a whole number\r\n * in the UI), with a minimum of 1x if any capital is unlocked.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The effective maximum leverage (integer, ≥ 1).\r\n */\r\nexport function computeWarmupLeverageCap(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): number {\r\n // Integer form: this is risk/sizing math, and the fractional\r\n // computeMaxLeverage() is a display value that cannot be used in BigInt\r\n // arithmetic. Flooring also keeps the client cap at or below the program's.\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n\r\n // No warmup or warmup not started → full leverage\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\r\n if (totalCapital <= 0n) return 1;\r\n\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n\r\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\r\n\r\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\r\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\r\n return Math.max(1, effectiveLev);\r\n}\r\n\r\n/**\r\n * Compute the maximum position size allowed during warmup.\r\n *\r\n * This is the unlocked capital multiplied by the base max leverage.\r\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\r\n * relative to total capital), this gives the absolute notional cap.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns Maximum position size in native units.\r\n */\r\nexport function computeWarmupMaxPositionSize(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n return unlocked * maxLev;\r\n}\r\n","/**\r\n * Input validation utilities for CLI commands.\r\n * Provides descriptive error messages for invalid input.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\n// Constants for numeric limits\r\nconst U16_MAX = 65535;\r\nconst U64_MAX = BigInt(\"18446744073709551615\");\r\nconst I64_MIN = BigInt(\"-9223372036854775808\");\r\nconst I64_MAX = BigInt(\"9223372036854775807\");\r\nconst U128_MAX = (1n << 128n) - 1n;\r\nconst I128_MIN = -(1n << 127n);\r\nconst I128_MAX = (1n << 127n) - 1n;\r\n\r\nexport class ValidationError extends Error {\r\n constructor(\r\n public readonly field: string,\r\n message: string\r\n ) {\r\n super(`Invalid ${field}: ${message}`);\r\n this.name = \"ValidationError\";\r\n }\r\n}\r\n\r\n/**\r\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\r\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\r\n */\r\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\r\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n */\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\r\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n *\r\n * @param value - The string to validate.\r\n * @param field - The field name used in error messages.\r\n * @returns The trimmed, validated decimal string.\r\n */\r\nexport function requireDecimalUIntString(value: string, field: string): string {\r\n const t = value.trim();\r\n if (t === \"\") {\r\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\r\n }\r\n if (!DECIMAL_UINT_RE.test(t)) {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\r\n );\r\n }\r\n return t;\r\n}\r\n\r\n/**\r\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\r\n * (hex, scientific notation, underscores, fractions, leading zeros).\r\n *\r\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\r\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\r\n *\r\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\r\n * @param caller - The calling function name, used in the error message.\r\n * @returns The parsed BigInt value.\r\n * @throws {Error} When `val` does not match the strict decimal integer format.\r\n *\r\n * @example\r\n * safeBigInt(\"123\", \"encU64\") // 123n\r\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\r\n * safeBigInt(\"0x1\", \"encU64\") // throws\r\n * safeBigInt(\"1e5\", \"encU128\") // throws\r\n */\r\nexport function safeBigInt(val: string, caller: string): bigint {\r\n const t = val.trim();\r\n if (!DECIMAL_INT_RE.test(t)) {\r\n throw new Error(\r\n `${caller}: \"${val}\" is not a valid decimal integer ` +\r\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\r\n );\r\n }\r\n return BigInt(t);\r\n}\r\n\r\n/**\r\n * Validate a public key string.\r\n */\r\nexport function validatePublicKey(value: string, field: string): PublicKey {\r\n try {\r\n return new PublicKey(value);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid base58 public key. ` +\r\n `Example: \"11111111111111111111111111111111\"`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate a non-negative integer index (u16 range for accounts).\r\n */\r\nexport function validateIndex(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a non-negative amount (u64 range).\r\n */\r\nexport function validateAmount(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U64_MAX} (u64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a u128 value.\r\n */\r\nexport function validateU128(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U128_MAX} (u128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i64 value.\r\n */\r\nexport function validateI64(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I64_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I64_MIN} (i64 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I64_MAX} (i64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i128 value (trade sizes).\r\n */\r\nexport function validateI128(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I128_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I128_MIN} (i128 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I128_MAX} (i128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a basis points value (0-10000).\r\n */\r\nexport function validateBps(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > 10000n) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= 10000 (100%), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a u64 value.\r\n */\r\nexport function validateU64(value: string, field: string): bigint {\r\n return validateAmount(value, field);\r\n}\r\n\r\n/**\r\n * Validate a u16 value.\r\n */\r\nexport function validateU16(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n","/**\r\n * Smart Price Router — automatic oracle selection for any token.\r\n *\r\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\r\n * ranks them by liquidity/reliability, and returns the best oracle config.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\r\n\r\nexport interface PriceSource {\r\n type: PriceSourceType;\r\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\r\n address: string;\r\n /** DEX id for dex sources */\r\n dexId?: string;\r\n /** Pair label e.g. \"SOL / USDC\" */\r\n pairLabel?: string;\r\n /** USD liquidity depth — higher is better */\r\n liquidity: number;\r\n /** Latest spot price in USD */\r\n price: number;\r\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\r\n confidence: number;\r\n}\r\n\r\nexport interface PriceRouterResult {\r\n mint: string;\r\n bestSource: PriceSource | null;\r\n allSources: PriceSource[];\r\n /** ISO timestamp of resolution */\r\n resolvedAt: string;\r\n}\r\n\r\n/** Options for {@link resolvePrice}. */\r\nexport interface ResolvePriceOptions {\r\n timeoutMs?: number;\r\n}\r\n\r\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\r\n\r\nfunction isRecord(v: unknown): v is Record {\r\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\r\n const already = signals.find((s) => s.aborted);\r\n if (already) {\r\n const c = new AbortController();\r\n c.abort(already.reason);\r\n return c.signal;\r\n }\r\n const active = signals.filter((s) => !s.aborted);\r\n if (active.length === 0) {\r\n const c = new AbortController();\r\n c.abort();\r\n return c.signal;\r\n }\r\n if (active.length === 1) return active[0];\r\n const ctrl = new AbortController();\r\n for (const s of active) {\r\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\r\n }\r\n return ctrl.signal;\r\n}\r\n\r\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\r\n\r\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\r\n if (!isRecord(json)) return [];\r\n const rawPairs = json.pairs;\r\n if (!Array.isArray(rawPairs)) return [];\r\n const sources: PriceSource[] = [];\r\n\r\n for (const pair of rawPairs) {\r\n if (!isRecord(pair)) continue;\r\n if (pair.chainId !== \"solana\") continue;\r\n const dexId = String(pair.dexId || \"\").toLowerCase();\r\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\r\n\r\n let liquidity = 0;\r\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\r\n liquidity = pair.liquidity.usd;\r\n }\r\n if (liquidity < 100) continue;\r\n\r\n let confidence = 30;\r\n if (liquidity > 1_000_000) confidence = 90;\r\n else if (liquidity > 100_000) confidence = 75;\r\n else if (liquidity > 10_000) confidence = 60;\r\n else if (liquidity > 1_000) confidence = 45;\r\n\r\n const priceUsd = pair.priceUsd;\r\n const price =\r\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\r\n ? parseFloat(String(priceUsd)) || 0\r\n : 0;\r\n\r\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\r\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\r\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\r\n // any source without a usable positive price.\r\n if (!(price > 0)) continue;\r\n\r\n let baseSym = \"?\";\r\n let quoteSym = \"?\";\r\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\r\n baseSym = pair.baseToken.symbol;\r\n }\r\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\r\n quoteSym = pair.quoteToken.symbol;\r\n }\r\n\r\n const addr = pair.pairAddress;\r\n sources.push({\r\n type: \"dex\",\r\n address: typeof addr === \"string\" ? addr : \"\",\r\n dexId,\r\n pairLabel: `${baseSym} / ${quoteSym}`,\r\n liquidity,\r\n price,\r\n confidence,\r\n });\r\n }\r\n\r\n sources.sort((a, b) => b.liquidity - a.liquidity);\r\n return sources.slice(0, 10);\r\n}\r\n\r\n/**\r\n * Parse a Jupiter price row.\r\n *\r\n * Handles BOTH shapes:\r\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\r\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\r\n *\r\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\r\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\r\n * cross-validation in this module was silently inert, including the #227/#315\r\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\r\n * mock or a proxy that still speaks v2 keeps working.\r\n */\r\nfunction parseJupiterMintEntry(\r\n json: unknown,\r\n mint: string,\r\n): { price: number; mintSymbol: string; liquidity: number } | null {\r\n if (!isRecord(json)) return null;\r\n\r\n // v3: the mint is a top-level key.\r\n const v3Row = json[mint];\r\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\r\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\r\n if (price <= 0) return null;\r\n const liquidity =\r\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\r\n ? v3Row.liquidity\r\n : 0;\r\n return { price, mintSymbol: \"?\", liquidity };\r\n }\r\n\r\n // v2 (retired): rows live under `data`.\r\n const data = json.data;\r\n if (!isRecord(data)) return null;\r\n const row = data[mint];\r\n if (!isRecord(row)) return null;\r\n const rawPrice = row.price;\r\n if (rawPrice === undefined || rawPrice === null) return null;\r\n const price = parseFloat(String(rawPrice)) || 0;\r\n if (price <= 0) return null;\r\n let mintSymbol = \"?\";\r\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\r\n return { price, mintSymbol, liquidity: 0 };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const PYTH_SOLANA_FEEDS: Record = {\r\n // SOL\r\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\r\n // BTC\r\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\r\n // ETH\r\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\r\n // USDC\r\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\r\n // USDT\r\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\r\n // BONK\r\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\r\n // JTO\r\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\r\n // JUP\r\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\r\n // PYTH\r\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\r\n // RAY\r\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\r\n // ORCA\r\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\r\n // MNGO\r\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\r\n // MSOL\r\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\r\n // JITOSOL\r\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\r\n // WIF\r\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\r\n // RENDER\r\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\r\n // W\r\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\r\n // TNSR\r\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\r\n // HNT\r\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\r\n // MOBILE\r\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\r\n // IOT\r\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\r\n};\r\nObject.freeze(PYTH_SOLANA_FEEDS);\r\n\r\n// Reverse lookup: mint → feed ID\r\nconst MINT_TO_PYTH_FEED = new Map();\r\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\r\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DexScreener fetcher\r\n// ---------------------------------------------------------------------------\r\n\r\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\r\n\r\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\r\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\r\n}\r\n\r\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return [];\r\n const json: unknown = await resp.json();\r\n return parseDexScreenerPairs(json);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth lookup\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction lookupPythSource(mint: string): PriceSource | null {\r\n const entry = MINT_TO_PYTH_FEED.get(mint);\r\n if (!entry) return null;\r\n return {\r\n type: \"pyth\",\r\n address: entry.feedId,\r\n pairLabel: `${entry.symbol} / USD (Pyth)`,\r\n liquidity: Infinity, // Pyth is considered deep liquidity\r\n price: 0, // We don't fetch live price here; caller can enrich\r\n confidence: 95, // Pyth is highest reliability for supported tokens\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Jupiter price fallback\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return null;\r\n const json: unknown = await resp.json();\r\n const row = parseJupiterMintEntry(json, mint);\r\n if (!row) return null;\r\n return {\r\n type: \"jupiter\",\r\n address: mint,\r\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\r\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\r\n // Used below to decide whether Jupiter is a credible enough reference to\r\n // demote a disagreeing pool.\r\n liquidity: row.liquidity,\r\n price: row.price,\r\n confidence: 40, // Fallback — lower confidence\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main resolver\r\n// ---------------------------------------------------------------------------\r\n\r\nexport async function resolvePrice(\r\n mint: string,\r\n signal?: AbortSignal,\r\n options?: ResolvePriceOptions,\r\n): Promise {\r\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\r\n const combinedSignal = signal\r\n ? combineAbortSignals([signal, timeoutSignal])\r\n : timeoutSignal;\r\n\r\n const [dexSources, jupiterSource] = await Promise.all([\r\n fetchDexSources(mint, combinedSignal),\r\n fetchJupiterSource(mint, combinedSignal),\r\n ]);\r\n\r\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\r\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\r\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\r\n // the common case for permissionless markets — had its top DEX source ranked\r\n // purely on self-reported liquidity, with no check against an independent price\r\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\r\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\r\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\r\n // source's confidence to Jupiter's when they diverge beyond the same tightened\r\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\r\n // independent reference purely on liquidity. The source stays in allSources for\r\n // transparency; only its ranking weight is reduced.\r\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\r\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\r\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\r\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\r\n // ahead and bestSource unchanged.\r\n const DISTRUST_CONFIDENCE_MARGIN = 1;\r\n if (jupiterSource && jupiterSource.price > 0) {\r\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\r\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\r\n // itself — enrichment reads dexSources[0].price, which is untouched; only\r\n // ranking weight changes, and Pyth's own confidence (95) still outranks\r\n // everything here.\r\n //\r\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\r\n // Jupiter is an aggregate across venues, so it is normally the better\r\n // reference — but with v2 retired a malformed/empty response used to yield a\r\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\r\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\r\n // ranking alone rather than trust it.\r\n const jupiterIsCredible = jupiterSource.liquidity > 0;\r\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\r\n if (jupiterIsCredible) {\r\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\r\n // returns up to 10 pools and confidence is a step function of liquidity, so a\r\n // second pool in the same tier would otherwise keep its score and win\r\n // bestSource at the divergent price.\r\n for (const dex of dexSources) {\r\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\r\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\r\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\r\n dex.confidence = Math.min(dex.confidence, distrusted);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const pythSource = lookupPythSource(mint);\r\n\r\n const allSources: PriceSource[] = [];\r\n\r\n // Add Pyth if available (highest priority for supported tokens)\r\n if (pythSource) {\r\n // Enrich Pyth price from Jupiter or DEX if available.\r\n // Guard: only push a Pyth source when we have at least one live price\r\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\r\n // at crank time on devnet/mainnet.\r\n const dexPrice = dexSources[0]?.price ?? 0;\r\n const jupPrice = jupiterSource?.price ?? 0;\r\n // #227: cross-validate the enrichment reference so a single manipulable DEX\r\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\r\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\r\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\r\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\r\n //\r\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\r\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\r\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\r\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\r\n let enrichedPrice = 0;\r\n let singleSource = false;\r\n if (dexPrice > 0 && jupPrice > 0) {\r\n const mid = (dexPrice + jupPrice) / 2;\r\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\r\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\r\n enrichedPrice = mid;\r\n } else {\r\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\r\n // DEX and Jupiter are still added below at their own confidence levels.\r\n console.warn(\r\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\r\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\r\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\r\n );\r\n }\r\n } else if (dexPrice > 0 || jupPrice > 0) {\r\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\r\n singleSource = true;\r\n }\r\n if (enrichedPrice > 0) {\r\n pythSource.price = enrichedPrice;\r\n if (singleSource) {\r\n pythSource.confidence = Math.min(pythSource.confidence, 50);\r\n }\r\n allSources.push(pythSource);\r\n }\r\n }\r\n\r\n // Add DEX sources\r\n allSources.push(...dexSources);\r\n\r\n // Add Jupiter as fallback\r\n if (jupiterSource) {\r\n allSources.push(jupiterSource);\r\n }\r\n\r\n // Sort by confidence descending (already accounts for liquidity/reliability)\r\n allSources.sort((a, b) => b.confidence - a.confidence);\r\n\r\n return {\r\n mint,\r\n bestSource: allSources[0] || null,\r\n allSources,\r\n resolvedAt: new Date().toISOString(),\r\n };\r\n}\r\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;A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","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file diff --git a/src/abi/nft.ts b/src/abi/nft.ts index a0a4c38..55bfe29 100644 --- a/src/abi/nft.ts +++ b/src/abi/nft.ts @@ -177,7 +177,8 @@ export const ACCOUNTS_NFT_MINT: AccountMeta[] = [ /** * Account metas for BurnPositionNft (tag 1). 10 accounts. * - * 0. [signer] NFT holder + * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint, + * PositionNft PDA and ExtraAccountMetaList rent) * 1. [writable] PositionNft PDA (closed) * 2. [writable] NFT mint (supply → 0) * 3. [writable] Holder's NFT ATA (closed) @@ -192,13 +193,13 @@ export const ACCOUNTS_NFT_MINT: AccountMeta[] = [ * release the escrow back to the holder, so #4 must be writable and #8/#9 are required. */ export const ACCOUNTS_NFT_BURN: AccountMeta[] = [ - "s", "w", "w", "w", "w", "r", "r", "w", "r", "r", + "sw", "w", "w", "w", "w", "r", "r", "w", "r", "r", ]; /** * Account metas for EmergencyBurn (tag 5). 10 accounts. * - * 0. [signer] NFT holder + * 0. [signer, writable] NFT holder (rent recipient) * 1. [writable] PositionNft PDA (closed) * 2. [writable] NFT mint * 3. [writable] Holder's NFT ATA @@ -210,7 +211,7 @@ export const ACCOUNTS_NFT_BURN: AccountMeta[] = [ * 9. [] Percolator wrapper program (#105 — unwrap CPI target) */ export const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [ - "s", "w", "w", "w", "w", "r", "r", "w", "r", "r", + "sw", "w", "w", "w", "w", "r", "r", "w", "r", "r", ]; /** diff --git a/test/drift-check.test.ts b/test/drift-check.test.ts index b644d49..7c7af48 100644 --- a/test/drift-check.test.ts +++ b/test/drift-check.test.ts @@ -40,6 +40,11 @@ import { encodeNftMint, deriveNftPda, deriveNftMint, + ACCOUNTS_NFT_MINT, + ACCOUNTS_NFT_BURN, + ACCOUNTS_NFT_EMERGENCY_BURN, + ACCOUNTS_NFT_RECONCILE, + buildNftAccountMetas, } from "../src/abi/nft.js"; import { detectSlabLayout, @@ -1000,3 +1005,60 @@ describe("encoding roundtrip — manual decode verifies no endianness or off-by- expect(readU128LE(data, 43)).toBe(IM_REQ); }); }); + +// --------------------------------------------------------------------------- +// percolator-nft account-list ABI +// --------------------------------------------------------------------------- +// +// These templates are the SDK's copy of the account tables in +// percolator-nft/src/instruction.rs, and nothing in this repo consumes them — +// only external callers do, so nothing here exercised them until now. +// +// Assertions round-trip through `buildNftAccountMetas`, because the shorthand +// codes are not what the runtime sees: the builder turns them into +// {isSigner, isWritable} booleans and THAT object goes on the wire. Asserting +// the booleans is what makes a wrong flag visible — and is what would have +// caught the historical wrong-builder bug documented above +// `buildNftAccountMetas`, where every flag silently became `undefined`. + +describe("percolator-nft account-list ABI", () => { + const flagsOf = (spec: readonly ("s" | "w" | "sw" | "r")[]) => + buildNftAccountMetas( + spec, + Array.from({ length: spec.length }, () => PublicKey.unique()), + ).map((m) => [m.isSigner, m.isWritable] as const); + + it("MintPositionNft: 12 accounts; payer and the fresh mint keypair both sign", () => { + const f = flagsOf(ACCOUNTS_NFT_MINT); + expect(f.length).toBe(12); + expect(f[0]).toEqual([true, true]); // payer / position owner + expect(f[2]).toEqual([true, true]); // fresh mint keypair + }); + + it("BurnPositionNft: the holder is the rent recipient, so signer AND writable", () => { + // percolator-nft `require_writable_rent_recipient(holder)` (processor.rs:825) + // rejects a read-only holder with InvalidAccountData, and the program's own + // ABI table documents account 0 as `[signer, writable]` (instruction.rs:44). + const f = flagsOf(ACCOUNTS_NFT_BURN); + expect(f.length).toBe(10); + expect(f[0]).toEqual([true, true]); + expect(f[7]).toEqual([false, true]); // extra_metas, closed (#102) + }); + + it("EmergencyBurn: same holder requirement (processor.rs:1000)", () => { + const f = flagsOf(ACCOUNTS_NFT_EMERGENCY_BURN); + expect(f.length).toBe(10); + expect(f[0]).toEqual([true, true]); + expect(f[7]).toEqual([false, true]); + }); + + it("ReconcileBurnedNft is permissionless — no account may be a signer", () => { + expect(flagsOf(ACCOUNTS_NFT_RECONCILE).every(([signer]) => !signer)).toBe(true); + }); + + it("buildNftAccountMetas rejects a key-count mismatch rather than truncating", () => { + expect(() => + buildNftAccountMetas(ACCOUNTS_NFT_RECONCILE, [PublicKey.unique()]), + ).toThrow(/account count mismatch/); + }); +}); From 780179a1b18cda18c807e9c17a42bfa83a4cedb1 Mon Sep 17 00:00:00 2001 From: 0X-SquidSol Date: Mon, 31 Aug 2026 09:56:18 -0400 Subject: [PATCH 2/3] feat(nft)!: ACCOUNTS_NFT_RECONCILE 7 -> 9 accounts (percolator-nft#182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors dcccrypto/percolator-nft#183, which gives ReconcileBurnedNft the rent reclamation the two burn paths have had since #102: extra_metas (writable) at index 7 and the Token-2022 program at index 8. The NFT mint at index 1 becomes writable because the program now closes it. Reconcile previously abandoned the NFT mint and the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable, because it closes the PositionNft PDA and every path that could later reclaim those two requires it to still be live. Ahead of chain, but forward-compatible, so this can ship before the program rather than after it. The deployed handlers pull seven accounts off an iterator, have no `accounts.len()` check anywhere in processor.rs, and never check `nft_mint.is_writable` in the reconcile path — so the two extra metas are unread and a nine-account call behaves identically on the deployed programs. The reverse order is the one that breaks: deploying #183 while the SDK still says seven fails every Reconcile with NotEnoughAccountKeys. Marked `!` because `buildNftAccountMetas` hard-throws on a count mismatch, so a caller passing seven keys now gets `account count mismatch: expected 9, got 7` at the call site. That is the intended failure — loud and local. Also corrects two module-header defects found alongside: the instruction list omitted tags 6 and 7, and the PositionNft PDA seed was documented as `asset_index_u16_LE`, the pre-#108 scheme #108 existed to remove. The code was always correct. Refs dcccrypto/percolator-nft#182 Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 17 +++++++++++++++++ dist/abi/nft.d.ts | 31 ++++++++++++++++++++++++++----- dist/index.js | 6 ++++-- dist/index.js.map | 2 +- src/abi/nft.ts | 33 +++++++++++++++++++++++++++------ test/drift-check.test.ts | 12 ++++++++++-- 6 files changed, 85 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b48e815..a62ab6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,23 @@ this collects that change and everything since. - **`fix(stake)!`** (`3704dfd`): an ambiguous network now throws instead of defaulting to mainnet. +### Changed + +- **`ACCOUNTS_NFT_RECONCILE` 7 → 9 accounts**, mirroring + dcccrypto/percolator-nft#183: `extra_metas` (writable) at index 7 and the + Token-2022 program at index 8, with the NFT mint at index 1 becoming writable + because the program now closes it. Recovers 7,676,880 lamports per NFT that + Reconcile previously abandoned unrecoverably. + + **Ahead of chain, but forward-compatible.** The currently deployed programs + (`FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS` mainnet, + `CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3` devnet) pull seven accounts off + an iterator, never check `accounts.len()`, and never check + `nft_mint.is_writable` — so a nine-account call behaves identically on them. + The rent reclamation this documents only takes effect once percolator-nft#183 + is deployed. Callers building the instruction by hand must pass nine keys: + `buildNftAccountMetas` throws `account count mismatch: expected 9, got 7`. + ### Added - Account-list drift tests (`test/drift-check.test.ts`) that round-trip each diff --git a/dist/abi/nft.d.ts b/dist/abi/nft.d.ts index 73604d8..4985b99 100644 --- a/dist/abi/nft.d.ts +++ b/dist/abi/nft.d.ts @@ -9,10 +9,16 @@ * - GetPositionValue (tag 3) * - ExecuteTransferHook (tag 4, SPL interface — not called directly) * - EmergencyBurn (tag 5) + * - RepairExtraMetas (tag 6) + * - ReconcileBurnedNft (tag 7) * * PDA seeds (matches percolator-nft/src/state_v16.rs): - * PositionNft state : ["position_nft", portfolio_account, asset_index_u16_LE] + * PositionNft state : ["position_nft", portfolio_account, market_id_u64_LE] * Mint authority : ["mint_authority"] + * + * NOTE: the PositionNft seed is keyed on `market_id`, NOT `asset_index` — see + * #108 and `deriveNftPda` below. This header claimed `asset_index_u16_LE` until + * 2026-08-31; the code was always correct. */ import { PublicKey } from "@solana/web3.js"; /** @@ -135,15 +141,30 @@ export declare const ACCOUNTS_NFT_BURN: AccountMeta[]; */ export declare const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[]; /** - * Account metas for ReconcileBurnedNft (tag 7, #138). 7 accounts. Permissionless. + * Account metas for ReconcileBurnedNft (tag 7, #138). 9 accounts. Permissionless. * * 0. [writable] PositionNft PDA (closed) - * 1. [] NFT mint (Token-2022 — supply must be 0) + * 1. [writable] NFT mint (Token-2022 — supply must be 0; closed, #182) * 2. [writable] Portfolio account (escrow released to the last holder) - * 3. [] Mint authority PDA (unwrap CPI signer) + * 3. [] Mint authority PDA (unwrap + mint-close CPI signer) * 4. [] Per-market NftRegistry PDA * 5. [] Percolator wrapper program (unwrap CPI target) - * 6. [writable] Recorded last-holder wallet (escrow + PDA-rent recipient) + * 6. [writable] Recorded last-holder wallet (escrow + all rent recipient) + * 7. [writable] ExtraAccountMetaList PDA (closed, #182) + * 8. [] Token-2022 program (mint-close CPI target, #182) + * + * dcccrypto/percolator-nft#182: Reconcile previously abandoned the NFT mint and + * the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable, + * because it closes the PositionNft PDA and every path that could later reclaim + * those two requires it to still be live. Accounts 7 and 8 are REQUIRED rather + * than optional: Reconcile is permissionless, irreversible and runs at most + * once, so an opt-in could be defeated permanently by whoever called first. + * + * Forward-compatible with the currently deployed programs: their handler pulls + * seven accounts off an iterator and never checks `accounts.len()`, so the two + * extra metas are simply unread, and it never checks `nft_mint.is_writable`. + * A nine-account call therefore behaves identically on both, which is why this + * can ship ahead of the program change rather than behind it. */ export declare const ACCOUNTS_NFT_RECONCILE: AccountMeta[]; /** diff --git a/dist/index.js b/dist/index.js index 332090e..f261d67 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2786,12 +2786,14 @@ var ACCOUNTS_NFT_EMERGENCY_BURN = [ ]; var ACCOUNTS_NFT_RECONCILE = [ "w", - "r", + "w", "w", "r", "r", "r", - "w" + "w", + "w", + "r" ]; var TEXT = new TextEncoder(); function u16Buf(value, label) { diff --git a/dist/index.js.map b/dist/index.js.map index ed3a64b..e7bb39f 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst U8_MAX = 0xFF;\r\nconst U16_MAX = 0xFFFF;\r\nconst U32_MAX = 0xFFFFFFFF;\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\r\n if (typeof val === \"bigint\") return val;\r\n if (typeof val !== \"string\") {\r\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\r\n }\r\n if (!DECIMAL_INT_RE.test(val)) {\r\n throw new Error(`${fnName}: value must be a decimal integer string`);\r\n }\r\n return BigInt(val);\r\n}\r\n\r\n/**\r\n * Encode u8 (1 byte)\r\n */\r\nexport function encU8(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\r\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\r\n }\r\n return new Uint8Array([val]);\r\n}\r\n\r\n/**\r\n * Encode u16 little-endian (2 bytes)\r\n */\r\nexport function encU16(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\r\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u32 little-endian (4 bytes)\r\n */\r\nexport function encU32(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\r\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\r\n }\r\n const buf = new Uint8Array(4);\r\n new DataView(buf.buffer).setUint32(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u64 little-endian (8 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU64\");\r\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\r\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i64 little-endian (8 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI64\");\r\n const min = -(1n << 63n);\r\n const max = (1n << 63n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigInt64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u128 little-endian (16 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU128\");\r\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\r\n const max = (1n << 128n) - 1n;\r\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = n & 0xffff_ffff_ffff_ffffn;\r\n const hi = n >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i128 little-endian (16 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI128\");\r\n const min = -(1n << 127n);\r\n const max = (1n << 127n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\r\n\r\n // Convert to unsigned representation (two's complement)\r\n let unsigned = n;\r\n if (n < 0n) {\r\n unsigned = (1n << 128n) + n;\r\n }\r\n\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\r\n const hi = unsigned >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\r\n *\r\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\r\n * objects are validated before their bytes are returned so JavaScript callers\r\n * cannot provide malformed `toBytes()` output.\r\n *\r\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\r\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\r\n */\r\nexport function encPubkey(val: PublicKey | string): Uint8Array {\r\n try {\r\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\r\n\r\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\r\n throw new Error(\"value must be a PublicKey or base58 string\");\r\n }\r\n\r\n const bytes = pk.toBytes();\r\n\r\n if (!(bytes instanceof Uint8Array)) {\r\n throw new Error(\"toBytes() must return a Uint8Array\");\r\n }\r\n\r\n if (bytes.length !== 32) {\r\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\r\n }\r\n\r\n return bytes;\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\r\n }\r\n}\r\n\r\n/**\r\n * Encode a boolean as u8 (0 = false, 1 = true)\r\n */\r\nexport function encBool(val: boolean): Uint8Array {\r\n return encU8(val ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\r\n */\r\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\r\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\r\n const result = new Uint8Array(totalLen);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n encU8,\r\n encU16,\r\n encU32,\r\n encU64,\r\n encI64,\r\n encU128,\r\n encI128,\r\n encPubkey,\r\n concatBytes,\r\n} from \"./encode.js\";\r\n\r\n/**\r\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\r\n * v17 converged wrapper (percolator-prog @v17-convergence, source\r\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\r\n * InvalidInstructionData.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\r\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\r\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\r\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\r\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\r\n * all callers — the program hard-rejects nonzero.\r\n * - Domain fields: u8→u16 everywhere.\r\n */\r\nexport const IX_TAG = {\r\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\r\n InitMarket: 0,\r\n InitPortfolio: 1,\r\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\r\n InitUser: 1,\r\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\r\n InitLP: 2,\r\n Deposit: 3,\r\n /** @alias DepositCollateral @since v12.x alias */\r\n DepositCollateral: 3,\r\n Withdraw: 4,\r\n /** @alias WithdrawCollateral @since v12.x alias */\r\n WithdrawCollateral: 4,\r\n /**\r\n * PermissionlessCrank (tag 5).\r\n *\r\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\r\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\r\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\r\n * construct the payload manually and omit this field — that produces a\r\n * malformed instruction (missing bytes).\r\n */\r\n PermissionlessCrank: 5,\r\n /** @alias KeeperCrank @since v12.x alias */\r\n KeeperCrank: 5,\r\n TradeNoCpi: 6,\r\n LiquidateAtOracle: 7,\r\n ClosePortfolio: 8,\r\n /** @alias CloseAccount @since v12.x alias */\r\n CloseAccount: 8,\r\n TopUpInsurance: 9,\r\n TradeCpi: 10,\r\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\r\n SetRiskThreshold: 11,\r\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\r\n UpdateAdmin: 12,\r\n CloseSlab: 13,\r\n ResolveMarket: 19,\r\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\r\n TopUpBackingBucket: 24,\r\n ConvertReleasedPnl: 28,\r\n CloseResolved: 30,\r\n /**\r\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\r\n *\r\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\r\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\r\n * rotation uses tag 65 (UpdateAssetAuthority).\r\n */\r\n UpdateAuthority: 32,\r\n ConfigureHybridOracle: 34,\r\n ConfigureEwmaMark: 35,\r\n PushEwmaMark: 36,\r\n UpdateLiquidationFeePolicy: 37,\r\n ConfigurePermissionlessResolve: 38,\r\n ResolveStalePermissionless: 39,\r\n UpdateAssetLifecycle: 40,\r\n WithdrawInsurance: 41,\r\n CureAndCancelClose: 42,\r\n ForfeitRecoveryLeg: 43,\r\n RebalanceReduce: 44,\r\n FinalizeResetSide: 45,\r\n ClaimResolvedPayoutTopup: 46,\r\n RefineResolvedUnreceiptedBound: 47,\r\n SyncMaintenanceFee: 48,\r\n UpdateMaintenanceFeePolicy: 49,\r\n WithdrawBackingBucket: 50,\r\n UpdateBackingFeePolicy: 51,\r\n WithdrawBackingBucketEarnings: 52,\r\n SyncBackingDomainLedger: 53,\r\n SyncInsuranceLedger: 54,\r\n UpdateTradeFeePolicy: 55,\r\n TopUpInsuranceDomain: 56,\r\n /**\r\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\r\n *\r\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\r\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\r\n */\r\n WithdrawInsuranceAsset: 57,\r\n UpdateFeeRedirectPolicy: 58,\r\n UpdateMarketInitFeePolicy: 59,\r\n UpdateBaseUnitMints: 60,\r\n SwapSecondaryForPrimary: 61,\r\n ConfigureAuthMark: 62,\r\n PushAuthMark: 63,\r\n ForceCloseAbandonedAsset: 64,\r\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\r\n /**\r\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\r\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\r\n * 1 = INSURANCE — insurance_authority\r\n * 2 = INSURANCE_OPERATOR — insurance_operator\r\n * 3 = BACKING_BUCKET — backing_bucket_authority\r\n * 4 = ORACLE — oracle_authority\r\n *\r\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\r\n * See stake-program docs.\r\n */\r\n UpdateAssetAuthority: 65,\r\n /**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\r\n */\r\n BatchTradeNoCpi: 66,\r\n /**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\r\n */\r\n BatchTradeCpi: 67,\r\n /**\r\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n */\r\n SetMatcherConfig: 68,\r\n /**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\r\n */\r\n RestartAssetOracle: 69,\r\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\r\n /**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n */\r\n TransferPortfolioOwnership: 72,\r\n /**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n */\r\n SetNftProgramId: 73,\r\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\r\n /**\r\n * CreateLpVault (tag 74).\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\r\n */\r\n CreateLpVault: 74,\r\n /**\r\n * DepositToLpVault (tag 75).\r\n * Wire: tag(1) + amount(u128) = 17 bytes.\r\n */\r\n DepositToLpVault: 75,\r\n /**\r\n * RequestRedeemLpShares (tag 76).\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n */\r\n RequestRedeemLpShares: 76,\r\n /**\r\n * ExecuteRedemption (tag 77).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n ExecuteRedemption: 77,\r\n /**\r\n * LpVaultCrankFees (tag 78).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n LpVaultCrankFees: 78,\r\n /**\r\n * SetLpVaultPaused (tag 79).\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n */\r\n SetLpVaultPaused: 79,\r\n /**\r\n * CloseLpVault (tag 80).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n CloseLpVault: 80,\r\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\r\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\r\n LpVaultDeposit: 75,\r\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\r\n LpVaultWithdraw: 76,\r\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\r\n /** @deprecated v12.x tag 14. Removed in v17. */\r\n UpdateConfig: 14,\r\n /** @deprecated v12.x tag 15. Removed in v17. */\r\n SetMaintenanceFee: 15,\r\n /** @deprecated v12.x tag 16. Removed in v17. */\r\n SetOraclePriceCap: 16,\r\n /** @deprecated v12.x tag 17. Removed in v17. */\r\n AdminForceClose: 17,\r\n /** @deprecated v12.x tag 18. Removed in v17. */\r\n UpdateRiskParams: 18,\r\n /** @deprecated v12.x tag 20. Removed in v17. */\r\n SetPythOracle: 20,\r\n /** @deprecated v12.x tag 21. Removed in v17. */\r\n RenounceAdmin: 21,\r\n /** @deprecated v12.x tag 22. Removed in v17. */\r\n SetInsuranceWithdrawPolicy: 22,\r\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\r\n WithdrawInsuranceLimited: 23,\r\n /** @deprecated v12.x tag 25. Removed in v17. */\r\n FundMarketInsurance: 25,\r\n /** @deprecated v12.x tag 26. Removed in v17. */\r\n SetInsuranceIsolation: 26,\r\n /** @deprecated v12.x tag 27. Removed in v17. */\r\n DepositFeeCredits: 27,\r\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\r\n ResolvePermissionless: 29,\r\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\r\n ForceCloseResolved: 30,\r\n /** @deprecated v12.x tag 33. Removed in v17. */\r\n UpdateInsurancePolicy: 33,\r\n /** @deprecated v12.x tag 36. Removed in v12.17. */\r\n UnresolveMarket: 36,\r\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\r\n ChallengeSettlement: 43,\r\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\r\n ResolveDispute: 44,\r\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\r\n DepositLpCollateral: 45,\r\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\r\n WithdrawLpCollateral: 46,\r\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\r\n SetOffsetPair: 54,\r\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\r\n AttestCrossMargin: 55,\r\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\r\n PauseMarket: 56,\r\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\r\n UnpauseMarket: 58,\r\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\r\n MintPositionNft: 64,\r\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\r\n TransferPositionOwnership: 65,\r\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\r\n BurnPositionNft: 66,\r\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\r\n SetPendingSettlement: 67,\r\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\r\n ClearPendingSettlement: 68,\r\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\r\n TransferOwnershipCpi: 69,\r\n /** @deprecated v12.x tag 70. Not in v17. */\r\n SetWalletCap: 70,\r\n /** @deprecated v12.x tag 71. Not in v17. */\r\n SetOiImbalanceHardBlock: 71,\r\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\r\n RescueOrphanVault: 72,\r\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\r\n CloseOrphanSlab: 73,\r\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\r\n SetDexPool: 74,\r\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\r\n InitMatcherCtxV12: 75,\r\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\r\n SetMaxPnlCap: 78,\r\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\r\n SetOiCapMultiplier: 79,\r\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\r\n SetDisputeParams: 80,\r\n /** @deprecated v12.x tag 81. Not in v17. */\r\n SetLpCollateralParams: 81,\r\n /** @deprecated v12.x tag 82. Not in v17. */\r\n AcceptAdmin: 82,\r\n /**\r\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\r\n *\r\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\r\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\r\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\r\n * skew_spread_mult_bps(u16) = 70 bytes total.\r\n *\r\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\r\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\r\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\r\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\r\n *\r\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\r\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\r\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\r\n * free tag 83 for this instruction rather than the reverse.\r\n */\r\n InitMatcherCtx: 83,\r\n /**\r\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\r\n *\r\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\r\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\r\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\r\n *\r\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\r\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\r\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\r\n */\r\n WithdrawProtocolFee: 84,\r\n /**\r\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\r\n * cfg.protocol_fee_authority.\r\n *\r\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\r\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\r\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\r\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\r\n *\r\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\r\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\r\n */\r\n SetProtocolFeeAuthority: 85,\r\n /**\r\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\r\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\r\n *\r\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\r\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\r\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\r\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\r\n * FeeSplitFloorViolation.\r\n *\r\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\r\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\r\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\r\n * `encodeStakeAdminUpdateFeeSplit`.\r\n */\r\n UpdateFeeSplit: 86,\r\n /**\r\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\r\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\r\n * vault and into the bound stake pool's vault, where percolator-stake's\r\n * AccrueFees measures it as surplus and distributes it to stakers.\r\n *\r\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\r\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\r\n *\r\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\r\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\r\n * id. The only thing a caller decides is *when* the push happens.\r\n *\r\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\r\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\r\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\r\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\r\n * ResolveMarket, not after.\r\n */\r\n WithdrawInsuranceReserveToStake: 87,\r\n /**\r\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\r\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\r\n * argument with no setter anywhere in the dispatch table and was therefore\r\n * frozen for the life of the market.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\r\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\r\n * (v16_program.rs tag-88 arm), matching both the storage type\r\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\r\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\r\n * rejects the whole instruction with InvalidInstructionData.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\r\n */\r\n UpdateMaintenanceFeePerSlot: 88,\r\n /**\r\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\r\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\r\n * bucket to `Expired`/`Impaired` so settlement against that domain can\r\n * proceed again.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\r\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\r\n *\r\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\r\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\r\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\r\n * horizon defers the lapse, it does not avoid it. See\r\n * {@link encodeExpireBackingBucket} for the full keeper contract.\r\n */\r\n ExpireBackingBucket: 89,\r\n /**\r\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\r\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\r\n * Pays the market creator's accrued trade-fee share out of the vault and\r\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\r\n * EXACTLY `amount`.\r\n *\r\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\r\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\r\n * tag 84).\r\n *\r\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\r\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\r\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\r\n * config and pass that to drain it.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\r\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\r\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\r\n * alone, so this deliberate divergence is what lets the creator still claim\r\n * after staking (and stops the pool PDA claiming creator revenue).\r\n *\r\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\r\n * saturated — there is no partial fill. Nothing is debited on failure.\r\n */\r\n WithdrawCreatorFee: 90,\r\n /**\r\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\r\n * between the two domains of the LP vault's asset, carrying ledger principal\r\n * in lockstep. No tokens move: `header.vault` is untouched.\r\n *\r\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\r\n * gains from the OPPOSITE domain, so without this the pot the house actually\r\n * needs can never be refilled (spec.md L410 requires refill be source-domain\r\n * local).\r\n */\r\n RebalanceLpVaultBacking: 91,\r\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\r\n ReclaimEmptyAccount: 85,\r\n /** @deprecated v12.x tag 86. Not in v17. */\r\n SettleAccount: 86,\r\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\r\n UpdateMarkPrice: 90,\r\n /** @deprecated v12.x tag 91. Not in v17. */\r\n AuditCrank: 91,\r\n /** @deprecated v12.x tag 92. Not in v17. */\r\n AdvanceOraclePhase: 92,\r\n /** @deprecated v12.x tag 93. Not in v17. */\r\n SlashCreationDeposit: 93,\r\n /** @deprecated v12.x tag 94. Not in v17. */\r\n InitSharedVault: 94,\r\n /** @deprecated v12.x tag 95. Not in v17. */\r\n AllocateMarket: 95,\r\n /** @deprecated v12.x tag 96. Not in v17. */\r\n QueueWithdrawalSV: 96,\r\n /** @deprecated v12.x tag 97. Not in v17. */\r\n ClaimEpochWithdrawal: 97,\r\n /** @deprecated v12.x tag 98. Not in v17. */\r\n AdvanceEpoch: 98,\r\n /** @deprecated v12.x tag 99. Not in v17. */\r\n ReclaimSlabRent: 99,\r\n /** @deprecated v12.x tag 100. Not in v17. */\r\n CloseStaleSlabs: 100,\r\n /** @deprecated v12.x tag 101. Not in v17. */\r\n ExecuteAdl: 101,\r\n /** @deprecated v12.x tag 102. Not in v17. */\r\n QueueWithdrawal: 102,\r\n /** @deprecated v12.x tag 103. Not in v17. */\r\n ClaimQueuedWithdrawal: 103,\r\n /** @deprecated v12.x tag 104. Not in v17. */\r\n CancelQueuedWithdrawal: 104,\r\n /** @deprecated v12.x tag 105. Not in v17. */\r\n TradeCpiV: 105,\r\n} as const;\r\nObject.freeze(IX_TAG);\r\n\r\n/**\r\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\r\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\r\n *\r\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\r\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\r\n */\r\nexport const EXPECTED_SLAB_VERSION = 16;\r\n\r\n/**\r\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\r\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\r\n throw new Error(\r\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\r\n );\r\n}\r\n\r\n/**\r\n * InitMarket instruction data — v17 wire format.\r\n *\r\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\r\n *\r\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\r\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\r\n * provided as account metas or configured separately via ConfigureHybridOracle /\r\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\r\n *\r\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\r\n * is completely rejected by the v17 program — the first field read is now\r\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\r\n * a u16 portfolio count, producing invalid config or rejection at every call.\r\n *\r\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\r\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\r\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\r\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\r\n */\r\n/**\r\n * Optional 66-byte extended tail for InitMarket (S-4).\r\n *\r\n * When present and any field is non-zero the encoder appends a 66-byte block\r\n * in the exact order that the program reads it (percolator.rs:1516-1545):\r\n * insurance_withdraw_max_bps u16 (2 bytes)\r\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\r\n * permissionless_resolve_stale_slots u64 (8 bytes)\r\n * funding_horizon_slots u64 (8 bytes)\r\n * funding_k_bps u64 (8 bytes)\r\n * funding_max_premium_bps i64 (8 bytes)\r\n * funding_max_bps_per_slot i64 (8 bytes)\r\n * mark_min_fee u64 (8 bytes)\r\n * force_close_delay_slots u64 (8 bytes)\r\n * total = 2 + 8*8 = 66 bytes\r\n *\r\n * When absent (or all fields are zero) the encoder omits the tail and the\r\n * program treats all extended fields as their default zero values. This\r\n * preserves full backward compatibility with existing 344-byte payloads.\r\n */\r\nexport interface InitMarketExtendedTail {\r\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\r\n insuranceWithdrawMaxBps: number;\r\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\r\n insuranceWithdrawCooldownSlots: bigint | string;\r\n /** Slots after which an unresolved market may be permissionlessly resolved. */\r\n permissionlessResolveStaleSlots: bigint | string;\r\n /** Funding rate horizon in slots (custom_funding_k denominator). */\r\n fundingHorizonSlots: bigint | string;\r\n /** Funding rate K parameter in bps (0 = disabled). */\r\n fundingKBps: bigint | string;\r\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\r\n fundingMaxPremiumBps: bigint | string;\r\n /** Maximum funding rate change per slot in bps (i64). */\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\r\n markMinFee: bigint | string;\r\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\r\n forceCloseDelaySlots: bigint | string;\r\n /**\r\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\r\n *\r\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\r\n * the wrapper applies its deployment default\r\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\r\n * emits a 74-byte v2 tail with this value appended after\r\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\r\n * `InvalidConfigParam`; the engine then re-validates the solvency\r\n * envelope at `init_in_place`.\r\n *\r\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\r\n */\r\n maxPriceMoveBpsPerSlot?: bigint | string;\r\n}\r\n\r\nexport interface InitMarketArgs {\r\n admin: PublicKey | string;\r\n collateralMint: PublicKey | string;\r\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\r\n maxStalenessSecs: bigint | string;\r\n confFilterBps: number;\r\n invert: number;\r\n unitScale: number;\r\n initialMarkPriceE6: bigint | string;\r\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\r\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n maxInsuranceFloor?: bigint | string;\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n minOraclePriceCap?: bigint | string;\r\n // RiskParams block (16 fields, read by read_risk_params on-chain)\r\n /**\r\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\r\n * when hMin/hMax are not provided.\r\n */\r\n warmupPeriodSlots?: bigint | string;\r\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMin?: bigint | string;\r\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMax?: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n initialMarginBps: bigint | string;\r\n tradingFeeBps: bigint | string;\r\n maxAccounts: bigint | string;\r\n newAccountFee: bigint | string;\r\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\r\n maintenanceFeePerSlot: bigint | string;\r\n maxCrankStalenessSlots: bigint | string;\r\n liquidationFeeBps: bigint | string;\r\n liquidationFeeCap: bigint | string;\r\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\r\n minLiquidationAbs: bigint | string;\r\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\r\n minInitialDeposit?: bigint | string;\r\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\r\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\r\n /**\r\n * Optional 66-byte extended tail (S-4).\r\n * When present and any field is non-zero, appended after the 344-byte base payload.\r\n * When absent (or all zeros), the base 344-byte payload is sent and the program\r\n * uses default zero values for all extended fields.\r\n * @see InitMarketExtendedTail\r\n */\r\n extendedTail?: InitMarketExtendedTail;\r\n}\r\n\r\n/**\r\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\r\n *\r\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\r\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\r\n * Retained as a utility for off-chain feed ID validation.\r\n */\r\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function encodeFeedId(feedId: string): Uint8Array {\r\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\r\n if (!HEX_RE.test(hex)) {\r\n throw new Error(\r\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\r\n );\r\n }\r\n const bytes = new Uint8Array(32);\r\n for (let i = 0; i < 64; i += 2) {\r\n const byte = parseInt(hex.substring(i, i + 2), 16);\r\n if (Number.isNaN(byte)) {\r\n throw new Error(\r\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\r\n );\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\r\n * (10_000_000_000_000_000 — effectively unlimited).\r\n *\r\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\r\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\r\n * engine returns `RecoveryRequired` and refuses further liquidation until\r\n * the insurance fund covers the residual. Production markets MUST use this\r\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\r\n * limit is intended AND the insurance fund is sized accordingly.\r\n *\r\n * @example\r\n * ```ts\r\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\r\n * const data = encodeInitMarket({\r\n * ...otherParams,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\r\n\r\n// v17 wire layout (v16_program.rs decode arm at tag 0):\r\n// tag(1) +\r\n// max_portfolio_assets(u16=2) +\r\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\r\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\r\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\r\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\r\n// liquidation_fee_bps(u64=8) +\r\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\r\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\r\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\r\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\r\n// max_bankrupt_close_lifetime_slots(u64=8) +\r\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\r\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\r\nconst INIT_MARKET_V17_LEN = 219;\r\n\r\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\r\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\r\n// with no optional tail — all parameters are required fields in the main body.\r\n\r\n/**\r\n * InitMarket v17 argument interface.\r\n *\r\n * admin and collateralMint are passed as account metas (accounts[0] and\r\n * accounts[2] respectively), NOT in instruction data.\r\n *\r\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\r\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\r\n * after the market is created.\r\n *\r\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\r\n * max_portfolio_assets, h_min, h_max, initial_price,\r\n * min_nonzero_mm_req, min_nonzero_im_req,\r\n * maintenance_margin_bps, initial_margin_bps,\r\n * max_trading_fee_bps, trade_fee_base_bps,\r\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\r\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\r\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\r\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\r\n * max_bankrupt_close_lifetime_slots,\r\n * public_b_chunk_atoms, maintenance_fee_per_slot.\r\n */\r\nexport interface InitMarketV17Args {\r\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\r\n maxPortfolioAssets: number;\r\n /** Minimum funding horizon in slots (u64). */\r\n hMin: bigint | string;\r\n /** Maximum funding horizon in slots (u64). */\r\n hMax: bigint | string;\r\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\r\n initialPrice: bigint | string;\r\n /** Minimum non-zero maintenance margin requirement (u128). */\r\n minNonzeroMmReq: bigint | string;\r\n /** Minimum non-zero initial margin requirement (u128). */\r\n minNonzeroImReq: bigint | string;\r\n /** Maintenance margin ratio in bps (u64). */\r\n maintenanceMarginBps: bigint | string;\r\n /** Initial margin ratio in bps (u64). */\r\n initialMarginBps: bigint | string;\r\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\r\n maxTradingFeeBps: bigint | string;\r\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\r\n tradeFeeBaseBps: bigint | string;\r\n /** Liquidation fee in bps (u64). */\r\n liquidationFeeBps: bigint | string;\r\n /** Liquidation fee cap in absolute units (u128). */\r\n liquidationFeeCap: bigint | string;\r\n /** Minimum liquidation size in absolute units (u128). */\r\n minLiquidationAbs: bigint | string;\r\n /** Maximum price movement per slot in bps (u64). */\r\n maxPriceMoveBpsPerSlot: bigint | string;\r\n /** Maximum accrual delta-time in slots (u64). */\r\n maxAccrualDtSlots: bigint | string;\r\n /** Maximum absolute funding rate in e9 per slot (u64). */\r\n maxAbsFundingE9PerSlot: bigint | string;\r\n /** Minimum funding lifetime in slots (u64). */\r\n minFundingLifetimeSlots: bigint | string;\r\n /** Maximum account-B settlement chunks per crank (u64). */\r\n maxAccountBSettlementChunks: bigint | string;\r\n /** Maximum bankrupt-close chunks per crank (u64). */\r\n maxBankruptCloseChunks: bigint | string;\r\n /** Maximum bankrupt-close lifetime in slots (u64). */\r\n maxBankruptCloseLifetimeSlots: bigint | string;\r\n /**\r\n * Public-B chunk size in atoms (u128).\r\n *\r\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\r\n * the engine returns `RecoveryRequired` when the bankrupt position's\r\n * liability exceeds this limit and insurance is insufficient to cover it.\r\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\r\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\r\n * and a funded insurance pool.\r\n */\r\n publicBChunkAtoms: bigint | string;\r\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\n/**\r\n * Encode InitMarket instruction data (v17 wire format).\r\n *\r\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\r\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\r\n *\r\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\r\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\r\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\r\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\r\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\r\n *\r\n * @param args v17 market parameters (InitMarketV17Args)\r\n * @returns 227-byte Uint8Array\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMarket({\r\n * maxPortfolioAssets: 256,\r\n * hMin: 1000n,\r\n * hMax: 100000n,\r\n * initialPrice: 50_000_000_000n,\r\n * minNonzeroMmReq: 1_000_000n,\r\n * minNonzeroImReq: 2_000_000n,\r\n * maintenanceMarginBps: 500n,\r\n * initialMarginBps: 1000n,\r\n * maxTradingFeeBps: 100n,\r\n * tradeFeeBaseBps: 30n,\r\n * liquidationFeeBps: 100n,\r\n * liquidationFeeCap: 10_000_000n,\r\n * minLiquidationAbs: 1_000_000n,\r\n * maxPriceMoveBpsPerSlot: 4n,\r\n * maxAccrualDtSlots: 600n,\r\n * maxAbsFundingE9PerSlot: 1000n,\r\n * minFundingLifetimeSlots: 50n,\r\n * maxAccountBSettlementChunks: 10n,\r\n * maxBankruptCloseChunks: 10n,\r\n * maxBankruptCloseLifetimeSlots: 500n,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\r\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\r\n const isV17Args = 'maxPortfolioAssets' in args;\r\n\r\n let maxPortfolioAssets: number;\r\n let hMin: bigint | string;\r\n let hMax: bigint | string;\r\n let initialPrice: bigint | string;\r\n let minNonzeroMmReq: bigint | string;\r\n let minNonzeroImReq: bigint | string;\r\n let maintenanceMarginBps: bigint | string;\r\n let initialMarginBps: bigint | string;\r\n let maxTradingFeeBps: bigint | string;\r\n let tradeFeeBaseBps: bigint | string;\r\n let liquidationFeeBps: bigint | string;\r\n let liquidationFeeCap: bigint | string;\r\n let minLiquidationAbs: bigint | string;\r\n let maxPriceMoveBpsPerSlot: bigint | string;\r\n let maxAccrualDtSlots: bigint | string;\r\n let maxAbsFundingE9PerSlot: bigint | string;\r\n let minFundingLifetimeSlots: bigint | string;\r\n let maxAccountBSettlementChunks: bigint | string;\r\n let maxBankruptCloseChunks: bigint | string;\r\n let maxBankruptCloseLifetimeSlots: bigint | string;\r\n let publicBChunkAtoms: bigint | string;\r\n let maintenanceFeePerSlot: bigint | string;\r\n\r\n if (isV17Args) {\r\n const v = args as InitMarketV17Args;\r\n maxPortfolioAssets = v.maxPortfolioAssets;\r\n hMin = v.hMin;\r\n hMax = v.hMax;\r\n initialPrice = v.initialPrice;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n maxTradingFeeBps = v.maxTradingFeeBps;\r\n tradeFeeBaseBps = v.tradeFeeBaseBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\r\n maxAccrualDtSlots = v.maxAccrualDtSlots;\r\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\r\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\r\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\r\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\r\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\r\n publicBChunkAtoms = v.publicBChunkAtoms;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n } else {\r\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\r\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\r\n // invert, unitScale, extendedTail) are silently ignored.\r\n const v = args as InitMarketArgs;\r\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\r\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\r\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\r\n hMin = resolvedHMin;\r\n hMax = resolvedHMax;\r\n initialPrice = v.initialMarkPriceE6;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\r\n maxTradingFeeBps = v.tradingFeeBps;\r\n tradeFeeBaseBps = v.tradingFeeBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\r\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\r\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\r\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\r\n minFundingLifetimeSlots = 0n;\r\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\r\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\r\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\r\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\r\n // them to functional values instead so v12-initialized markets stay recoverable; callers\r\n // wanting explicit control should migrate to InitMarketV17Args.\r\n maxAccountBSettlementChunks = 10n;\r\n maxBankruptCloseChunks = 10n;\r\n maxBankruptCloseLifetimeSlots = 500n;\r\n publicBChunkAtoms = 1_000_000n;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n }\r\n\r\n const data = concatBytes(\r\n encU8(IX_TAG.InitMarket),\r\n encU16(maxPortfolioAssets),\r\n encU64(hMin),\r\n encU64(hMax),\r\n encU64(initialPrice),\r\n encU128(minNonzeroMmReq),\r\n encU128(minNonzeroImReq),\r\n encU64(maintenanceMarginBps),\r\n encU64(initialMarginBps),\r\n encU64(maxTradingFeeBps),\r\n encU64(tradeFeeBaseBps),\r\n encU64(liquidationFeeBps),\r\n encU128(liquidationFeeCap),\r\n encU128(minLiquidationAbs),\r\n encU64(maxPriceMoveBpsPerSlot),\r\n encU64(maxAccrualDtSlots),\r\n encU64(maxAbsFundingE9PerSlot),\r\n encU64(minFundingLifetimeSlots),\r\n encU64(maxAccountBSettlementChunks),\r\n encU64(maxBankruptCloseChunks),\r\n encU64(maxBankruptCloseLifetimeSlots),\r\n encU128(publicBChunkAtoms),\r\n encU128(maintenanceFeePerSlot),\r\n );\r\n\r\n if (data.length !== INIT_MARKET_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n return data;\r\n}\r\n\r\n/**\r\n * InitPortfolio / InitUser instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\r\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\r\n * Sending extra bytes causes garbage reads in downstream decoder arms.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitUser();\r\n * ```\r\n */\r\nexport interface InitUserArgs {\r\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\r\n feePayment?: bigint | string;\r\n}\r\n\r\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.InitPortfolio]);\r\n}\r\n\r\n/**\r\n * InitLP (tag 2) — REMOVED in v17.\r\n *\r\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\r\n */\r\nexport interface InitLPArgs {\r\n matcherProgram: PublicKey | string;\r\n matcherContext: PublicKey | string;\r\n feePayment: bigint | string;\r\n}\r\n\r\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\r\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\r\n}\r\n\r\n/**\r\n * DepositCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\r\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\r\n *\r\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface DepositCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\r\n *\r\n * @param amount Collateral to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\r\n * ```\r\n */\r\nexport interface WithdrawCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) action byte values.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\r\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\r\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\r\n */\r\nexport const CrankAction = {\r\n FeeSweep: 0,\r\n Liquidate: 1,\r\n} as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) instruction args.\r\n *\r\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\r\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\r\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\r\n * and the fee rate is always read from config inside\r\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\r\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\r\n * while still making forward progress. Any client still encoding the old\r\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\r\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\r\n * side, not a runtime check.\r\n *\r\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\r\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\r\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\r\n * `read_u64`/`read_i128`/`push_*` call sequence.\r\n *\r\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\r\n * The program hard-rejects any nonzero value with InvalidInstructionData.\r\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\r\n * produces a truncated instruction (missing 16 bytes).\r\n *\r\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\r\n * @param assetIndex Asset/domain index to operate on.\r\n * @param nowSlot Current slot (for crank freshness check).\r\n * @param recoveryReason Recovery reason byte (0 for normal operations).\r\n *\r\n * @example\r\n * ```ts\r\n * // Simple fee-sweep crank\r\n * const data = encodePermissionlessCrank({\r\n * action: CrankAction.FeeSweep,\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * recoveryReason: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface PermissionlessCrankArgs {\r\n action: number;\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n recoveryReason: number;\r\n}\r\n\r\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.PermissionlessCrank),\r\n encU8(args.action),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\r\n encU8(args.recoveryReason),\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\r\n * Use encodePermissionlessCrank() instead.\r\n *\r\n * Retained for source-compat only. Will throw to prevent silent misuse.\r\n */\r\nexport interface KeeperCrankArgs {\r\n callerIdx: number;\r\n candidates?: unknown[];\r\n}\r\n\r\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\r\n throw new Error(\r\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\r\n \"Use encodePermissionlessCrank() instead.\"\r\n );\r\n}\r\n\r\n/**\r\n * TradeNoCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\r\n * v17 has asset_index+size_q+exec_price+fee_bps.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\r\n * @param execPrice Execution price in e6 units.\r\n * @param feeBps Fee in basis points.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeNoCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * execPrice: 50_000_000_000n,\r\n * feeBps: 30n,\r\n * });\r\n * ```\r\n */\r\nexport interface TradeNoCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeNoCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.execPrice),\r\n encU64(args.feeBps),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\r\n *\r\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\r\n */\r\nexport interface LiquidateAtOracleArgs {\r\n targetIdx: number;\r\n}\r\n\r\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LiquidateAtOracle\",\r\n IX_TAG.LiquidateAtOracle,\r\n \"PermissionlessCrank (tag 5)\",\r\n );\r\n}\r\n\r\n/**\r\n * ClosePortfolio / CloseAccount instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\r\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\r\n * bytes from the old userIdx field cause InvalidInstructionData.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseAccount();\r\n * ```\r\n */\r\nexport interface CloseAccountArgs {\r\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\r\n userIdx?: number;\r\n}\r\n\r\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.ClosePortfolio]);\r\n}\r\n\r\n/**\r\n * TopUpInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\r\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\r\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\r\n *\r\n * @param amount Amount to top up the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\r\n * ```\r\n */\r\nexport interface TopUpInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * TopUpBackingBucket instruction data (tag 24).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\r\n * = 27 bytes.\r\n *\r\n * Deposits `amount` quote atoms of external collateral into a source domain's\r\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\r\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\r\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\r\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\r\n *\r\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\r\n * SHORT domain is `2*i + 1`.\r\n *\r\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\r\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\r\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\r\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\r\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\r\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\r\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\r\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\r\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\r\n * every later automatic loss-reserve requests the SAME existing expiry and\r\n * hits the harmless no-op arm instead of the LockActive trap.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\r\n * nonzero \"dust\" amount is sufficient — there is no\r\n * minimum floor enforced by the engine.\r\n * @param expirySlot Requested fresh-expiry slot (u64). Use\r\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\r\n *\r\n * @example\r\n * ```ts\r\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\r\n * const data = encodeTopUpBackingBucket({\r\n * domain: 0,\r\n * amount: 10_000n, // 0.01 Sim-USDC dust\r\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\r\n * });\r\n * ```\r\n */\r\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\r\n\r\nexport interface TopUpBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n expirySlot: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TopUpBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n encU64(args.expirySlot),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucket instruction data (tag 50).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\r\n * back to the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\r\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\r\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\r\n *\r\n * Together with TopUpBackingBucket (24, deposit) and\r\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\r\n * LP-provider backing-bucket loop.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateBackingFeePolicy instruction data (tag 51).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * THE switch that turns on LP-vault yield for a domain: sets the\r\n * backing-trade fee charged on that domain's fills, of which\r\n * `insurance_share_bps` is diverted to the insurance budget and the\r\n * remainder accrues to the domain's backing-bucket providers as\r\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\r\n * currently has this at 0 — which is why LP APY is 0%.\r\n *\r\n * Gated by the asset's `insurance_authority` (v16_program.rs\r\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\r\n * the market creator can call it even after the launch flow rotates\r\n * marketauth to the stake-pool PDA. Market must be Live.\r\n *\r\n * Handler-side validation (reverts InvalidInstruction otherwise):\r\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\r\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\r\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\r\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\r\n * of the fee (the rest goes to backing providers).\r\n */\r\nexport interface UpdateBackingFeePolicyArgs {\r\n domain: number;\r\n feeBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateBackingFeePolicy),\r\n encU16(args.domain),\r\n encU16(args.feeBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings instruction data (tag 52).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\r\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\r\n * the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket_earnings` → same\r\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\r\n * per-domain ledger account is REQUIRED (account [2]).\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketEarningsArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucketEarnings(\r\n args: WithdrawBackingBucketEarningsArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * TradeCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\r\n * v17 has asset_index+size_q+fee_bps+limit_price.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed).\r\n * @param feeBps Fee in basis points.\r\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\r\n * Buys: reject if exec_price > limit_price.\r\n * Sells: reject if exec_price < limit_price.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * feeBps: 30n,\r\n * limitPrice: 51_000_000_000n, // max price for a buy\r\n * });\r\n * ```\r\n */\r\nexport interface TradeCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n /** Limit price in e6 units. 0 = no limit. */\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.feeBps),\r\n encU64(args.limitPrice),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\r\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\r\n */\r\nexport interface TradeCpiV2Args {\r\n lpIdx: number;\r\n userIdx: number;\r\n size: bigint | string;\r\n bump: number;\r\n}\r\n\r\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\r\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\r\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\r\n */\r\nexport interface UnresolveMarketArgs {\r\n confirmation: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\r\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\r\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetRiskThresholdArgs {\r\n newThreshold: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\r\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * UpdateAdmin (tag 12) — REMOVED in v17.\r\n *\r\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\r\n */\r\nexport interface UpdateAdminArgs {\r\n newAdmin: PublicKey | string;\r\n}\r\n\r\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\r\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateAdmin\",\r\n IX_TAG.UpdateAdmin,\r\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\r\n );\r\n}\r\n\r\n/**\r\n * CloseSlab instruction data (1 byte)\r\n */\r\nexport function encodeCloseSlab(): Uint8Array {\r\n return encU8(IX_TAG.CloseSlab);\r\n}\r\n\r\n/**\r\n * UpdateConfig instruction data.\r\n *\r\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\r\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\r\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\r\n * src/percolator.rs:2027-2041 (handle_update_config decode).\r\n */\r\nexport interface UpdateConfigArgs {\r\n fundingHorizonSlots: bigint | string;\r\n fundingKBps: bigint | string;\r\n fundingMaxPremiumBps: bigint | string;\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /**\r\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\r\n * Wrapper field added at src/percolator.rs:2031.\r\n */\r\n tvlInsuranceCapMult?: number;\r\n}\r\n\r\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\r\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\r\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetMaintenanceFeeArgs {\r\n newFee: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\r\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * SetOraclePriceCap instruction data (9 bytes)\r\n * Set oracle price circuit breaker cap (admin only).\r\n *\r\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\r\n * 1_000_000 = 100% max move per slot.\r\n *\r\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\r\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\r\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\r\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\r\n *\r\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\r\n */\r\nexport interface SetOraclePriceCapArgs {\r\n maxChangeE2bps: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\r\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\r\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\r\n}\r\n\r\n/**\r\n * ResolveMode constants — retained for source compatibility with v12.x callers.\r\n *\r\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\r\n * no longer encoded into the instruction data. They may be used in logging or\r\n * off-chain logic but must not be passed to encodeResolveMarket.\r\n */\r\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\r\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\r\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\r\n\r\n/**\r\n * ResolveMarket instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\r\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\r\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\r\n * next read in a subsequent call, corrupting the instruction stream.\r\n *\r\n * The `mode` argument is accepted for source compatibility but is silently ignored.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeResolveMarket();\r\n * ```\r\n */\r\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\r\n return new Uint8Array([IX_TAG.ResolveMarket]);\r\n}\r\n\r\n/**\r\n * WithdrawInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\r\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\r\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\r\n * 1-byte payload fails on devnet/mainnet.\r\n *\r\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\r\n *\r\n * @param amount Amount to withdraw from the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * AdminForceClose instruction data (3 bytes)\r\n * Force-close any position at oracle price (admin only, skips margin checks).\r\n */\r\nexport interface AdminForceCloseArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\r\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\r\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\r\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\r\n * Use encodeSetInsuranceWithdrawPolicy instead.\r\n */\r\nexport interface UpdateRiskParamsArgs {\r\n initialMarginBps: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n tradingFeeBps?: bigint | string;\r\n}\r\n\r\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\r\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateRiskParams\",\r\n IX_TAG.UpdateRiskParams,\r\n \"encodeSetInsuranceWithdrawPolicy()\",\r\n );\r\n}\r\n\r\n/**\r\n * On-chain confirmation code for RenounceAdmin (must match program constant).\r\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\r\n */\r\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\r\n\r\n/**\r\n * On-chain confirmation code for UnresolveMarket (must match program constant).\r\n */\r\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\r\n\r\n/**\r\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\r\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\r\n * Use encodeWithdrawInsuranceLimited instead.\r\n */\r\nexport function encodeRenounceAdmin(): Uint8Array {\r\n return removedInstruction(\r\n \"RenounceAdmin\",\r\n IX_TAG.RenounceAdmin,\r\n \"encodeWithdrawInsuranceLimited()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\r\n * withdraw proportional collateral.\r\n *\r\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\r\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\r\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\r\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\r\n *\r\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\r\n *\r\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\r\n * [0] withdrawer signer\r\n * [1] slab writable\r\n * [2] withdrawerAta writable\r\n * [3] vault writable\r\n * [4] tokenProgram\r\n * [5] lpVaultMint writable\r\n * [6] withdrawerLpAta writable\r\n * [7] vaultAuthority\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\r\n *\r\n * @param lpAmount - Amount of LP vault tokens to burn.\r\n *\r\n * @example\r\n * ```ts\r\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\r\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\r\n *\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\r\n *\r\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\r\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\r\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\r\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\r\n * });\r\n * ```\r\n */\r\nexport interface LpVaultWithdrawArgs {\r\n /** Amount of LP vault tokens to burn. */\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\r\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\r\n */\r\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\r\n IX_TAG.LpVaultWithdraw,\r\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\r\n */\r\nexport function encodePauseMarket(): Uint8Array {\r\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\r\n */\r\nexport function encodeUnpauseMarket(): Uint8Array {\r\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-117: Pyth Oracle CPI Instructions\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetPythOracleArgs {\r\n feedId: Uint8Array;\r\n maxStalenessSecs: bigint;\r\n confFilterBps: number;\r\n}\r\n\r\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\r\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\r\n void args;\r\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\r\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\r\n *\r\n * @param feedId 32-byte Pyth feed ID\r\n * @param shardId Shard index (default 0 for mainnet/devnet)\r\n */\r\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\r\n\r\nexport async function derivePythPriceUpdateAccount(\r\n feedId: Uint8Array,\r\n shardId = 0,\r\n): Promise {\r\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\r\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\r\n }\r\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\r\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\r\n }\r\n const { PublicKey } = await import('@solana/web3.js');\r\n const shardBuf = new Uint8Array(2);\r\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\r\n const [pda] = PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\r\n );\r\n return pda.toBase58();\r\n}\r\n\r\n// SetPythOracle tag (32) is already defined in IX_TAG above.\r\n\r\n// PERC-118: Mark Price EMA Instructions\r\n// ============================================================================\r\n\r\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\r\n\r\n/**\r\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport function encodeUpdateMarkPrice(): Uint8Array {\r\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\r\n}\r\n\r\n/**\r\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\r\n */\r\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\r\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\r\n\r\n/**\r\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\r\n */\r\nexport function computeEmaMarkPrice(\r\n markPrevE6: bigint,\r\n oracleE6: bigint,\r\n dtSlots: bigint,\r\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\r\n capE2bps = 0n,\r\n): bigint {\r\n if (oracleE6 === 0n) return markPrevE6;\r\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\r\n\r\n let oracleClamped = oracleE6;\r\n if (capE2bps > 0n) {\r\n // Avoid overflow: divide early to reduce intermediate product\r\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\r\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\r\n const hi = markPrevE6 + maxDelta;\r\n if (oracleClamped < lo) oracleClamped = lo;\r\n if (oracleClamped > hi) oracleClamped = hi;\r\n }\r\n\r\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\r\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\r\n\r\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\r\n}\r\n\r\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\r\n// ============================================================================\r\n\r\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\r\n\r\n/**\r\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\r\n *\r\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\r\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\r\n * to authority_price_e6 on the slab.\r\n *\r\n * This is the core mechanism for permissionless token markets — no Pyth or\r\n * Chainlink feed is needed. The DEX AMM IS the oracle.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\r\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\r\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\r\n */\r\nexport function encodeUpdateHyperpMark(): Uint8Array {\r\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\r\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\r\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\r\n return removedInstruction(\r\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\r\n 34,\r\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-306: Per-Market Insurance Isolation\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\r\n */\r\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\r\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\r\n}\r\n\r\n/**\r\n * Set insurance isolation BPS for a market.\r\n * Accounts: [admin(signer), slab(writable)]\r\n */\r\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\r\n void args;\r\n return removedInstruction(\r\n \"SetInsuranceIsolation\",\r\n IX_TAG.SetInsuranceIsolation,\r\n \"encodeFundMarketInsurance()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\r\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\r\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\r\n// ============================================================================\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\r\n *\r\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\r\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\r\n *\r\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\r\n * ```\r\n */\r\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\r\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n/**\r\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\r\n *\r\n * Burns LP tokens and releases one tranche of SOL to the user.\r\n * Call once per epoch until epochs_remaining == 0.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\r\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\r\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\r\n */\r\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\r\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\r\n *\r\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\r\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\r\n * Use only to abandon a partial withdrawal.\r\n *\r\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\r\n */\r\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\r\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\r\n *\r\n * Permissionless. Surgically closes or reduces `targetIdx` position when\r\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\r\n * the incentive is unblocking the market for normal trading.\r\n *\r\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\r\n *\r\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\r\n *\r\n * @param targetIdx - Account index of the position to deleverage.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteAdl({ targetIdx: 5 });\r\n * ```\r\n */\r\nexport interface ExecuteAdlArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\r\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\r\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\r\n *\r\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\r\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\r\n * whose size does not match any current valid tier.\r\n *\r\n * Accounts: [dest(signer,writable), slab(writable)]\r\n */\r\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\r\nexport function encodeCloseStaleSlabs(): Uint8Array {\r\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\r\n}\r\n\r\n/**\r\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\r\n *\r\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\r\n * The slab account must sign (proves the caller holds the slab keypair).\r\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\r\n *\r\n * Accounts: [dest(signer,writable), slab(signer,writable)]\r\n */\r\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\r\nexport function encodeReclaimSlabRent(): Uint8Array {\r\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\r\n *\r\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\r\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\r\n * prevent DoS from transient failures).\r\n *\r\n * Accounts: [slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeAuditCrank();\r\n * ```\r\n */\r\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\r\nexport function encodeAuditCrank(): Uint8Array {\r\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// SMART PRICE ROUTER — quote computation for LP selection\r\n// ============================================================================\r\n\r\n/**\r\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\r\n */\r\nexport interface VammMatcherParams {\r\n mode: number; // 0 = Passive, 1 = vAMM\r\n tradingFeeBps: number;\r\n baseSpreadBps: number;\r\n maxTotalBps: number;\r\n impactKBps: number;\r\n liquidityNotionalE6: bigint;\r\n}\r\n\r\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\r\nexport const VAMM_MAGIC = 0x504552434d415443n;\r\n/** Alias matching the Rust constant name for parity tests */\r\nexport const MATCHER_MAGIC = VAMM_MAGIC;\r\n\r\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\r\nexport const CTX_RETURN_OFFSET = 0;\r\n/** Byte length of the MatcherReturn section of the context account */\r\nexport const MATCHER_RETURN_LEN = 64;\r\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\r\nexport const CTX_VAMM_OFFSET = 64;\r\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\r\nexport const CTX_VAMM_LEN = 256;\r\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\r\nexport const MATCHER_CONTEXT_LEN = 320;\r\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\r\nexport const MATCHER_CALL_LEN = 67;\r\n/**\r\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\r\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\r\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\r\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\r\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\r\n */\r\nexport const INIT_CTX_LEN = 78;\r\n\r\nconst BPS_DENOM = 10_000n;\r\n\r\n/**\r\n * Compute execution price for a given LP quote.\r\n * For buys (isLong=true): price above oracle.\r\n * For sells (isLong=false): price below oracle.\r\n */\r\nexport function computeVammQuote(\r\n params: VammMatcherParams,\r\n oraclePriceE6: bigint,\r\n tradeSize: bigint,\r\n isLong: boolean,\r\n): bigint {\r\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\r\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\r\n\r\n // Impact for vAMM mode\r\n let impactBps = 0n;\r\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\r\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\r\n }\r\n\r\n // Total = base_spread + trading_fee + impact, capped at max_total\r\n const maxTotal = BigInt(params.maxTotalBps);\r\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\r\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\r\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\r\n let totalBps = baseFee + clampedImpact;\r\n if (totalBps > maxTotal) totalBps = maxTotal;\r\n\r\n if (isLong) {\r\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\r\n } else {\r\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\r\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\r\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless crank)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\r\n *\r\n * Checks if a market should transition from Phase 0→1→2 based on\r\n * time elapsed and cumulative volume. Anyone can call this.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n */\r\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\r\nexport function encodeAdvanceOraclePhase(): Uint8Array {\r\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\r\n}\r\n\r\n/** Oracle phase constants matching on-chain values */\r\nexport const ORACLE_PHASE_NASCENT = 0;\r\nexport const ORACLE_PHASE_GROWING = 1;\r\nexport const ORACLE_PHASE_MATURE = 2;\r\n\r\n/** Phase transition thresholds (must match program constants) */\r\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\r\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\r\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\r\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\r\n\r\n/**\r\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\r\n *\r\n * @returns [newPhase, shouldTransition]\r\n */\r\nexport function checkPhaseTransition(\r\n currentSlot: bigint,\r\n marketCreatedSlot: bigint,\r\n oraclePhase: number,\r\n cumulativeVolumeE6: bigint,\r\n phase2DeltaSlots: number,\r\n hasMatureOracle: boolean,\r\n): [number, boolean] {\r\n switch (oraclePhase) {\r\n case 0: {\r\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\r\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\r\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\r\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\r\n if (timeReady || volumeReady) {\r\n return [ORACLE_PHASE_GROWING, true];\r\n }\r\n return [ORACLE_PHASE_NASCENT, false];\r\n }\r\n case 1: {\r\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\r\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\r\n const elapsedSincePhase2 = currentSlot - phase2Start;\r\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\r\n return [ORACLE_PHASE_MATURE, true];\r\n }\r\n return [ORACLE_PHASE_GROWING, false];\r\n }\r\n default:\r\n return [ORACLE_PHASE_MATURE, false];\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-629: Dynamic Creation Deposit\r\n// ============================================================================\r\n\r\n/**\r\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\r\n * after the spam grace period has elapsed (PERC-629).\r\n *\r\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\r\n * handler in the on-chain program. Sending this instruction will fail with\r\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [] Slab\r\n * 2. [writable] Creator history PDA\r\n * 3. [writable] Insurance vault\r\n * 4. [writable] Treasury\r\n * 5. [] System program\r\n *\r\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\r\n */\r\nexport function encodeSlashCreationDeposit(): Uint8Array {\r\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\r\n// ============================================================================\r\n\r\n/**\r\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\r\n *\r\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [writable] Shared vault PDA\r\n * 2. [] System program\r\n */\r\nexport interface InitSharedVaultArgs {\r\n epochDurationSlots: bigint | string;\r\n maxMarketExposureBps: number;\r\n}\r\n\r\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\r\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\r\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\r\n}\r\n\r\n/**\r\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\r\n * to a market (PERC-628).\r\n *\r\n * Instruction data: tag(1) + amount(16) = 17 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [] Slab\r\n * 2. [writable] Shared vault PDA\r\n * 3. [writable] Market alloc PDA\r\n * 4. [] System program\r\n */\r\nexport interface AllocateMarketArgs {\r\n amount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\r\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\r\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\r\n}\r\n\r\n/**\r\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\r\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\r\n *\r\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] System program\r\n */\r\nexport interface QueueWithdrawalSVArgs {\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\r\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\r\n}\r\n\r\n/**\r\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\r\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] Slab\r\n * 4. [writable] Vault\r\n * 5. [writable] User ATA\r\n * 6. [] Vault authority\r\n * 7. [] Token program\r\n */\r\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\r\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\r\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [writable] Shared vault PDA\r\n */\r\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\r\nexport function encodeAdvanceEpoch(): Uint8Array {\r\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\r\n}\r\n\r\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\r\n\r\n// PERC-8110 ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\r\n *\r\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\r\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\r\n *\r\n * - `threshold_bps = 0`: hard block disabled.\r\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\r\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\r\n *\r\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\r\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\r\n * });\r\n * ```\r\n */\r\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\r\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-608 — Position NFT instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\r\n *\r\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\r\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\r\n *\r\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\r\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\r\n * program creates it, so the ATA can't be created in a preceding instruction.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts (11):\r\n * 0. [signer, writable] payer\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\r\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\r\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\r\n * 5. [signer] owner (must match engine account owner)\r\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\r\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\r\n * 8. [] system_program\r\n * 9. [] rent sysvar\r\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\r\n */\r\nexport interface MintPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\r\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\r\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\r\n */\r\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\r\n IX_TAG.MintPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\r\n *\r\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\r\n * engine account's owner field. Requires `pending_settlement == 0`.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] current_owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA\r\n * 3. [writable] nft_mint PDA\r\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\r\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\r\n * 6. [] new_owner\r\n * 7. [] token_2022_program\r\n */\r\nexport interface TransferPositionOwnershipArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\r\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\r\n */\r\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\r\n IX_TAG.TransferPositionOwnership,\r\n \"encodeTransferPortfolioOwnership() (tag 72)\",\r\n );\r\n}\r\n\r\n/**\r\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\r\n *\r\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\r\n * Can only be called after the position is fully closed (size == 0).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (closed — rent to owner)\r\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\r\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\r\n * 5. [] vault_authority PDA\r\n * 6. [] token_2022_program\r\n */\r\nexport interface BurnPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\r\n * NFT burn is handled by the standalone percolator-nft program in v17.\r\n */\r\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\r\n IX_TAG.BurnPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin before performing a funding settlement transfer.\r\n * Blocks NFT transfers until ClearPendingSettlement is called.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface SetPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\r\n */\r\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\r\n IX_TAG.SetPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface ClearPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\r\n */\r\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\r\n IX_TAG.ClearPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\r\n *\r\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\r\n * Updates the engine account's owner field to the new_owner public key.\r\n * NOT intended for direct external use — always called via Token-2022 CPI.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] nft TransferHook program (CPI caller)\r\n * 1. [writable] slab\r\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\r\n */\r\nexport interface TransferOwnershipCpiArgs {\r\n userIdx: number;\r\n newOwner: PublicKey | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\r\n */\r\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\r\n IX_TAG.TransferOwnershipCpi,\r\n \"percolator-nft transfer hook\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-8111 — SetWalletCap (tag 70)\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\r\n *\r\n * Limits the maximum absolute position size any single wallet may hold on this market.\r\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\r\n *\r\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\r\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\r\n * Phase 1 launch value: 1_000_000_000n ($1,000).\r\n *\r\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\r\n * (error code 58) is returned.\r\n *\r\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * // Set $1K per-wallet cap\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\r\n * });\r\n *\r\n * // Disable cap\r\n * const disableIx = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\r\n * });\r\n * ```\r\n */\r\nexport interface SetWalletCapArgs {\r\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\r\n capE6: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\r\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\r\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\r\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\r\n *\r\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\r\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\r\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\r\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\r\n * handler reads the LP portfolio's stored matcher config and verifies that:\r\n * cfg.matcher_program == matcherProg\r\n * cfg.matcher_context == matcherCtx\r\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\r\n *\r\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\r\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\r\n * check on the deployed binary. No client-side signer of the delegate is needed.\r\n *\r\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\r\n * [0] lp_owner signer (LP portfolio owner)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\r\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\r\n * [4] matcher_prog read-only, executable (the matcher program)\r\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\r\n *\r\n * @param args.kind 0=Passive, 1=vAMM\r\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\r\n * @param args.baseSpreadBps Base spread in bps (u32)\r\n * @param args.maxTotalBps Max total spread in bps (u32)\r\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\r\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\r\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\r\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\r\n *\r\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\r\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\r\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\r\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\r\n * this tag free.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMatcherCtx({\r\n * kind: 0, // Passive\r\n * tradingFeeBps: 30,\r\n * baseSpreadBps: 50,\r\n * maxTotalBps: 200,\r\n * impactKBps: 0,\r\n * liquidityNotionalE6: 0n,\r\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\r\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\r\n * feeToInsuranceBps: 0,\r\n * skewSpreadMultBps: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface InitMatcherCtxArgs {\r\n /**\r\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\r\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\r\n */\r\n lpIdx?: number;\r\n /** Matcher kind: 0=Passive, 1=vAMM. */\r\n kind: number;\r\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\r\n tradingFeeBps: number;\r\n /** Base spread in bps (u32). */\r\n baseSpreadBps: number;\r\n /** Max total spread in bps (u32). */\r\n maxTotalBps: number;\r\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\r\n impactKBps: number;\r\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\r\n liquidityNotionalE6: bigint | string;\r\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\r\n maxFillAbs: bigint | string;\r\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\r\n maxInventoryAbs: bigint | string;\r\n /** Fraction of fees routed to insurance fund in bps (u16). */\r\n feeToInsuranceBps: number;\r\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\r\n skewSpreadMultBps: number;\r\n}\r\n\r\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\r\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\r\n\r\n/**\r\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\r\n *\r\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\r\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\r\n *\r\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\r\n * @returns 70-byte Uint8Array\r\n */\r\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(83), // IX_TAG.InitMatcherCtx = 83\r\n encU8(args.kind),\r\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\r\n encU128(args.liquidityNotionalE6), // u128 LE\r\n encU128(args.maxFillAbs), // u128 LE\r\n encU128(args.maxInventoryAbs), // u128 LE\r\n encU16(args.feeToInsuranceBps), // u16 LE\r\n encU16(args.skewSpreadMultBps), // u16 LE\r\n );\r\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n// ============================================================================\r\n// Missing encoders — corrected tag mappings (tags 22-74)\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\r\n */\r\nexport interface SetInsuranceWithdrawPolicyArgs {\r\n authority: PublicKey | string;\r\n minWithdrawBase: bigint | string;\r\n maxWithdrawBps: number;\r\n cooldownSlots: bigint | string;\r\n}\r\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\r\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\r\n */\r\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\r\n */\r\nexport function encodeResolvePermissionless(): Uint8Array {\r\n return removedInstruction(\r\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\r\n IX_TAG.ResolvePermissionless,\r\n \"encodeResolveStalePermissionless()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\r\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\r\n return removedInstruction(\r\n \"ForceCloseResolved\",\r\n IX_TAG.ForceCloseResolved,\r\n \"encodeCloseResolved() for v17\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeCreateLpVault (v12 format)\",\r\n IX_TAG.CreateLpVault,\r\n \"encodeCreateLpVaultV17()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeLpVaultDeposit (v12 format)\",\r\n IX_TAG.LpVaultDeposit,\r\n \"encodeDepositToLpVault()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\r\n */\r\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"ChallengeSettlement\",\r\n IX_TAG.ChallengeSettlement,\r\n undefined,\r\n );\r\n}\r\n\r\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\r\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\r\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\r\n}\r\n\r\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\r\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\r\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\r\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\r\n}\r\n\r\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\r\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\r\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\r\n}\r\n\r\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\r\nexport function encodeRescueOrphanVault(): Uint8Array {\r\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\r\n}\r\n\r\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\r\nexport function encodeCloseOrphanSlab(): Uint8Array {\r\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\r\n}\r\n\r\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\r\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\r\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeCreateInsuranceMint(): Uint8Array {\r\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n// ============================================================================\r\n// Phase B admin setters (tags 78-81) — added 2026-04-17\r\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\r\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport interface SetMaxPnlCapArgs {\r\n cap: bigint | string;\r\n}\r\n\r\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\r\n IX_TAG.SetMaxPnlCap,\r\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\r\n */\r\nexport interface SetOiCapMultiplierArgs {\r\n packed: bigint | string;\r\n}\r\n\r\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\r\n IX_TAG.SetOiCapMultiplier,\r\n \"encodeSetLpVaultPaused() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\r\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\r\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\r\n }\r\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\r\n }\r\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\r\n */\r\nexport interface SetDisputeParamsArgs {\r\n windowSlots: bigint | string;\r\n bondAmount: bigint | string;\r\n}\r\n\r\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\r\n IX_TAG.SetDisputeParams,\r\n \"encodeCloseLpVault() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\r\n */\r\nexport interface SetLpCollateralParamsArgs {\r\n enabled: number;\r\n ltvBps: number;\r\n}\r\n\r\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\r\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\r\n */\r\nexport function encodeAcceptAdmin(): Uint8Array {\r\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\r\n}\r\n\r\n// ============================================================================\r\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\r\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\r\n */\r\nexport interface ReclaimEmptyAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\r\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\r\n */\r\nexport interface SettleAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\r\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\r\n */\r\nexport interface DepositFeeCreditsArgs {\r\n userIdx: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\r\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\r\n}\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\r\n * Owner only.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\r\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\r\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\r\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\r\n * are identified by account key alone.\r\n *\r\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\r\n *\r\n * @param amount Amount of released PnL to convert (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface ConvertReleasedPnlArgs {\r\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ConvertReleasedPnl),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\r\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\r\n *\r\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\r\n *\r\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\r\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\r\n * Burning marketauth to zero is rejected on-chain.\r\n *\r\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\r\n * ```\r\n */\r\nexport interface UpdateAuthorityArgs {\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAuthority),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — UpdateAssetAuthority (tag 65)\r\n// ============================================================================\r\n\r\n/**\r\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\r\n *\r\n * Exact mapping from v16_program.rs lines 5246-5250:\r\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\r\n * ASSET_AUTH_INSURANCE = 1 → Insurance\r\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\r\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\r\n * ASSET_AUTH_ORACLE = 4 → Oracle\r\n *\r\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\r\n * slot. Wrong values silently corrupt authority state:\r\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\r\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\r\n * corrupting the market-level admin key instead.\r\n *\r\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\r\n * the stake vault PDA into the asset_admin authority slot.\r\n */\r\nexport const ASSET_AUTH_KIND = {\r\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\r\n AssetAdmin: 0,\r\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\r\n Insurance: 1,\r\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\r\n InsuranceOperator: 2,\r\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\r\n BackingBucket: 3,\r\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\r\n Oracle: 4,\r\n} as const;\r\nObject.freeze(ASSET_AUTH_KIND);\r\n\r\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\r\n\r\n/**\r\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * Gated by the asset's own asset_admin (can rotate any) or by the current\r\n * holder of that authority (self-rotation). Isolated to the given asset_index.\r\n *\r\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\r\n * @param kind ASSET_AUTH_KIND.* constant.\r\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\r\n *\r\n * @example\r\n * ```ts\r\n * // Rotate insurance authority for asset 0\r\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\r\n * const data = encodeUpdateAssetAuthority({\r\n * assetIndex: 0,\r\n * kind: ASSET_AUTH_KIND.Insurance,\r\n * newPubkey: newInsuranceKey,\r\n * });\r\n * ```\r\n */\r\nexport interface UpdateAssetAuthorityArgs {\r\n assetIndex: number;\r\n kind: AssetAuthKind;\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAssetAuthority),\r\n encU16(args.assetIndex),\r\n encU8(args.kind),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\r\n// ============================================================================\r\n\r\n/**\r\n * One leg of a BatchTradeNoCpi instruction.\r\n */\r\nexport interface BatchTradeNoCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\n/**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\r\n *\r\n * @param legs Array of up to 255 trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeNoCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\r\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\r\n * ]});\r\n * ```\r\n */\r\nexport interface BatchTradeNoCpiArgs {\r\n legs: BatchTradeNoCpiLeg[];\r\n}\r\n\r\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\r\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\r\n if (feeBps > 10_000n) {\r\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\r\n }\r\n}\r\n\r\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeNoCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.execPrice));\r\n parts.push(encU64(leg.feeBps));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n/**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\r\n *\r\n * @param legs Array of up to 255 CPI trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\r\n * ]});\r\n * ```\r\n */\r\n\r\nexport interface BatchTradeCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport interface BatchTradeCpiArgs {\r\n legs: BatchTradeCpiLeg[];\r\n}\r\n\r\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.feeBps));\r\n parts.push(encU64(leg.limitPrice));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — SetMatcherConfig (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n *\r\n * @param enabled 1 = enabled, 0 = disabled.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetMatcherConfig({ enabled: 1 });\r\n * ```\r\n */\r\nexport interface SetMatcherConfigArgs {\r\n enabled: number;\r\n}\r\n\r\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\r\n if (args.enabled !== 0 && args.enabled !== 1) {\r\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\r\n }\r\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — RestartAssetOracle (tag 69)\r\n// ============================================================================\r\n\r\n/**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\r\n *\r\n * Used to un-stick a stale or hung oracle. Anyone can call this.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param nowSlot Current slot.\r\n * @param initialPrice Initial mark price in e6 units.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRestartAssetOracle({\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * initialPrice: 50_000_000_000n,\r\n * });\r\n * ```\r\n */\r\nexport interface RestartAssetOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialPrice: bigint | string;\r\n}\r\n\r\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RestartAssetOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialPrice),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\r\n *\r\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\r\n * asset_index is u16 (domain u8→u16 migration in v17).\r\n *\r\n * @param assetIndex Asset/domain index (u16, not u8).\r\n * @param amount Amount to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceAssetArgs {\r\n assetIndex: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawInsuranceAsset),\r\n encU16(args.assetIndex),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — LP-vault renumbered tags (74-80)\r\n// ============================================================================\r\n\r\n/**\r\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\r\n *\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\r\n *\r\n * @param feeShareBps LP vault fee share in bps (0-10000).\r\n * @param redemptionCooldownSlots Slots between redemption requests.\r\n * @param oiReservationThresholdBps OI reservation threshold in bps.\r\n * @param domain Asset/domain index (u16 in v17).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCreateLpVault({\r\n * feeShareBps: 5000,\r\n * redemptionCooldownSlots: 21600n,\r\n * oiReservationThresholdBps: 8000,\r\n * domain: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface CreateLpVaultArgs {\r\n feeShareBps: number;\r\n redemptionCooldownSlots: bigint | string;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n}\r\n\r\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.CreateLpVault),\r\n encU16(args.feeShareBps),\r\n encU64(args.redemptionCooldownSlots),\r\n encU16(args.oiReservationThresholdBps),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\r\n *\r\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\r\n *\r\n * `domain` selects which pot of the vault's asset receives the backing and MUST\r\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\r\n * NAV across both pots, so the depositor is indifferent to the choice; routing\r\n * exists so new money can reach whichever pot the house is drawing on.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\r\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\r\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\r\n * and mint the depositor free shares at existing holders' expense.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\r\n * ```\r\n */\r\nexport function encodeDepositToLpVault(args: {\r\n amount: bigint | string;\r\n domain: number;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositToLpVault),\r\n encU128(args.amount),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\r\n *\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\r\n * v17 uses shares u128 and a two-step request/execute redemption flow.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\r\n * ```\r\n */\r\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\r\n}\r\n\r\n/**\r\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\r\n * available-principal stay COMBINED across both pots, so this does not change\r\n * what the redeemer is owed — only where the atoms come from. A redemption draws\r\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\r\n * cover it; rebalance (tag 91) first.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteRedemption({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\r\n * choice cannot dilute; routing exists so fees can become backing in the pot\r\n * that needs it. The target ledger is created on first use.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\r\n * index 5 is the system program (needed to create a missing target ledger).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeLpVaultCrankFees({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\r\n * the LP vault's asset.\r\n *\r\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\r\n *\r\n * Permissionless: both pots belong to the same vault, so the move cannot extract\r\n * value, and the source-side gate refuses anything that would leave the source\r\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\r\n * open interest, already consumed, or impaired stays put.\r\n *\r\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\r\n * systemProgram]. The destination ledger is created on first arrival.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRebalanceLpVaultBacking({\r\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeRebalanceLpVaultBacking(args: {\r\n fromDomain: number;\r\n toDomain: number;\r\n amount: bigint | string;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RebalanceLpVaultBacking),\r\n encU16(args.fromDomain),\r\n encU16(args.toDomain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\r\n *\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n *\r\n * @param paused 1 = paused, 0 = active.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetLpVaultPaused({ paused: 1 });\r\n * ```\r\n */\r\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\r\n}\r\n\r\n/**\r\n * CloseLpVault (tag 80) — close an empty LP vault.\r\n *\r\n * Wire: tag(1) = 1 byte.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseLpVault();\r\n * ```\r\n */\r\nexport function encodeCloseLpVault(): Uint8Array {\r\n return encU8(IX_TAG.CloseLpVault);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NFT / B-3 (tags 72/73) — kept from v16\r\n// ============================================================================\r\n\r\n/**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n *\r\n * @param newOwner New owner pubkey.\r\n * @param assetIndex Asset/domain index.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTransferPortfolioOwnership({\r\n * newOwner: newOwnerKey,\r\n * assetIndex: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface TransferPortfolioOwnershipArgs {\r\n newOwner: PublicKey | string;\r\n assetIndex: number;\r\n}\r\n\r\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TransferPortfolioOwnership),\r\n encPubkey(args.newOwner),\r\n encU16(args.assetIndex),\r\n );\r\n}\r\n\r\n/**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n *\r\n * @param nftProgramId Pubkey of the percolator-nft program.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\r\n * ```\r\n */\r\nexport interface SetNftProgramIdArgs {\r\n nftProgramId: PublicKey | string;\r\n}\r\n\r\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetNftProgramId),\r\n encPubkey(args.nftProgramId),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\r\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\r\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\r\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\r\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\r\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\r\n *\r\n * Constraints (from v16_program.rs:10419-10435):\r\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\r\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\r\n * - hybrid_soft_stale_slots > 0\r\n * - invert ∈ {0, 1}\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\r\n * @param oracleLegCount Number of active oracle legs (1–3).\r\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\r\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\r\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\r\n * @param markMinFee Minimum fee charged per mark-price update.\r\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\r\n * @param unitScale Unit scaling factor (u32).\r\n * @param confFilterBps Confidence filter in basis points (u16).\r\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureHybridOracle({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * nowUnixTs: 1700000000n,\r\n * oracleLegCount: 1,\r\n * oracleLegFlags: 0,\r\n * maxStalenessSecs: 60n,\r\n * hybridSoftStaleSlots: 100n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * invert: 0,\r\n * unitScale: 1000000,\r\n * confFilterBps: 200,\r\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\r\n * });\r\n * assert(data.length === 156);\r\n * ```\r\n */\r\nexport interface ConfigureHybridOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n nowUnixTs: bigint | string;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n maxStalenessSecs: bigint | string;\r\n hybridSoftStaleSlots: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\r\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\r\n}\r\n\r\nconst ORACLE_LEG_CAP = 3;\r\n\r\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\r\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\r\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\r\n }\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureHybridOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI64(args.nowUnixTs),\r\n encU8(args.oracleLegCount),\r\n encU8(args.oracleLegFlags),\r\n encU64(args.maxStalenessSecs),\r\n encU64(args.hybridSoftStaleSlots),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n encU8(args.invert),\r\n encU32(args.unitScale),\r\n encU16(args.confFilterBps),\r\n encPubkey(args.oracleLegFeeds[0]),\r\n encPubkey(args.oracleLegFeeds[1]),\r\n encPubkey(args.oracleLegFeeds[2]),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\r\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10558-10563):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - mark_ewma_halflife_slots > 0\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\r\n * @param markMinFee Minimum fee charged per mark-price update (u64).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureEwmaMark({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * initialMarkE6: 50000000000n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * });\r\n * assert(data.length === 35);\r\n * ```\r\n */\r\nexport interface ConfigureEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n}\r\n\r\nfunction requirePositiveU64(value: bigint | string, field: string): void {\r\n const n = typeof value === \"string\" ? BigInt(value) : value;\r\n if (n <= 0n) {\r\n throw new Error(`${field} must be > 0`);\r\n }\r\n}\r\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n );\r\n}\r\n\r\n/**\r\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10771):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10665):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface ConfigureAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n}\r\n\r\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n );\r\n}\r\n\r\n/**\r\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10847):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\r\n// ============================================================================\r\n\r\n/**\r\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\r\n * to initialize a passive LP matcher context.\r\n *\r\n * This is NOT a wrapper instruction. Program = matcher program address.\r\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\r\n *\r\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\r\n * [0] = 2 (opcode: passive-LP init)\r\n * [1] = 0 (reserved)\r\n * [2..10] = 0 (8 bytes reserved)\r\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\r\n * [14..34] = 0 (20 bytes reserved)\r\n * [34..50] = max_fill_abs (u128 LE)\r\n * [50..66] = 0 (16 bytes reserved)\r\n * Total = 66 bytes\r\n *\r\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\r\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\r\n *\r\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\r\n * assert(data.length === 66);\r\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\r\n * ```\r\n */\r\nexport interface MatcherInitPassiveArgs {\r\n maxFillAbs: bigint | string;\r\n}\r\n\r\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\r\n const buf = new Uint8Array(66);\r\n buf[0] = 2;\r\n buf[1] = 0;\r\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\r\n const u32Bytes = encU32(100);\r\n buf.set(u32Bytes, 10);\r\n // [34..50] = max_fill_abs u128 LE\r\n const u128Bytes = encU128(args.maxFillAbs);\r\n buf.set(u128Bytes, 34);\r\n return buf;\r\n}\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\r\n// handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\r\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\r\n//\r\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\r\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\r\n// all — sending this encoded data to it would be rejected or misinterpreted.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee instruction data (tag 84).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\r\n * WrapperConfigV17) to an external token account. Signer-gated on\r\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\r\n * clamped to what's actually available on-chain (engine surplus, vault\r\n * balance) and only the actually-transferred amount is marked withdrawn —\r\n * this never errors solely because the ledger raced ahead of availability.\r\n *\r\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\r\n * currently-available capacity.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\r\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawProtocolFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawProtocolFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetProtocolFeeAuthority instruction data (tag 85).\r\n *\r\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\r\n *\r\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\r\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\r\n * marketauth/insurance_authority/any creator-facing gate) — see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\r\n * a keeper script iterates markets for a mass rotation.\r\n *\r\n * @param newAuthority New protocol-fee-authority pubkey.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\r\n * ```\r\n */\r\nexport interface SetProtocolFeeAuthorityArgs {\r\n newAuthority: PublicKey;\r\n}\r\n\r\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetProtocolFeeAuthority),\r\n encPubkey(args.newAuthority),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\r\n *\r\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\r\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\r\n * three stored shares below, which are bps *of T* and must sum to exactly\r\n * `FEE_SHARE_TOTAL_BPS`.\r\n *\r\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\r\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\r\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\r\n * above its ceiling necessarily drags another leg under its floor.\r\n *\r\n * Defaults are written unconditionally at InitMarket and are never instruction\r\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\r\n * legs correctly from its first trade.\r\n */\r\nexport const FEE_SPLIT = {\r\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\r\n PROTOCOL_FEE_BPS: 2000,\r\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\r\n FEE_SHARE_TOTAL_BPS: 8000,\r\n DEFAULT_CREATOR_SHARE_BPS: 1600,\r\n DEFAULT_LP_SHARE_BPS: 4800,\r\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\r\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\r\n MAX_CREATOR_SHARE_BPS: 3600,\r\n /** LP floor, bps of T (40% of the post-protocol remainder). */\r\n MIN_LP_SHARE_BPS: 3200,\r\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\r\n MIN_INSURANCE_SHARE_BPS: 1200,\r\n} as const;\r\nObject.freeze(FEE_SPLIT);\r\n\r\n/**\r\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\r\n * the split would be accepted on-chain, otherwise a human-readable reason.\r\n *\r\n * Provided so a wizard/UI can reject a bad split before paying for a\r\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\r\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\r\n * floors), so this is a convenience, never the security boundary.\r\n *\r\n * @param args The three candidate shares, in bps of T.\r\n * @returns `null` if valid, else a string describing the first violation.\r\n *\r\n * @example\r\n * ```ts\r\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\r\n * // => null (these are the on-chain defaults)\r\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\r\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\r\n * ```\r\n */\r\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\r\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\r\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\r\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\r\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\r\n }\r\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\r\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\r\n }\r\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\r\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\r\n }\r\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\r\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * UpdateFeeSplit instruction data (tag 86).\r\n *\r\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\r\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\r\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\r\n * {@link validateFeeSplit} to check before sending.\r\n *\r\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\r\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\r\n * top-level transaction and this tag is reachable only via the stake program's\r\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\r\n *\r\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\r\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\r\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Restore the on-chain defaults explicitly.\r\n * const data = encodeUpdateFeeSplit({\r\n * creatorShareBps: 1600,\r\n * lpShareBps: 4800,\r\n * insuranceShareBps: 1600,\r\n * });\r\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateFeeSplitArgs {\r\n creatorShareBps: number;\r\n lpShareBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateFeeSplit),\r\n encU16(args.creatorShareBps),\r\n encU16(args.lpShareBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\r\n *\r\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\r\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\r\n * clamped on-chain to engine-available surplus, and the destination is derived\r\n * rather than passed.\r\n *\r\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\r\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\r\n * PINNED stake program id, so there is nothing for a caller to redirect.\r\n *\r\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\r\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\r\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\r\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\r\n * resolution.\r\n *\r\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\r\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\r\n * stake deployment.\r\n *\r\n * @returns 1-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceReserveToStake();\r\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\r\n * ```\r\n */\r\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\r\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\r\n}\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\r\n *\r\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\r\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\r\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\r\n * wrapper rejects the instruction outright.\r\n *\r\n * Gated on `cfg.marketauth`. The wrapper range-checks against\r\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\r\n * exceeded — the same bound InitMarket applies.\r\n *\r\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\r\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\r\n * (maintenance fee disabled).\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\r\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateMaintenanceFeePerSlotArgs {\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateMaintenanceFeePerSlot(\r\n args: UpdateMaintenanceFeePerSlotArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\r\n encU128(args.maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateTradeFeePolicy instruction data (tag 55).\r\n *\r\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\r\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\r\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\r\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\r\n * (stake tag 28).\r\n *\r\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\r\n * with `read_u128`.\r\n *\r\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\r\n * which left stake tag 28's CPI target unrepresentable from the SDK.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\r\n * ```\r\n */\r\nexport interface UpdateTradeFeePolicyArgs {\r\n tradeFeeBaseBps: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateTradeFeePolicy),\r\n encU64(args.tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * ExpireBackingBucket instruction data (tag 89).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\r\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\r\n * domain: read_u16(&mut rest)? }`) followed by the shared\r\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\r\n *\r\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\r\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\r\n * authority to hold.\r\n *\r\n * ## Why this exists\r\n *\r\n * A realized loss reserves capital as counterparty backing, which opens the\r\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\r\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\r\n * END in all three directions, permanently:\r\n *\r\n * - settling a GAIN against it -> Custom(19) EngineStale\r\n * - reserving a further LOSS -> Custom(21) EngineLockActive\r\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\r\n *\r\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\r\n * no call site that reached the engine's own escape hatch\r\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\r\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\r\n * good. Tag 89 IS that missing call site.\r\n *\r\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\r\n *\r\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\r\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\r\n * once when the bucket opens and is never extended. Seeding a long horizon\r\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\r\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\r\n * incident-response tool: a keeper should scan live markets for domains whose\r\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\r\n * nobody cranks it, the first lapse silently bricks the domain and the failure\r\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\r\n * settlement.\r\n *\r\n * ## Safety\r\n *\r\n * Permissionless is not an authority hole. The engine refuses the transition\r\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\r\n * is read from the runtime `Clock` (via\r\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\r\n * — so no caller can force an early forfeiture. Moves no tokens.\r\n *\r\n * Expiry forfeits the lapsed principal to the junior pool. That is the\r\n * engine's documented expiry semantics, not a haircut invented by this\r\n * instruction; the alternative is the account never settling at all.\r\n *\r\n * ## Failure modes\r\n *\r\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\r\n * resolved/wound-down path reaches the transition through the engine's own\r\n * resolved-close sweep, so re-entering it from outside is refused.\r\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\r\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\r\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\r\n * speculatively on a healthy domain is safe (it just reverts).\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short), u16. Must be\r\n * `< 2 * max_market_slots`.\r\n * @returns 3-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\r\n * const data = encodeExpireBackingBucket({ domain: 0 });\r\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\r\n * // beyond the fee payer.\r\n * ```\r\n */\r\nexport interface ExpireBackingBucketArgs {\r\n domain: number;\r\n}\r\n\r\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ExpireBackingBucket),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n//\r\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\r\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\r\n// 576-byte config — see solana/slab.ts).\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee instruction data (tag 90).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\r\n * percolator-prog `src/v16_program.rs`:\r\n *\r\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\r\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\r\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\r\n * -> total length is EXACTLY 17; any trailing byte is rejected\r\n * encode arm: out.push(90); push_u128(&mut out, amount)\r\n *\r\n * Pays the market creator's accrued trade-fee share out of the market vault to\r\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\r\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\r\n * backstop): before this change the creator leg was credited INTO the backstop,\r\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\r\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\r\n * counter.\r\n *\r\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\r\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\r\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\r\n * `parseWrapperConfigV17` and pass that exact value.\r\n *\r\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\r\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\r\n * the whole instruction fails closed (EngineLockActive); retry with less.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\r\n * `cfg.marketauth`), so claiming still works on a staked market where\r\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\r\n *\r\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\r\n * u64, so anything above u64::MAX is an over-claim).\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketAccount.data);\r\n * // Drain the full claimable balance:\r\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\r\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawCreatorFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCreatorFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n","import {\r\n PublicKey,\r\n AccountMeta,\r\n SYSVAR_CLOCK_PUBKEY,\r\n SYSVAR_RENT_PUBKEY,\r\n SystemProgram,\r\n} from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Account spec for building instruction account metas.\r\n * Each instruction has a fixed ordering that matches the Rust processor.\r\n */\r\nexport interface AccountSpec {\r\n name: string;\r\n signer: boolean;\r\n writable: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// ACCOUNT ORDERINGS - Single source of truth\r\n// ============================================================================\r\n\r\n/**\r\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\r\n */\r\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"mint\", signer: false, writable: false },\r\n { name: \"vault\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"dummyAta\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * InitPortfolio (tag 2): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\r\n * [0] owner signer, writable (portfolio owner; pays for alloc)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n *\r\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\r\n * InitPortfolio does not transfer collateral and does not read the clock.\r\n */\r\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * InitLP: 6 accounts\r\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\r\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\r\n * [0] user signer, writable (LP owner; pays fee)\r\n * [1] slab writable\r\n * [2] userAta writable (collateral source for fee)\r\n * [3] vault writable (collateral destination)\r\n * [4] tokenProgram read-only\r\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\r\n */\r\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Deposit (tag 3): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] sourceToken writable (owner's collateral ATA)\r\n * [4] vaultToken writable (program vault token account)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\r\n */\r\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Withdraw (tag 4): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] destToken writable (owner's collateral ATA — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs token CPI)\r\n * [6] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\r\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\r\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\r\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\r\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\r\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\r\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\r\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\r\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\r\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\r\n */\r\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\r\n { name: \"nftRegistry\", signer: false, writable: false },\r\n { name: \"positionNft\", signer: false, writable: false },\r\n { name: \"signerNftAta\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\r\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\r\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\r\n */\r\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\r\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\r\n}\r\n\r\n/**\r\n * KeeperCrank: 4 accounts\r\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\r\n */\r\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\r\n * [0] owner signer, writable (keeper key; receives liquidation reward)\r\n * [1] market writable (the market-group slab)\r\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\r\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\r\n *\r\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\r\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\r\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\r\n * the same program and have a different key from accounts[2].\r\n *\r\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\r\n * including oracle tail and optional keeper portfolio.\r\n */\r\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * RestartAssetOracle (tag 69): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\r\n * [0] authority signer (asset_admin for the target asset_index)\r\n * [1] market writable (the market-group slab)\r\n *\r\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\r\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\r\n * Permissionless in the sense that any holder of asset_admin can call it.\r\n */\r\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n\r\n/**\r\n * TradeNoCpi (tag 9): 5 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\r\n * [0] signerA signer, writable (party A — portfolio owner)\r\n * [1] signerB signer, writable (party B — portfolio owner)\r\n * [2] market writable (market-group slab; program-owned)\r\n * [3] accountA writable (portfolio A; program-owned)\r\n * [4] accountB writable (portfolio B; program-owned)\r\n *\r\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\r\n * signerB replaces lp (both portfolios must have live owner signers).\r\n */\r\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: true },\r\n { name: \"signerB\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LiquidateAtOracle: 4 accounts\r\n * Note: account[0] is unused but must be present\r\n */\r\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\r\n { name: \"unused\", signer: false, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClosePortfolio (tag 8): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\r\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\r\n *\r\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\r\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\r\n * portfolio and closes the account back to the market slab.\r\n */\r\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\r\n * [0] signer signer, writable (insurance authority for asset 0)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\r\n *\r\n * v12 stale accounts removed: clock sysvar (was at [5]).\r\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\r\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\r\n * per-authority deposit principals; omit for simple vault top-ups.\r\n */\r\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\r\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\r\n * omit for a simple top-up with no ledger tracking)\r\n *\r\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\r\n */\r\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority-OWNED token account — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\r\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\r\n * so it stays callable by the creator wallet after the\r\n * launch flow rotates marketauth to the stake-pool PDA)\r\n * [1] market writable (market-group slab; program-owned)\r\n */\r\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\r\n * unlike tag 50 where it is an optional tail)\r\n * [3] destToken writable (authority-OWNED token account — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [6] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\r\n * [0] signerA signer (party A — portfolio owner)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] accountA writable (portfolio A; program-owned)\r\n * [3] accountB writable (portfolio B; program-owned)\r\n * [4] matcherProg read-only, executable (matcher program)\r\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\r\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\r\n * [7+] tail additional accounts forwarded to matcher CPI\r\n *\r\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\r\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\r\n * market replaces slab name.\r\n */\r\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetRiskThreshold: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAdmin: 2 accounts\r\n */\r\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * AcceptAdmin: 2 accounts (tag 82)\r\n * Second half of two-step admin transfer. The proposed new admin must sign to\r\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\r\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\r\n * [1] slab writable\r\n */\r\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\r\n { name: \"pendingAdmin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CloseSlab: 6 accounts\r\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\r\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\r\n * [0] dest signer, writable (receives rent + drained vault tokens)\r\n * [1] slab writable\r\n * [2] vault writable (token account — drained)\r\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\r\n * [4] destAta writable (dest's token ATA receiving drained tokens)\r\n * [5] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"destAta\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\r\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\r\n * 3-account form: [admin(s+w), slab(w), clock].\r\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\r\n * needs to re-read price during config commit). Default to the 3-account form;\r\n * callers that need oracle re-reads should append the oracle account themselves.\r\n */\r\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetMaintenanceFee: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetOraclePriceCap: 3 accounts.\r\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\r\n * Layout: [admin(s+w), slab(w), clock].\r\n */\r\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ResolveMarket (tag 19): 2 accounts.\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\r\n * `handle_resolve_market` at src/v16_program.rs:12269:\r\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\r\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\r\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\r\n * clock account, and never touches an oracle account at all.\r\n *\r\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\r\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\r\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\r\n * also admin-gated, market-level, no token movement — which is\r\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\r\n * when the program does not require it only widens the account's write lock.\r\n */\r\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\r\n * [0] authority signer, writable (insurance authority)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority's collateral ATA — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\r\n *\r\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\r\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\r\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\r\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\r\n * the handler does a same-instruction accrue_market_to against the fresh\r\n * oracle price to prevent withdrawals against overstated insurance.\r\n * On resolved markets the oracle is frozen — 7 accounts suffice.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"authorityAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\r\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UnpauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\r\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\r\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\r\n// (set_insurance_withdraw_policy), 6876 (update_authority).\r\n// ============================================================================\r\n\r\n/**\r\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10470.\r\n */\r\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SettleAccount (tag 26): 3 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10503.\r\n */\r\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\r\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\r\n * Owner only. No token movement (internal PnL-bucket conversion within the\r\n * same portfolio).\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\r\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\r\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\r\n * at src/v16_program.rs:17469, which reads:\r\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\r\n * [1] market writable — `expect_writable` + `expect_owner`\r\n * [2] portfolio writable — `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\r\n * is no clock account (the handler needs no slot) and no oracle account.\r\n *\r\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\r\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\r\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\r\n * portfolio rent — this instruction moves no lamports at all.\r\n *\r\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\r\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\r\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\r\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\r\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\r\n */\r\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\r\n * Wrapper: src/percolator.rs:9990.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\r\n * Wrapper: src/percolator.rs:6876.\r\n *\r\n * Both the current authority and the new authority must sign. For burn\r\n * (`new_pubkey == default()`) the new account is still passed but does\r\n * not need to sign per wrapper L7036 region.\r\n */\r\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"currentAuthority\", signer: true, writable: false },\r\n { name: \"newAuthority\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// ACCOUNT META BUILDERS\r\n// ============================================================================\r\n\r\n/**\r\n * Build AccountMeta array from spec and provided pubkeys.\r\n *\r\n * Accepts either:\r\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\r\n * - `Record` — named map keyed by account `name` (preferred form)\r\n *\r\n * Named-map form resolves accounts by spec name so callers don't have to\r\n * remember the positional order, and errors clearly on missing names.\r\n */\r\nexport function buildAccountMetas(\r\n spec: readonly AccountSpec[],\r\n keys: PublicKey[] | Record\r\n): AccountMeta[] {\r\n let keysArray: PublicKey[];\r\n\r\n if (Array.isArray(keys)) {\r\n keysArray = keys;\r\n } else {\r\n // Named map: resolve by spec name\r\n keysArray = spec.map((s) => {\r\n const key = (keys as Record)[s.name];\r\n if (!key) {\r\n throw new Error(\r\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\r\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\r\n );\r\n }\r\n return key;\r\n });\r\n }\r\n\r\n if (keysArray.length !== spec.length) {\r\n throw new Error(\r\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\r\n );\r\n }\r\n return spec.map((s, i) => ({\r\n pubkey: keysArray[i],\r\n isSigner: s.signer,\r\n isWritable: s.writable,\r\n }));\r\n}\r\n\r\n/**\r\n * CreateInsuranceMint: 9 accounts\r\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\r\n */\r\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"collateralMint\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"payer\", signer: true, writable: true },\r\n] as const;\r\n\r\n/**\r\n * DepositInsuranceLP: 8 accounts\r\n * Deposit collateral into insurance fund, receive LP tokens.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"depositorAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLP: 8 accounts\r\n * Burn LP tokens and withdraw proportional share of insurance fund.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\r\n *\r\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\r\n *\r\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\r\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\r\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\r\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\r\n *\r\n * Accounts:\r\n * [0] withdrawer signer, read-only\r\n * [1] slab writable\r\n * [2] withdrawerAta writable (collateral destination)\r\n * [3] vault writable (collateral source)\r\n * [4] tokenProgram read-only\r\n * [5] lpVaultMint writable (LP tokens burned from here)\r\n * [6] withdrawerLpAta writable (LP tokens source)\r\n * [7] vaultAuthority read-only (PDA that signs token transfers)\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\r\n */\r\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"creatorLockPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * FundMarketInsurance: 5 accounts (PERC-306)\r\n * Fund per-market isolated insurance balance.\r\n */\r\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceIsolation: 2 accounts (PERC-306)\r\n * Set max % of global fund this market can access.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal: 5 accounts (PERC-309)\r\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\r\n */\r\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"lpVaultState\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\r\n * Burns LP tokens and releases one epoch tranche of SOL.\r\n */\r\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\r\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\r\n */\r\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\r\n * Permissionless — surgically close/reduce the most profitable position\r\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\r\n * pass additional oracle accounts at accounts[4..].\r\n */\r\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs: 2 accounts (tag 51)\r\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\r\n */\r\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ReclaimSlabRent: 2 accounts (tag 52)\r\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\r\n */\r\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: true, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// AuditCrank (tag 53) — Permissionless invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank: 1 account (tag 53)\r\n * Permissionless. Verifies conservation invariants; pauses market on violation.\r\n */\r\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase: 1 account\r\n * Permissionless — no signer required beyond fee payer.\r\n */\r\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dexPool\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * CreateLpVault (tag 74): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\r\n * [0] admin signer, writable (marketauth — pays for PDA creation)\r\n * [1] market read-only (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\r\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\r\n * [4] systemProgram read-only (required for create_account CPI)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\r\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\r\n */\r\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositToLpVault (tag 75): 10 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\r\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] lpMint writable (LP share mint PDA)\r\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\r\n * [5] sourceToken writable (depositor's collateral ATA — source)\r\n * [6] vaultToken writable (program vault token account — destination)\r\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\r\n * [8] tokenProgram read-only\r\n * [9] systemProgram read-only (required for ledger create_account CPI)\r\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n *\r\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\r\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\r\n * and mints the depositor free shares at existing holders' expense. `ledger` at\r\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\r\n * which of the two actually receives the backing.\r\n *\r\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\r\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\r\n * ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\r\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n * [5] systemProgram read-only (required to create a missing target ledger)\r\n *\r\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\r\n * land in, and that pot's ledger is created on first use. Once deposits can be\r\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\r\n * so cranker had to become writable and the system program is now required.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\r\n *\r\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\r\n * carrying ledger principal in lockstep. No tokens move.\r\n *\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\r\n * destination ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry read-only (LpVaultRegistry PDA)\r\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\r\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\r\n * [5] systemProgram read-only\r\n */\r\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: false },\r\n { name: \"fromLedger\", signer: false, writable: true },\r\n { name: \"toLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"challenger\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"attestation\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8110: SetOiImbalanceHardBlock\r\n// ============================================================================\r\n\r\n/**\r\n * SetOiImbalanceHardBlock: 2 accounts\r\n * Sets the OI imbalance hard-block threshold (admin only)\r\n */\r\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-608: Position NFT Instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft: 10 accounts\r\n * Creates a Token-2022 position NFT for an open position.\r\n */\r\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TransferPositionOwnership: 8 accounts\r\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\r\n */\r\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\r\n { name: \"currentOwner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"currentOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwner\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * BurnPositionNft: 7 accounts\r\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\r\n */\r\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetPendingSettlement: 3 accounts\r\n * Keeper/admin sets pending_settlement flag before funding transfer.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ClearPendingSettlement: 3 accounts\r\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"nftProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8111: SetWalletCap\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap: 2 accounts\r\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\r\n */\r\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-SetDexPool: SetDexPool (tag 74)\r\n// ============================================================================\r\n\r\n/**\r\n * SetDexPool: 3 accounts\r\n * Admin pins the approved DEX pool address for a HYPERP market.\r\n * After this call, UpdateHyperpMark rejects any pool that does not match.\r\n */\r\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"poolAccount\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// InitMatcherCtx (tag 83) — v17 wire\r\n//\r\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\r\n// 83. The protocol-fee instructions below were renumbered to 84/85\r\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\r\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\r\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\r\n * [0] lpOwner signer (LP portfolio owner wallet)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\r\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\r\n * [4] matcherProg read-only, executable (the external matcher program)\r\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\r\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\r\n * calling the matcher CPI.\r\n *\r\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\r\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\r\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\r\n */\r\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\r\n *\r\n * Fixed accounts:\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned market account)\r\n *\r\n * Dynamic accounts [2..2+oracle_leg_count]:\r\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\r\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\r\n *\r\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\r\n] as const;\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\r\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushEwmaMark (tag 36): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\r\n */\r\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushAuthMark (tag 63): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\r\n */\r\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK B — SetMatcherConfig account spec (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\r\n * 6 accounts when enabling (enabled=1).\r\n *\r\n * [0] lpOwner signer (portfolio owner)\r\n * [1] market read-only (program-owned; owner-check only)\r\n * [2] lpPortfolio writable (program-owned portfolio)\r\n * [3] matcherProg read-only, executable (required when enabled=1 only)\r\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\r\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\r\n *\r\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\r\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\r\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\r\n */\r\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: true },\r\n // When enabled=1, also pass:\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee (tag 84): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\r\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\r\n * in the instruction data means \"withdraw all currently-available capacity\".\r\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\r\n * domain budgets; the protocol's claim is a separate, non-domain balance).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\r\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\r\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\r\n * seeds [program_id])\r\n * [2] market writable (program-owned market-group slab)\r\n *\r\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\r\n * authority — NOT marketauth, NOT insurance_authority, NOT any\r\n * creator-facing gate. No global fan-out: call once per market.\r\n */\r\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"upgradeAuthority\", signer: true, writable: false },\r\n { name: \"programData\", signer: false, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateFeeSplit (tag 86): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\r\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors the neighbouring marketauth-gated single-field setters\r\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\r\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\r\n *\r\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\r\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\r\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\r\n */\r\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_withdraw_insurance_reserve_to_stake):\r\n * [0] cranker signer (permissionless — any signer, pays fees only)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\r\n * wrapper's PINNED stake program id; its owner is\r\n * asserted BEFORE any byte is read — the forgery gate)\r\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\r\n * [4] vaultToken writable (this market's collateral vault token acct)\r\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\r\n * [6] tokenProgram read-only\r\n *\r\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\r\n * destination; percolator-stake's own AccrueFees is what later credits it.\r\n *\r\n * Failure codes are deliberately distinct so a keeper can tell the cases\r\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\r\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\r\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\r\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"stakePool\", signer: false, writable: false },\r\n { name: \"stakeVault\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\r\n * [0] admin signer (must match cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * ⚠ The instruction payload is a u128, not a u64. See\r\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\r\n */\r\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\r\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\r\n * cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\r\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\r\n * than by StakeInitPool; proxy is stake tag 28.\r\n *\r\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\r\n * the authority normally also being the fee payer. The program itself only\r\n * calls `expect_signer(authority)` — it never writes to this account.\r\n */\r\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\r\n * [0] market writable (program-owned market-group slab)\r\n *\r\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\r\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\r\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\r\n * instruction moves no tokens. The transaction still needs a fee payer, but\r\n * that signer is not an account of this instruction and is not checked against\r\n * anything.\r\n *\r\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\r\n * only by an authority that may be a cold key or a stake-pool PDA. The\r\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\r\n * against the runtime `Clock`), not an authority check. See\r\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\r\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\r\n * Custom(19) bucket not `Fresh`-and-lapsed.\r\n */\r\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee (tag 90): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\r\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\r\n * only the authority the program checks [0] against differs:\r\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account, owned by [0])\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\r\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\r\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\r\n * reflects the authority normally also being the transaction fee payer; the\r\n * program itself only calls expect_signer on it.\r\n *\r\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\r\n * does NOT accept marketauth as an alternate the way\r\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\r\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\r\n * pool claim the creator's revenue. It also means claiming keeps working after\r\n * StakeInitPool, since staking never rotates insurance_operator.\r\n *\r\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\r\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\r\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\r\n * from the loss backstop, so backstop gating does not apply).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\r\n// ============================================================================\r\n\r\nexport const WELL_KNOWN = {\r\n tokenProgram: TOKEN_PROGRAM_ID,\r\n clock: SYSVAR_CLOCK_PUBKEY,\r\n rent: SYSVAR_RENT_PUBKEY,\r\n systemProgram: SystemProgram.programId,\r\n} as const;\r\n","/**\r\n * Percolator v17 program error definitions.\r\n *\r\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\r\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\r\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\r\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\r\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\r\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\r\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\r\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\r\n *\r\n * Ordinals 0-61 read directly off the PercolatorError enum in\r\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\r\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\r\n * tentative\" TODO here is resolved.\r\n *\r\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\r\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Errors 0-29 have completely different names and semantics from v12.\r\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\r\n * - Errors 42-46 are NFT/B-3 (new in v17).\r\n * - v12.x errors 28-65 are entirely removed.\r\n */\r\nexport interface ErrorInfo {\r\n name: string;\r\n hint: string;\r\n}\r\n\r\nexport const PERCOLATOR_ERRORS: Record = {\r\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\r\n 0: {\r\n name: \"InvalidMagic\",\r\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\r\n },\r\n 1: {\r\n name: \"InvalidVersion\",\r\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\r\n },\r\n 2: {\r\n name: \"AlreadyInitialized\",\r\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\r\n },\r\n 3: {\r\n name: \"NotInitialized\",\r\n hint: \"Account is not initialized. Run InitMarket first.\",\r\n },\r\n 4: {\r\n name: \"InvalidAccountKind\",\r\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\r\n },\r\n 5: {\r\n name: \"InvalidAccountLen\",\r\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\r\n },\r\n 6: {\r\n name: \"ExpectedSigner\",\r\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\r\n },\r\n 7: {\r\n name: \"ExpectedWritable\",\r\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\r\n },\r\n 8: {\r\n name: \"Unauthorized\",\r\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\r\n },\r\n 9: {\r\n name: \"InvalidInstruction\",\r\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\r\n },\r\n 10: {\r\n name: \"InvalidMint\",\r\n hint: \"Token mint does not match the market's collateral mint.\",\r\n },\r\n 11: {\r\n name: \"InvalidTokenAccount\",\r\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\r\n },\r\n 12: {\r\n name: \"InvalidVaultAccount\",\r\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\r\n },\r\n 13: {\r\n name: \"InvalidTokenProgram\",\r\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\r\n },\r\n 14: {\r\n name: \"EngineInvalidConfig\",\r\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\r\n },\r\n 15: {\r\n name: \"EngineArithmeticOverflow\",\r\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\r\n },\r\n 16: {\r\n name: \"EngineProvenanceMismatch\",\r\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\r\n },\r\n 17: {\r\n name: \"EngineHiddenLeg\",\r\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\r\n },\r\n 18: {\r\n name: \"EngineInvalidLeg\",\r\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\r\n },\r\n 19: {\r\n name: \"EngineStale\",\r\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\r\n },\r\n 20: {\r\n name: \"EngineBStale\",\r\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\r\n },\r\n 21: {\r\n name: \"EngineLockActive\",\r\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\r\n },\r\n 22: {\r\n name: \"EngineNonProgress\",\r\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\r\n },\r\n 23: {\r\n name: \"EngineRecoveryRequired\",\r\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\r\n },\r\n 24: {\r\n name: \"EngineCounterOverflow\",\r\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\r\n },\r\n 25: {\r\n name: \"EngineCounterUnderflow\",\r\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\r\n },\r\n 26: {\r\n name: \"OracleInvalid\",\r\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\r\n },\r\n 27: {\r\n name: \"OracleStale\",\r\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\r\n },\r\n 28: {\r\n name: \"OracleConfTooWide\",\r\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\r\n },\r\n 29: {\r\n name: \"InvalidOracleKey\",\r\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\r\n },\r\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\r\n 30: {\r\n name: \"LpVaultAlreadyExists\",\r\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\r\n },\r\n 31: {\r\n name: \"LpVaultNotFound\",\r\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\r\n },\r\n 32: {\r\n name: \"LpVaultPaused\",\r\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\r\n },\r\n 33: {\r\n name: \"LpVaultSharesOutstanding\",\r\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\r\n },\r\n 34: {\r\n name: \"LpVaultZeroAmount\",\r\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\r\n },\r\n 35: {\r\n name: \"LpVaultInsufficientShares\",\r\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\r\n },\r\n 36: {\r\n name: \"LpVaultCooldownActive\",\r\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\r\n },\r\n 37: {\r\n name: \"LpVaultOiReservationViolated\",\r\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\r\n },\r\n 38: {\r\n name: \"LpVaultNoFeesToCrank\",\r\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\r\n },\r\n 39: {\r\n name: \"LpVaultSupplyMismatch\",\r\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\r\n },\r\n 40: {\r\n name: \"LpVaultAuthorityMismatch\",\r\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\r\n },\r\n 41: {\r\n name: \"LpVaultZeroSharesMinted\",\r\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\r\n },\r\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\r\n 42: {\r\n name: \"NftRegistryNotFound\",\r\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\r\n },\r\n 43: {\r\n name: \"NftPortfolioNotTransferable\",\r\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\r\n },\r\n 44: {\r\n name: \"NftTransferSelfOrZero\",\r\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\r\n },\r\n 45: {\r\n name: \"NftInvalidMintAuthority\",\r\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\r\n },\r\n 46: {\r\n name: \"NftPortfolioProvenance\",\r\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\r\n },\r\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\r\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\r\n 47: {\r\n name: \"InsuranceWithdrawCooldownActive\",\r\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\r\n },\r\n 48: {\r\n name: \"InsuranceWithdrawCeilingExceeded\",\r\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\r\n },\r\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\r\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\r\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\r\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\r\n // initial-margin failure, previously collapsed into the opaque\r\n // EngineInvalidConfig=14.\r\n 49: {\r\n name: \"EngineInsufficientInitialMargin\",\r\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\r\n },\r\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\r\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\r\n 50: {\r\n name: \"LpVaultDepositBelowMinimumLiquidity\",\r\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\r\n },\r\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\r\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\r\n // a3cb4390).\r\n //\r\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\r\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\r\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\r\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\r\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\r\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\r\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\r\n // EXACTLY and with no tolerance, against the bps floors below.\r\n 51: {\r\n name: \"FeeSplitFloorViolation\",\r\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\r\n },\r\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variants appended after\r\n // FeeSplitFloorViolation=51 on percolator-prog\r\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\r\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\r\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\r\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\r\n 52: {\r\n name: \"FeeSplitSumInvalid\",\r\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\r\n },\r\n 53: {\r\n name: \"NoInsuranceReserveToClaim\",\r\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\r\n },\r\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\r\n // Source: v16_program.rs, same branch. These seven previously ALL returned\r\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\r\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\r\n // destination-resolution now has its own code.\r\n //\r\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\r\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\r\n // removed. That variant existed only on an unmerged branch and was NEVER\r\n // deployed, so no on-chain consumer has ever observed the old meaning.\r\n 54: {\r\n name: \"StakePoolNotBound\",\r\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\r\n },\r\n 55: {\r\n name: \"StakePoolOwnerMismatch\",\r\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\r\n },\r\n 56: {\r\n name: \"StakePoolAuthorityMismatch\",\r\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\r\n },\r\n 57: {\r\n name: \"StakePoolMarketMismatch\",\r\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\r\n },\r\n 58: {\r\n name: \"StakePoolWrapperMismatch\",\r\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\r\n },\r\n 59: {\r\n name: \"StakePoolModeMismatch\",\r\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\r\n },\r\n 60: {\r\n name: \"StakeProgramNotPinned\",\r\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\r\n },\r\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\r\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n 61: {\r\n name: \"AssetSlotAlreadyConfigured\",\r\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\r\n },\r\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\r\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\r\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\r\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\r\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\r\n // wrapper this code is unreachable.\r\n 62: {\r\n name: \"CreatorFeeOverClaim\",\r\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\r\n },\r\n\r\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\r\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\r\n // slot 490057417, verified byte-identical.\r\n 63: {\r\n name: \"LpVaultBackingBucketNotEmpty\",\r\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\r\n },\r\n};\r\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\r\nObject.freeze(PERCOLATOR_ERRORS);\r\n\r\n/**\r\n * Decode a custom program error code to its info.\r\n *\r\n * @param code Custom error code from `custom program error: 0x`.\r\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\r\n */\r\nexport function decodeError(code: number): ErrorInfo | undefined {\r\n return PERCOLATOR_ERRORS[code];\r\n}\r\n\r\n/**\r\n * Get error name from code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\r\n */\r\nexport function getErrorName(code: number): string {\r\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\r\n}\r\n\r\n/**\r\n * Get actionable hint for error code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Actionable hint string, or undefined if not recognized.\r\n */\r\nexport function getErrorHint(code: number): string | undefined {\r\n return PERCOLATOR_ERRORS[code]?.hint;\r\n}\r\n\r\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\r\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\r\n\r\n/**\r\n * Parse a custom program error from transaction logs.\r\n *\r\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\r\n * Returns null if no custom error is found.\r\n *\r\n * @param logs Array of transaction log strings from the RPC response.\r\n * @returns Parsed error with code, name, and hint — or null if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\r\n * if (err) console.error(`${err.name}: ${err.hint}`);\r\n * ```\r\n */\r\nexport function parseErrorFromLogs(logs: string[]): {\r\n code: number;\r\n name: string;\r\n hint?: string;\r\n} | null {\r\n if (!Array.isArray(logs)) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\r\n \"i\",\r\n );\r\n for (const log of logs) {\r\n if (typeof log !== \"string\") {\r\n continue;\r\n }\r\n const match = log.match(re);\r\n if (match) {\r\n const code = parseInt(match[1], 16);\r\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\r\n continue;\r\n }\r\n const info = decodeError(code);\r\n return {\r\n code,\r\n name: info?.name ?? `Unknown(${code})`,\r\n hint: info?.hint,\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Standalone percolator-nft program SDK module.\r\n *\r\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\r\n * separate from the main Percolator program. It handles:\r\n * - MintPositionNft (tag 0)\r\n * - BurnPositionNft (tag 1)\r\n * - SettleFunding (tag 2)\r\n * - GetPositionValue (tag 3)\r\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\r\n * - EmergencyBurn (tag 5)\r\n *\r\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\r\n * PositionNft state : [\"position_nft\", portfolio_account, asset_index_u16_LE]\r\n * Mint authority : [\"mint_authority\"]\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\r\nimport { safeEnv } from \"../config/program-ids.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Program ID\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Allowlist of known NFT program addresses. */\r\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\r\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\r\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\r\n]);\r\n\r\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\r\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\r\n throw new Error(\r\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\r\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\r\n `Pass the programId argument explicitly to bypass env resolution.`,\r\n );\r\n}\r\n\r\n/**\r\n * The standalone percolator-nft program (TransferHook + mint authority).\r\n *\r\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\r\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\r\n * address while every other id in the SDK is devnet, so any consumer importing it built\r\n * transactions against a program that does not exist on devnet and failed late with\r\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\r\n * constant to work around it.\r\n */\r\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\r\n\r\nexport function getNftProgramId(): PublicKey {\r\n return NFT_PROGRAM_ID;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const NFT_IX_TAG = {\r\n MintPositionNft: 0,\r\n BurnPositionNft: 1,\r\n SettleFunding: 2,\r\n GetPositionValue: 3,\r\n ExecuteTransferHook: 4,\r\n EmergencyBurn: 5,\r\n RepairExtraMetas: 6,\r\n ReconcileBurnedNft: 7,\r\n} as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction encoders\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\r\nexport function encodeNftMint(assetIndex: number): Uint8Array {\r\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\r\n const buf = new Uint8Array(3);\r\n buf[0] = NFT_IX_TAG.MintPositionNft;\r\n buf.set(assetIndexBuf, 1);\r\n return buf;\r\n}\r\n\r\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\r\nexport function encodeNftBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\r\n}\r\n\r\n/** Encode SettleFunding (tag 2). Data: tag(1). */\r\nexport function encodeNftSettleFunding(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\r\n}\r\n\r\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\r\nexport function encodeNftEmergencyBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\r\n}\r\n\r\n/**\r\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\r\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\r\n * released) back to the recorded last holder, then closes the PositionNft PDA.\r\n */\r\nexport function encodeNftReconcile(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account meta templates\r\n// ---------------------------------------------------------------------------\r\n\r\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\r\n\r\n/**\r\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\r\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\r\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\r\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\r\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\r\n * `isSigner: undefined` and `isWritable: undefined` for every account\r\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\r\n * both to falsy, so EVERY account in the built instruction ends up\r\n * non-signer/read-only. The NFT program's own writable/signer checks then\r\n * reject the transaction (confirmed live against the deployed NFT program:\r\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\r\n * CPI — matching its `if !nft_pda.is_writable { return\r\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\r\n *\r\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\r\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\r\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\r\n * these arrays and working — the only prior working reference\r\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\r\n * bypassing the mismatch entirely.\r\n */\r\nexport function buildNftAccountMetas(\r\n spec: readonly AccountMeta[],\r\n keys: readonly PublicKey[],\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n if (keys.length !== spec.length) {\r\n throw new Error(\r\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\r\n );\r\n }\r\n return spec.map((code, i) => ({\r\n pubkey: keys[i],\r\n isSigner: code === \"s\" || code === \"sw\",\r\n isWritable: code === \"w\" || code === \"sw\",\r\n }));\r\n}\r\n\r\n/**\r\n * Account metas for MintPositionNft (tag 0). 12 accounts.\r\n *\r\n * 0. [signer, writable] payer / position owner\r\n * 1. [writable] PositionNft PDA (created)\r\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\r\n * 3. [writable] Owner's NFT ATA (created)\r\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [] Associated token account program\r\n * 8. [] System program\r\n * 9. [writable] ExtraAccountMetaList PDA\r\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\r\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\r\n *\r\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\r\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\r\n * writable and #10/#11 are required.\r\n */\r\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\r\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint,\r\n * PositionNft PDA and ExtraAccountMetaList rent)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint (supply → 0)\r\n * 3. [writable] Holder's NFT ATA (closed)\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n *\r\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\r\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\r\n */\r\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint\r\n * 3. [writable] Holder's NFT ATA\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n */\r\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for ReconcileBurnedNft (tag 7, #138). 7 accounts. Permissionless.\r\n *\r\n * 0. [writable] PositionNft PDA (closed)\r\n * 1. [] NFT mint (Token-2022 — supply must be 0)\r\n * 2. [writable] Portfolio account (escrow released to the last holder)\r\n * 3. [] Mint authority PDA (unwrap CPI signer)\r\n * 4. [] Per-market NftRegistry PDA\r\n * 5. [] Percolator wrapper program (unwrap CPI target)\r\n * 6. [writable] Recorded last-holder wallet (escrow + PDA-rent recipient)\r\n */\r\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\r\n \"w\", \"r\", \"w\", \"r\", \"r\", \"r\", \"w\",\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// PDA derivation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\nfunction u16Buf(value: number, label: string): Uint8Array {\r\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\r\n throw new Error(`${label} must be a u16`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, true);\r\n return buf;\r\n}\r\n\r\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\r\n const v = typeof value === \"bigint\" ? value : BigInt(value);\r\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\r\n throw new Error(`${label} must be a u64`);\r\n }\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, v, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive the PositionNft state PDA.\r\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n *\r\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\r\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\r\n * engine reuses across close/re-open of the same asset and which therefore\r\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\r\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\r\n * NFT's stored `marketIdAtMint` for any later op.\r\n */\r\nexport function deriveNftPda(\r\n portfolioAccount: PublicKey,\r\n marketId: bigint | number,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\r\n programId,\r\n );\r\n}\r\n\r\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\r\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\r\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\r\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\r\n\r\n/**\r\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\r\n */\r\nexport function deriveNftMint(\r\n _portfolioAccount: PublicKey,\r\n _assetIndex: number,\r\n _programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\r\n}\r\n\r\n/**\r\n * Derive the program-wide mint authority PDA.\r\n * Seeds: [\"mint_authority\"]\r\n */\r\nexport function deriveMintAuthority(\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"mint_authority\")],\r\n programId,\r\n );\r\n}\r\n\r\n/**\r\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\r\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\r\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\r\n * close it and refund its rent to the holder.\r\n */\r\nexport function deriveExtraAccountMetas(\r\n nftMint: PublicKey,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\r\n programId,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account parser\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\r\n *\r\n * [0..8] magic u64 (\"PERCNFT\\0\")\r\n * [8] version u8\r\n * [9] bump u8\r\n * [10..42] portfolio_account [u8; 32]\r\n * [42..74] nft_mint [u8; 32]\r\n * [74..78] asset_index u32 LE\r\n * [78] side_at_mint u8\r\n * [79..95] basis_pos_q_at_mint i128\r\n * [95..111] f_snap_at_mint i128\r\n * [111..119] market_id_at_mint u64\r\n * [119..127] epoch_snap_at_mint u64\r\n * [127..159] position_owner_at_mint [u8; 32]\r\n * [159..167] minted_at i64\r\n * [167..199] _reserved\r\n */\r\nexport const POSITION_NFT_STATE_LEN = 199;\r\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\r\nconst POSITION_NFT_VERSION = 2;\r\n\r\nexport interface PositionNftState {\r\n version: number;\r\n bump: number;\r\n portfolioAccount: PublicKey;\r\n nftMint: PublicKey;\r\n assetIndex: number;\r\n sideAtMint: number;\r\n basisPosQAtMint: bigint;\r\n fSnapAtMint: bigint;\r\n marketIdAtMint: bigint;\r\n epochSnapAtMint: bigint;\r\n positionOwnerAtMint: PublicKey;\r\n /** Backward-compatible alias for positionOwnerAtMint. */\r\n positionOwner: PublicKey;\r\n mintedAt: bigint;\r\n}\r\n\r\n/**\r\n * Read a little-endian signed i128 from a DataView at `offset`.\r\n *\r\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\r\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\r\n * value is set the result is negative and two's-complement sign extension is\r\n * applied explicitly.\r\n *\r\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\r\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\r\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\r\n * shifted high half collapses the sign bit into all high bits and corrupts the\r\n * result.\r\n *\r\n * @param view DataView wrapping the raw account bytes\r\n * @param offset Byte offset of the i128 field (little-endian)\r\n * @returns Signed BigInt in the range [-2^127, 2^127)\r\n */\r\nfunction readI128FromView(view: DataView, offset: number): bigint {\r\n const lo = view.getBigUint64(offset, true);\r\n const hi = view.getBigUint64(offset + 8, true);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Parse a PositionNft account from raw bytes.\r\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\r\n */\r\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\r\n if (data.length < POSITION_NFT_STATE_LEN) {\r\n throw new Error(\r\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\r\n );\r\n }\r\n\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n const magic = view.getBigUint64(0, true);\r\n if (magic !== POSITION_NFT_MAGIC) {\r\n throw new Error(\"PositionNft account has invalid magic\");\r\n }\r\n if (data[8] !== POSITION_NFT_VERSION) {\r\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\r\n }\r\n\r\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\r\n\r\n return {\r\n version: data[8],\r\n bump: data[9],\r\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\r\n nftMint: new PublicKey(data.subarray(42, 74)),\r\n assetIndex: view.getUint32(74, true),\r\n sideAtMint: data[78],\r\n basisPosQAtMint: readI128FromView(view, 79),\r\n fSnapAtMint: readI128FromView(view, 95),\r\n marketIdAtMint: view.getBigUint64(111, true),\r\n epochSnapAtMint: view.getBigUint64(119, true),\r\n positionOwnerAtMint,\r\n positionOwner: positionOwnerAtMint,\r\n mintedAt: view.getBigInt64(159, true),\r\n };\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\n/**\r\n * Read an environment variable safely. Returns `undefined` in browser\r\n * environments where `process` is not defined, avoiding a\r\n * `ReferenceError` crash at import time.\r\n */\r\nexport function safeEnv(key: string): string | undefined {\r\n try {\r\n return typeof process !== \"undefined\" && process?.env\r\n ? process.env[key]\r\n : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Centralized PROGRAM_ID configuration\r\n * \r\n * Default to environment variable, then fall back to network-specific defaults.\r\n * This prevents hard-coded program IDs scattered across the codebase.\r\n */\r\n\r\nexport const PROGRAM_IDS = {\r\n devnet: {\r\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\r\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\r\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n },\r\n mainnet: {\r\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\r\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\r\n },\r\n} as const;\r\nObject.freeze(PROGRAM_IDS.devnet);\r\nObject.freeze(PROGRAM_IDS.mainnet);\r\nObject.freeze(PROGRAM_IDS);\r\n\r\n/**\r\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\r\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\r\n * and upgraded in place at the same address).\r\n *\r\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\r\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\r\n * markets — they were not migrated in place, so anything still pointed at them\r\n * (e.g. the percolator-launch playground config, which hardcodes its own program\r\n * ID rather than reading this module) keeps working against the old markets until\r\n * it is explicitly cut over to this fresh triple. That playground cutover is a\r\n * separate, later step — NOT performed by this change.\r\n */\r\nexport const PROGRAM_IDS_V17 = {\r\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\r\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\r\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\r\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\r\n} as const;\r\nObject.freeze(PROGRAM_IDS_V17);\r\n\r\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\r\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\r\n\r\nexport type Network = \"devnet\" | \"mainnet\";\r\n\r\n/** Allowlist of legitimate percolator program addresses (all networks). */\r\nconst KNOWN_PROGRAM_IDS = new Set([\r\n PROGRAM_IDS.devnet.percolator,\r\n PROGRAM_IDS.mainnet.percolator,\r\n PROGRAM_IDS_V17.percolator,\r\n]);\r\n\r\n/** Allowlist of legitimate matcher program addresses (all networks). */\r\nconst KNOWN_MATCHER_IDS = new Set([\r\n PROGRAM_IDS.devnet.matcher,\r\n PROGRAM_IDS.mainnet.matcher,\r\n]);\r\n\r\n/**\r\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\r\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\r\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\r\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\r\n * during pre-deploy / devnet testing — which the allowlist alone would break.\r\n */\r\nfunction programOverrideOptIn(): boolean {\r\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\r\n}\r\n\r\n/**\r\n * Get the Percolator program ID for the current network\r\n * \r\n * Priority:\r\n * 1. PROGRAM_ID env var (explicit override)\r\n * 2. Network-specific default (NETWORK env var)\r\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\r\n */\r\nexport function getProgramId(network?: Network): PublicKey {\r\n // #249: an explicit `network` argument is authoritative and must NOT be silently\r\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\r\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\r\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\r\n if (network === undefined) {\r\n const override = safeEnv(\"PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\r\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].percolator;\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the Matcher program ID for the current network\r\n */\r\nexport function getMatcherProgramId(network?: Network): PublicKey {\r\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\r\n if (network === undefined) {\r\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\r\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].matcher;\r\n\r\n if (!programId) {\r\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\r\n }\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the current network from environment.\r\n *\r\n * SECURITY (PERC-697): Removed silent mainnet default.\r\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\r\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\r\n *\r\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\r\n * Production deployments always set NETWORK explicitly via Railway/env.\r\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\r\n * enforces FORCE_MAINNET=1.\r\n */\r\nexport function getCurrentNetwork(): Network {\r\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\r\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\r\n return \"mainnet\";\r\n }\r\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\r\n return \"devnet\";\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\n\r\n// =============================================================================\r\n// Browser-compatible read helpers using DataView\r\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\r\n// =============================================================================\r\n\r\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\n/** Read a single unsigned byte at `off`. */\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n if (off >= data.length) {\r\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\r\n }\r\n return data[off];\r\n}\r\n/** Read a little-endian u16 at `off`. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\n/** Read a little-endian u32 at `off`. */\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint32(off, true);\r\n}\r\n/** Read a little-endian u64 at `off` as a BigInt. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\n/** Read a little-endian signed i64 at `off` as a BigInt. */\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\n\r\n// =============================================================================\r\n// Helper: read signed/unsigned i128 from buffer\r\n// =============================================================================\r\n\r\n/**\r\n * Read a little-endian signed i128 at `offset`.\r\n * Composed from two u64 halves; sign-extends if the high bit is set.\r\n */\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// =============================================================================\r\n// Slab Layout Version Detection\r\n// =============================================================================\r\n// The deployed devnet program uses a different struct layout (V0) than the SDK\r\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\r\n// struct changes that have NOT been deployed to devnet yet.\r\n//\r\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\r\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\r\n// - RiskParams: 56 bytes (basic fields only)\r\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\r\n// - No partial liquidation field in Account (240 bytes)\r\n//\r\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\r\n// - InsuranceFund: expanded with isolation fields (72 bytes)\r\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\r\n// - Has mark_price, long_oi/short_oi, emergency fields\r\n// - Account has last_partial_liquidation_slot (248 bytes)\r\n// =============================================================================\r\n\r\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\r\n\r\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\r\nexport const SLAB_MAGIC = MAGIC;\r\n\r\n// Flag bits in header._padding[0] at offset 13\r\nconst FLAG_RESOLVED = 1 << 0;\r\n\r\n/**\r\n * Full slab layout descriptor. Returned by detectSlabLayout().\r\n * All engine field offsets are relative to engineOff.\r\n */\r\nexport interface SlabLayout {\r\n version: 0 | 1 | 2;\r\n headerLen: number;\r\n configOffset: number;\r\n configLen: number;\r\n reservedOff: number; // offset of _reserved in header\r\n engineOff: number;\r\n accountSize: number;\r\n maxAccounts: number;\r\n bitmapWords: number;\r\n accountsOff: number; // absolute offset of accounts array in slab\r\n\r\n // Engine field offsets (relative to engineOff)\r\n engineInsuranceOff: number;\r\n engineParamsOff: number;\r\n paramsSize: number;\r\n engineCurrentSlotOff: number;\r\n engineFundingIndexOff: number;\r\n engineLastFundingSlotOff: number;\r\n engineFundingRateBpsOff: number;\r\n engineMarkPriceOff: number; // -1 if not present (V0)\r\n engineLastCrankSlotOff: number;\r\n engineMaxCrankStalenessOff: number;\r\n engineTotalOiOff: number;\r\n engineLongOiOff: number; // -1 if not present (V0)\r\n engineShortOiOff: number; // -1 if not present (V0)\r\n engineCTotOff: number;\r\n enginePnlPosTotOff: number;\r\n engineLiqCursorOff: number;\r\n engineGcCursorOff: number;\r\n engineLastSweepStartOff: number;\r\n engineLastSweepCompleteOff: number;\r\n engineCrankCursorOff: number;\r\n engineSweepStartIdxOff: number;\r\n engineLifetimeLiquidationsOff: number;\r\n engineLifetimeForceClosesOff: number;\r\n engineNetLpPosOff: number;\r\n engineLpSumAbsOff: number;\r\n engineLpMaxAbsOff: number;\r\n engineLpMaxAbsSweepOff: number;\r\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\r\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\r\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\r\n engineBitmapOff: number; // relative to engineOff\r\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\r\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\r\n\r\n // Insurance fund layout\r\n hasInsuranceIsolation: boolean;\r\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\r\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\r\n\r\n // Optional fallback for engines without a stored mark_price field (v12.17+):\r\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\r\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\r\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\r\n // predate v12.17 and already expose a real engine.mark_price.\r\n configMarkEwmaOff?: number;\r\n}\r\n\r\n// ---- V0 layout constants (deployed devnet program) ----\r\nconst V0_HEADER_LEN = 72;\r\nconst V0_CONFIG_LEN = 408;\r\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\r\nconst V0_ACCOUNT_SIZE = 240;\r\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\r\n\r\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\r\n// V0 RiskParams: 56 bytes → runtime state at 104\r\nconst V0_ENGINE_PARAMS_OFF = 48;\r\nconst V0_PARAMS_SIZE = 56;\r\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\r\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\r\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\r\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\r\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\r\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\r\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\r\nconst V0_ENGINE_C_TOT_OFF = 176;\r\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\r\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\r\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\r\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\r\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\r\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\r\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\r\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\r\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\r\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\r\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\r\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\r\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\r\nconst V0_ENGINE_BITMAP_OFF = 320;\r\n\r\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\r\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\r\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\r\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\r\nconst V1_HEADER_LEN = 104;\r\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\r\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\r\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\r\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\r\nconst V1_ENGINE_OFF_LEGACY = 640;\r\nconst V1_ACCOUNT_SIZE = 248;\r\nconst V1_RESERVED_OFF = 80;\r\n\r\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\r\n// V1 RiskParams: 288 bytes → runtime state at 360\r\nconst V1_ENGINE_PARAMS_OFF = 72;\r\nconst V1_PARAMS_SIZE = 288;\r\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\r\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\r\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\r\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\r\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\r\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\r\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\r\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\r\nconst V1_ENGINE_LONG_OI_OFF = 456;\r\nconst V1_ENGINE_SHORT_OI_OFF = 472;\r\nconst V1_ENGINE_C_TOT_OFF = 488;\r\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\r\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\r\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\r\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\r\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\r\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\r\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\r\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\r\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\r\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\r\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\r\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\r\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\r\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\r\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\r\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\r\nconst V1_ENGINE_BITMAP_OFF = 656;\r\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\r\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\r\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\r\n// These corrected values must be used for actual byte-level parsing.\r\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\r\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\r\n\r\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\r\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\r\n// Key differences:\r\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\r\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\r\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\r\n// - Bitmap at engine+624 (not 656)\r\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\r\nconst V1D_CONFIG_LEN = 320;\r\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\r\nconst V1D_ACCOUNT_SIZE = 248;\r\n\r\n// V1D engine field offsets (relative to engineOff):\r\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\r\nconst V1D_ENGINE_INSURANCE_OFF = 16;\r\nconst V1D_ENGINE_PARAMS_OFF = 96;\r\nconst V1D_PARAMS_SIZE = 288;\r\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\r\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\r\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\r\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\r\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\r\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\r\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\r\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\r\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\r\nconst V1D_ENGINE_LONG_OI_OFF = 480;\r\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\r\nconst V1D_ENGINE_C_TOT_OFF = 512;\r\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\r\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\r\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\r\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\r\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\r\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\r\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\r\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\r\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\r\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\r\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\r\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\r\nconst V1D_ENGINE_BITMAP_OFF = 624;\r\n\r\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\r\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\r\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\r\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\r\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\r\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\r\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\r\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\r\nconst V2_HEADER_LEN = 104;\r\nconst V2_CONFIG_LEN = 496;\r\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\r\nconst V2_ACCOUNT_SIZE = 248;\r\nconst V2_ENGINE_BITMAP_OFF = 432;\r\n\r\n// V2 engine field offsets (relative to engineOff)\r\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\r\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\r\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\r\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\r\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\r\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\r\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\r\nconst V2_ENGINE_C_TOT_OFF = 424;\r\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\r\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\r\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\r\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\r\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\r\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\r\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\r\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\r\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\r\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\r\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\r\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\r\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\r\n\r\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\r\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\r\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\r\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\r\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\r\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\r\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\r\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\r\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\r\n//\r\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\r\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\r\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\r\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\r\n// Prior value of 1006 was an arithmetic transcription error.\r\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\r\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\r\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\r\n\r\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\r\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\r\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\r\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\r\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\r\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\r\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\r\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\r\n\r\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\r\nconst V_ADL_PARAMS_SIZE = 336;\r\n\r\n// V_ADL engine field offsets (relative to engineOff=624):\r\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\r\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\r\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\r\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\r\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\r\n// PERC-8270 new fields at 472-504:\r\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\r\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\r\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\r\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\r\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\r\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\r\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\r\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\r\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\r\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\r\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\r\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\r\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\r\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\r\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\r\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\r\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\r\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\r\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\r\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\r\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\r\n// ADL side state (PERC-8268, 224 bytes):\r\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\r\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\r\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\r\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\r\n// Then LP aggregates:\r\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\r\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\r\n// emergency fields:\r\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\r\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\r\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\r\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\r\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\r\n\r\n// V_ADL account field offsets (relative to account slot start):\r\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\r\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\r\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\r\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\r\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\r\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\r\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\r\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\r\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\r\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\r\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\r\n\r\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\r\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\r\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\r\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\r\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\r\n// dynamic fee tiers, fee splits).\r\n// Engine field ordering completely reorganized from V_ADL.\r\n// All values verified by cargo build-sbf compile-time assertions.\r\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\r\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\r\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\r\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\r\n// Those fields exist in percolator-core but NOT in the deployed binary.\r\n//\r\n// HOST constants below are for aarch64 test builds (percolator-core).\r\n// SBF constants are for the actual deployed program.\r\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\r\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\r\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\r\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\r\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\r\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\r\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\r\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\r\nconst V12_1_ENGINE_PARAMS_OFF = 96;\r\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\r\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\r\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\r\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\r\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\r\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\r\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\r\nconst V12_1_SBF_OFF_C_TOT = 248;\r\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\r\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\r\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\r\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\r\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\r\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\r\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\r\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\r\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\r\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\r\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\r\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\r\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\r\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\r\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\r\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\r\n// Bitmap (used field): 584\r\n// Fields NOT present in deployed program (return -1):\r\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\r\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\r\n//\r\n// HOST engine field offsets (percolator-core, for test builds):\r\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\r\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\r\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\r\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\r\nconst V12_1_ENGINE_C_TOT_OFF = 480;\r\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\r\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\r\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\r\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\r\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\r\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\r\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\r\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\r\n// HOST-only fields (percolator-core has these, deployed percolator does not):\r\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\r\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\r\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\r\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\r\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\r\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\r\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\r\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\r\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\r\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\r\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\r\n// V12_1 account field offsets (relative to account slot start):\r\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\r\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\r\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\r\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\r\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\r\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\r\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\r\n\r\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\r\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\r\n// SBF layout (u128 align=8):\r\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\r\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\r\n// → fees_earned_total(@272) = 288 bytes\r\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\r\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\r\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\r\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\r\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\r\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\r\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\r\n\r\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\r\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\r\n// explicitly sized, no pointer-derived alignment differences).\r\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\r\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\r\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\r\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\r\n// overflow_newest_present(u8@4384).\r\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\r\n// Field max_accounts moved to offset 24, insurance_floor at 144.\r\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\r\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\r\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\r\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\r\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\r\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\r\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\r\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\r\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\r\n\r\n// V12_15 account field offsets (relative to account slot start):\r\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\r\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\r\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\r\nconst V12_15_ACCT_PNL_OFF = 32; // i128\r\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\r\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\r\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\r\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\r\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\r\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\r\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\r\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\r\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\r\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\r\n\r\n// V12_15 RiskParams offsets (relative to params base):\r\n// sizeof(RiskParams) = 192\r\nconst V12_15_PARAMS_SIZE = 192;\r\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\r\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\r\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\r\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\r\n\r\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\r\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\r\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\r\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\r\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\r\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\r\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\r\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\r\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\r\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\r\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\r\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\r\nconst V12_15_ENGINE_BITMAP_OFF = 862;\r\n\r\n// V12_15 size map for layout detection\r\nconst V12_15_SIZES = new Map();\r\n\r\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\r\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\r\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\r\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\r\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\r\n// pending_present/remaining_q/horizon/created_slot.\r\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\r\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\r\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\r\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\r\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\r\n\r\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\r\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\r\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\r\n// _new_fields_pad, pending_admin[32]).\r\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\r\n// size_of::() = 512 (both native and SBF — u128 fields happen\r\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\r\n\r\n// Native (i128 align=16)\r\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\r\nconst V12_17_ACCOUNT_SIZE = 368;\r\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\r\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\r\nconst V12_17_RISK_BUF_LEN = 160;\r\n// Per-account generation table appended after RISK_BUF in percolator-prog.\r\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\r\nconst V12_17_GEN_TABLE_ENTRY = 8;\r\n\r\n// SBF (i128 align=8)\r\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\r\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\r\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\r\n\r\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\r\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\r\nconst V12_17_ACCT_KIND_OFF = 16; // u8\r\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\r\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\r\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\r\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\r\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\r\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\r\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\r\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\r\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\r\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\r\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\r\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\r\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\r\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\r\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\r\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\r\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\r\n\r\n// V12_17 RiskEngine field offsets (native, relative to engine start)\r\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\r\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\r\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\r\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\r\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\r\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\r\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\r\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\r\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\r\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\r\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\r\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\r\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\r\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\r\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\r\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\r\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\r\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\r\n\r\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\r\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\r\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\r\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\r\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\r\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\r\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\r\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\r\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\r\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\r\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\r\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\r\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\r\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_17 size map for layout detection\r\nconst V12_17_SIZES = new Map();\r\n\r\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\r\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\r\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\r\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\r\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\r\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\r\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\r\nconst V1M_ACCOUNT_SIZE = 248;\r\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\r\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\r\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\r\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\r\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\r\n\r\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\r\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\r\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\r\n// min_nonzero_im_req(u128=16) = +48 total\r\nconst V1M_PARAMS_SIZE = 336;\r\n\r\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\r\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\r\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\r\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\r\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\r\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\r\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\r\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\r\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\r\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\r\nconst V1M_ENGINE_LONG_OI_OFF = 504;\r\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\r\nconst V1M_ENGINE_C_TOT_OFF = 536;\r\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\r\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\r\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\r\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\r\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\r\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\r\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\r\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\r\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\r\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\r\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\r\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\r\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\r\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\r\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\r\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\r\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\r\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\r\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\r\n// which is invalid for a [u64; N] array under #[repr(C)].\r\nconst V1M_ENGINE_BITMAP_OFF = 720;\r\n\r\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\r\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\r\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\r\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\r\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\r\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\r\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\r\n// New runtime fields inserted between fundingRateBps and markPrice:\r\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\r\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\r\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\r\n// +504: lastCrankSlot, +512: maxCrankStaleness\r\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\r\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\r\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\r\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\r\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\r\n\r\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\r\n// (used by reinit-slab and other scripts). These refer to V1 layout.\r\nexport const ENGINE_OFF = V1_ENGINE_OFF;\r\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\r\n\r\n// ---- Known slab sizes per version and tier ----\r\n\r\n/**\r\n * Compute the total byte size of a slab given its layout parameters.\r\n * Used to pre-populate the known-size lookup maps at module load time.\r\n */\r\nfunction computeSlabSize(\r\n engineOff: number,\r\n bitmapOff: number,\r\n accountSize: number,\r\n maxAccounts: number,\r\n // postBitmap bytes immediately after the free-slot bitmap:\r\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\r\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\r\n postBitmap = 18,\r\n): number {\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return engineOff + accountsOff + maxAccounts * accountSize;\r\n}\r\n\r\nconst TIERS = [64, 256, 1024, 4096] as const;\r\n\r\n// Pre-compute known slab sizes for fast lookup\r\nconst V0_SIZES = new Map();\r\nconst V1_SIZES = new Map();\r\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\r\nconst V1_SIZES_LEGACY = new Map();\r\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\r\nconst V1D_SIZES = new Map();\r\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\r\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\r\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\r\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\r\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\r\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\r\nconst V2_SIZES = new Map();\r\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\r\nconst V1M_SIZES = new Map();\r\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\nconst V_ADL_SIZES = new Map();\r\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\r\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n// No disambiguation probe required — size-based detection works correctly.\r\nconst V1M2_SIZES = new Map();\r\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\r\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\r\nconst V_SETDEXPOOL_SIZES = new Map();\r\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\r\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\r\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\r\nconst V12_1_SIZES = new Map();\r\nconst V1D_SIZES_LEGACY = new Map();\r\nfor (const n of TIERS) {\r\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\r\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\r\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\r\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\r\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\r\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\r\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\r\n // Disambiguation requires peeking at the version field in the slab header.\r\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\r\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\r\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\r\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\r\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\r\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\r\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\r\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\r\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\r\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\r\n // e.g. n=4096 → 1288336 bytes.\r\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\r\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\r\n // Register BOTH host-computed and SBF-empirical sizes for detection.\r\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\r\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\r\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\r\n}\r\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\r\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\r\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\r\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\r\n\r\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\r\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\r\n// SBF: Account align=8 → accountsOff alignment is 8.\r\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\r\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\r\nconst V12_17_TIERS = [256, 1024, 4096] as const;\r\nfor (const n of V12_17_TIERS) {\r\n const bitmapWords = Math.ceil(n / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = n * 2;\r\n\r\n // Native (i128 align=16, Account align=16)\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(nativeSize, n);\r\n\r\n // SBF (i128 align=8, Account align=8)\r\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\r\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(sbfSize, n);\r\n}\r\n\r\n// ---- V12_19 layout constants ----\r\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\r\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\r\n// below comes from a Rust compile-error message that revealed the real SBF\r\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\r\n//\r\n// V12_19 vs V12_17 SBF differences:\r\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\r\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\r\n// - ENGINE_OFF: 584 -> 616\r\n// - ACCOUNT_SIZE: 352 -> 360\r\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\r\n// - RiskEngine grew substantially; accounts now inline within engine struct.\r\nconst V12_19_HEADER_LEN_SBF = 136;\r\nconst V12_19_CONFIG_LEN = 480;\r\nconst V12_19_ENGINE_OFF_SBF = 616;\r\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\r\nconst V12_19_SBF_RISK_BUF_LEN = 160;\r\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\r\n\r\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\r\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\r\n// MAX_ACCOUNTS; small (256) shown here.\r\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\r\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\r\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\r\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\r\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\r\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\r\n\r\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\r\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\r\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\r\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\r\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\r\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\r\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\r\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\r\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\r\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\r\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\r\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\r\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\r\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\r\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\r\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\r\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\r\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\r\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\r\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\r\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\r\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\r\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\r\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\r\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\r\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\r\n\r\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\r\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\r\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\r\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\r\n// + (8-byte align pad) + N*360 (accounts).\r\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\r\n// (mainnet probe-confirmed), medium=376432, large=1495024.\r\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\r\nconst V12_19_SIZES = new Map([\r\n [26872, 64], // --features micro (derived)\r\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\r\n [376432, 1024], // --features medium (derived)\r\n [1495024, 4096], // default features / large (derived)\r\n]);\r\n\r\n/**\r\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\r\n *\r\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\r\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\r\n * 736 area to same offset but the post-bitmap region now contains both\r\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\r\n * before the inline accounts.\r\n *\r\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\r\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\r\n * linearly with MAX_ACCOUNTS.\r\n */\r\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\r\n // Compute layout-dependent offsets for this tier.\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\r\n const freeHeadOff = numUsedOff + 2; // after num_used u16\r\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\r\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\r\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\r\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\r\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\r\n\r\n // Inherit Account-internal field offsets from V12_17 (they're the same since\r\n // the Account struct definition is identical between v12.17 and v12.19;\r\n // the +8 byte size diff is from trailing padding, not field reordering).\r\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\r\n\r\n return {\r\n ...base,\r\n headerLen: V12_19_HEADER_LEN_SBF,\r\n configLen: V12_19_CONFIG_LEN,\r\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\r\n engineOff: V12_19_ENGINE_OFF_SBF,\r\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\r\n accountsOff,\r\n bitmapWords,\r\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\r\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\r\n // V12_19-specific engine field offsets (probe-confirmed):\r\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\r\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\r\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\r\n // last_market_slot replaces V12_17 last_crank_slot semantics.\r\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\r\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\r\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\r\n };\r\n}\r\n\r\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\r\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\r\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\r\n// Bitmap at engine+584 (used field in RiskEngine).\r\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\r\nconst V12_1_SBF_ENGINE_OFF = 616;\r\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\r\n V12_1_SIZES.set(total, n);\r\n}\r\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\r\nconst V12_1_EP_SIZES = new Map();\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\r\n V12_1_EP_SIZES.set(total, n);\r\n}\r\n\r\n/**\r\n * V2 slab tier sizes (small and large) for discovery.\r\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\r\n */\r\nexport const SLAB_TIERS_V2 = Object.freeze({\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\r\n} as const);\r\n\r\n/**\r\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\r\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\r\n */\r\nexport const SLAB_TIERS_V1M: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M);\r\n\r\n/**\r\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\r\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\r\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\r\n */\r\nexport const SLAB_TIERS_V1M2: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M2);\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\r\n */\r\nexport const SLAB_TIERS_V_ADL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_ADL);\r\n\r\n/**\r\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\r\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\r\n */\r\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\r\n const isV0 = version === 0;\r\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\r\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\r\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\r\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\r\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\r\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\r\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\r\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\r\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\r\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\r\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version,\r\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\r\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\r\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\r\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: actualBitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: !isV0,\r\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\r\n * Uses correct field offsets derived from on-chain probing.\r\n *\r\n * @param maxAccounts - Number of account slots in the slab\r\n * @param postBitmap - Bytes after the bitmap before next_free array.\r\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\r\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\r\n */\r\n/**\r\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\r\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\r\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\r\n */\r\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\r\n const engineOff = V1D_ENGINE_OFF;\r\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\r\n const accountSize = V1D_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1D_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\r\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\r\n paramsSize: V1D_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: -1, // not present in deployed V1\r\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\r\n engineEmergencyOiModeOff: -1, // not present in deployed V1\r\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\r\n engineLastBreakerSlotOff: -1, // not present in deployed V1\r\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\r\n postBitmap,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\r\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V2 (BPF intermediate layout).\r\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\r\n */\r\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\r\n const engineOff = V2_ENGINE_OFF;\r\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\r\n const accountSize = V2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V2_HEADER_LEN,\r\n configOffset: V2_HEADER_LEN,\r\n configLen: V2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\r\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\r\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: -1, // V2 has no mark_price\r\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: -1, // V2 has no long_oi\r\n engineShortOiOff: -1, // V2 has no short_oi\r\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\r\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\r\n * and trade_twap runtime fields push the bitmap to offset 726.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\r\n */\r\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M_ENGINE_OFF;\r\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\r\n paramsSize: V1M_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\r\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\r\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\r\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\r\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\r\n */\r\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M2_ENGINE_OFF;\r\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\r\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n *\r\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\r\n * large (4096 accounts): 1288320 bytes\r\n * medium (1024 accounts): 323320 bytes\r\n * small (256 accounts): 82064 bytes\r\n */\r\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\r\n const engineOff = V_ADL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_ADL_CONFIG_LEN, // 520\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\r\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\r\n * e.g. large (4096 accts) = 1288336 bytes.\r\n */\r\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\r\n\r\n/**\r\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\r\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\r\n * Verified by cargo build-sbf compile-time assertions.\r\n */\r\nexport const SLAB_TIERS_V12_1: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_1);\r\n\r\n/**\r\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\r\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\r\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\r\n * Account layout completely redesigned with reserve cohort arrays.\r\n */\r\nexport const SLAB_TIERS_V12_15: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_15);\r\n\r\n/**\r\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\r\n * Uses SBF sizes (on-chain layout) for the dataSize values.\r\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\r\n * RISK_BUF_LEN=160 appended after engine.\r\n * Supported tiers: small(256), medium(1024), large(4096).\r\n */\r\nexport const SLAB_TIERS_V12_17: Record = {};\r\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\r\n const accountsOff = Math.ceil(preAcc / 8) * 8;\r\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_17);\r\n\r\n/**\r\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\r\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\r\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\r\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\r\n * fall through to the memcmp fallback path with no layout hint.\r\n *\r\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\r\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\r\n * exports consumed by discovery.ts.\r\n */\r\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\r\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\r\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\r\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\r\n});\r\n\r\n/**\r\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\r\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\r\n * All engine and account field offsets are identical to V_ADL.\r\n */\r\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\r\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\r\n paramsSize: V_ADL_PARAMS_SIZE,\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF vs host detection via size comparison.\r\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\r\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\r\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\r\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\r\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\r\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\r\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: isSbf ? 544 : 576,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\r\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\r\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\r\n // Fields that don't exist in the deployed program are set to -1 on SBF.\r\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\r\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\r\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\r\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\r\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\r\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\r\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\r\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\r\n\r\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\r\n // No isolated_balance or insurance_isolation_bps fields.\r\n hasInsuranceIsolation: !isSbf,\r\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\r\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\r\n */\r\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\r\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\r\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\r\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: 72,\r\n configOffset: 72,\r\n configLen: 544,\r\n reservedOff: 80, // V1_RESERVED_OFF\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\r\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\r\n // Engine offsets identical to V12_1 SBF\r\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\r\n engineFundingIndexOff: -1,\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\r\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\r\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\r\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\r\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\r\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\r\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\r\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\r\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\r\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\r\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\r\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\r\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\r\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\r\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\r\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\r\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\r\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\r\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\r\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\r\n *\r\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\r\n */\r\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\r\n const isSbf = dataLen === 237512;\r\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\r\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\r\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\r\n // SBF small has different bitmap/accounts offsets due to u128 align=8\r\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: 552, // SBF CONFIG_LEN for v12.15\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\r\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\r\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\r\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\r\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\r\n engineMarkPriceOff: -1, // not present in v12.15\r\n engineLastCrankSlotOff: -1, // not yet mapped\r\n engineMaxCrankStalenessOff: -1, // not yet mapped\r\n engineTotalOiOff: -1, // not present in v12.15 engine\r\n engineLongOiOff: -1, // not present in v12.15 engine\r\n engineShortOiOff: -1, // not present in v12.15 engine\r\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\r\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\r\n engineLiqCursorOff: -1, // not yet mapped\r\n engineGcCursorOff: -1, // not yet mapped\r\n engineLastSweepStartOff: -1, // not yet mapped\r\n engineLastSweepCompleteOff: -1, // not yet mapped\r\n engineCrankCursorOff: -1, // not yet mapped\r\n engineSweepStartIdxOff: -1, // not yet mapped\r\n engineLifetimeLiquidationsOff: -1, // not yet mapped\r\n engineLifetimeForceClosesOff: -1, // not present in v12.15\r\n engineNetLpPosOff: -1, // not present in v12.15\r\n engineLpSumAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\r\n engineEmergencyOiModeOff: -1, // not present in v12.15\r\n engineEmergencyStartSlotOff: -1, // not present in v12.15\r\n engineLastBreakerSlotOff: -1, // not present in v12.15\r\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\r\n postBitmap,\r\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\r\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\r\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\r\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\r\n * RISK_BUF_LEN=160 appended after engine.\r\n */\r\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\r\n // Detect SBF vs native from account size and engine offset.\r\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\r\n const isSbf = (() => {\r\n // Compute expected native size for this tier\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\r\n return dataLen !== nativeSize;\r\n })();\r\n\r\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\r\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\r\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const acctAlign = isSbf ? 8 : 16;\r\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\r\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\r\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\r\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\r\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\r\n configLen: 512,\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : 192,\r\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\r\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\r\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: -1,\r\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\r\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\r\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: -1, // removed in v12.17\r\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: -1,\r\n engineLastSweepCompleteOff: -1,\r\n engineCrankCursorOff: -1,\r\n engineSweepStartIdxOff: -1,\r\n engineLifetimeLiquidationsOff: -1,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap,\r\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n\r\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\r\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\r\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\r\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\r\n // so absolute offset in the slab is 72 + 304 = 376.\r\n configMarkEwmaOff: V0_HEADER_LEN + 304,\r\n };\r\n}\r\n\r\n/**\r\n * Detect the slab layout version from the raw account data length.\r\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\r\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\r\n *\r\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\r\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\r\n * V2 slabs have version===2 at offset 8 (u32 LE).\r\n *\r\n * @param dataLen - The slab account data length in bytes\r\n * @param data - Optional raw slab data for version-field disambiguation\r\n */\r\n/**\r\n * Assert that a built SlabLayout is internally consistent.\r\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\r\n * Used by layout builders to catch offset arithmetic bugs early.\r\n *\r\n * @param layout - Layout descriptor to validate.\r\n * @param dataLen - Actual byte length of the slab data buffer.\r\n * @returns The validated layout (identity function for chaining).\r\n */\r\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\r\n if (layout.accountsOff > dataLen) {\r\n throw new Error(\r\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\r\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\r\n );\r\n }\r\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\r\n if (bitmapEnd > dataLen) {\r\n throw new Error(\r\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\r\n );\r\n }\r\n return layout;\r\n}\r\n\r\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\r\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\r\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\r\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\r\n // deployed program only emits v12.19 going forward, so this priority\r\n // is correct for live mainnet reads.\r\n const v1219n = V12_19_SIZES.get(dataLen);\r\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\r\n\r\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\r\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\r\n const v1217n = V12_17_SIZES.get(dataLen);\r\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\r\n\r\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\r\n // Vastly larger account size — no collision with any earlier layout possible.\r\n const v1215n = V12_15_SIZES.get(dataLen);\r\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\r\n\r\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\r\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\r\n const v121epn = V12_1_EP_SIZES.get(dataLen);\r\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\r\n\r\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\r\n const v121n = V12_1_SIZES.get(dataLen);\r\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\r\n\r\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\r\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\r\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\r\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\r\n\r\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\r\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\r\n // works directly — no data-probe disambiguation required.\r\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n const v1m2n = V1M2_SIZES.get(dataLen);\r\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\r\n\r\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\r\n const vadln = V_ADL_SIZES.get(dataLen);\r\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\r\n\r\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\r\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\r\n const v1mn = V1M_SIZES.get(dataLen);\r\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\r\n\r\n // Check V0 sizes (deployed devnet V0 program)\r\n const v0n = V0_SIZES.get(dataLen);\r\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\r\n\r\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\r\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\r\n // When data is available, peek at the version field to disambiguate.\r\n const v1dn = V1D_SIZES.get(dataLen);\r\n if (v1dn !== undefined) {\r\n if (data && data.length >= 12) {\r\n const version = readU32LE(data, 8);\r\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\r\n }\r\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\r\n }\r\n\r\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\r\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\r\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\r\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\r\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\r\n\r\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\r\n const v1n = V1_SIZES.get(dataLen);\r\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\r\n\r\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\r\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\r\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\r\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\r\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\r\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Legacy detectLayout for backward compat.\r\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\r\n *\r\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\r\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\r\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\r\n */\r\nexport function detectLayout(dataLen: number) {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return null;\r\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\r\n}\r\n\r\n// =============================================================================\r\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\r\n// =============================================================================\r\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\r\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\r\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\r\nconst PARAMS_TRADING_FEE_OFF = 24;\r\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\r\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\r\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\r\n// riskReductionThreshold and liquidationBufferBps fields).\r\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\r\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\r\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\r\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\r\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\r\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\r\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\r\n\r\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\r\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\r\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\r\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\r\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\r\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\r\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\r\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\r\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\r\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\r\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\r\n\r\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\r\n// InitMarket wire payload for policy fields such as new_account_fee and\r\n// insurance_floor, but those fields are not stored inside engine RiskParams.\r\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\r\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\r\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\r\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\r\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\r\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\r\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\r\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\r\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\r\nconst V12_19_PARAMS_H_MIN_OFF = 104;\r\nconst V12_19_PARAMS_H_MAX_OFF = 112;\r\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\r\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\r\n\r\n// =============================================================================\r\n// Account Layout (240/248 bytes)\r\n// The first 240 bytes are identical in V0 and V1.\r\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\r\n// =============================================================================\r\nconst ACCT_ACCOUNT_ID_OFF = 0;\r\nconst ACCT_CAPITAL_OFF = 8;\r\nconst ACCT_KIND_OFF = 24;\r\nconst ACCT_PNL_OFF = 32;\r\nconst ACCT_RESERVED_PNL_OFF = 48;\r\nconst ACCT_WARMUP_STARTED_OFF = 56;\r\nconst ACCT_WARMUP_SLOPE_OFF = 64;\r\nconst ACCT_POSITION_SIZE_OFF = 80;\r\nconst ACCT_ENTRY_PRICE_OFF = 96;\r\nconst ACCT_FUNDING_INDEX_OFF = 104;\r\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\r\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\r\nconst ACCT_OWNER_OFF = 184;\r\nconst ACCT_FEE_CREDITS_OFF = 216;\r\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\r\n\r\n// =============================================================================\r\n// Interfaces\r\n// =============================================================================\r\n\r\nexport interface SlabHeader {\r\n magic: bigint;\r\n version: number;\r\n bump: number;\r\n flags: number;\r\n resolved: boolean;\r\n paused: boolean;\r\n admin: PublicKey;\r\n nonce: bigint;\r\n lastThrUpdateSlot: bigint;\r\n}\r\n\r\nexport interface MarketConfig {\r\n collateralMint: PublicKey;\r\n vaultPubkey: PublicKey;\r\n indexFeedId: PublicKey;\r\n maxStalenessSlots: bigint;\r\n confFilterBps: number;\r\n vaultAuthorityBump: number;\r\n invert: number;\r\n unitScale: number;\r\n fundingHorizonSlots: bigint;\r\n fundingKBps: bigint;\r\n fundingInvScaleNotionalE6: bigint;\r\n fundingMaxPremiumBps: bigint;\r\n fundingMaxBpsPerSlot: bigint;\r\n threshFloor: bigint;\r\n threshRiskBps: bigint;\r\n threshUpdateIntervalSlots: bigint;\r\n threshStepBps: bigint;\r\n threshAlphaBps: bigint;\r\n threshMin: bigint;\r\n threshMax: bigint;\r\n threshMinStep: bigint;\r\n oracleAuthority: PublicKey;\r\n authorityPriceE6: bigint;\r\n authorityTimestamp: bigint;\r\n oraclePriceCapE2bps: bigint;\r\n lastEffectivePriceE6: bigint;\r\n oiCapMultiplierBps: bigint;\r\n maxPnlCap: bigint;\r\n adaptiveFundingEnabled: boolean;\r\n adaptiveScaleBps: number;\r\n adaptiveMaxFundingBps: bigint;\r\n marketCreatedSlot: bigint;\r\n oiRampSlots: bigint;\r\n /**\r\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\r\n * Do not use for market-resolution logic until a parser is wired.\r\n */\r\n resolvedSlot: bigint;\r\n insuranceIsolationBps: number;\r\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\r\n oraclePhase: number;\r\n /** PERC-622: Cumulative trade volume in e6 format */\r\n cumulativeVolumeE6: bigint;\r\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\r\n phase2DeltaSlots: number;\r\n /**\r\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\r\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\r\n * SetDexPool has never been called (all-zero pubkey).\r\n * Non-null means the program will reject any UpdateHyperpMark that passes\r\n * a different pool account.\r\n */\r\n dexPool: PublicKey | null;\r\n}\r\n\r\nexport interface InsuranceFund {\r\n balance: bigint;\r\n feeRevenue: bigint;\r\n isolatedBalance: bigint;\r\n isolationBps: number;\r\n}\r\n\r\nexport interface RiskParams {\r\n /**\r\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\r\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\r\n */\r\n warmupPeriodSlots: bigint;\r\n maintenanceMarginBps: bigint;\r\n initialMarginBps: bigint;\r\n tradingFeeBps: bigint;\r\n maxAccounts: bigint;\r\n newAccountFee: bigint;\r\n riskReductionThreshold: bigint;\r\n maintenanceFeePerSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n liquidationFeeBps: bigint;\r\n liquidationFeeCap: bigint;\r\n liquidationBufferBps: bigint;\r\n minLiquidationAbs: bigint;\r\n /** Minimum initial deposit to open an account (V12_1+ only) */\r\n minInitialDeposit: bigint;\r\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\r\n minNonzeroMmReq: bigint;\r\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\r\n minNonzeroImReq: bigint;\r\n /** Insurance fund floor (V12_1+ only) */\r\n insuranceFloor: bigint;\r\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\r\n hMin: bigint;\r\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\r\n hMax: bigint;\r\n}\r\n\r\nexport interface EngineState {\r\n vault: bigint;\r\n insuranceFund: InsuranceFund;\r\n currentSlot: bigint;\r\n fundingIndexQpbE6: bigint;\r\n lastFundingSlot: bigint;\r\n /**\r\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\r\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\r\n */\r\n fundingRateBpsPerSlotLast: bigint;\r\n /**\r\n * Funding rate in e9 units (i128). v12.15+ only.\r\n * 0n on pre-v12.15 slabs.\r\n */\r\n fundingRateE9: bigint;\r\n /**\r\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\r\n */\r\n marketMode: 0 | 1 | null;\r\n lastCrankSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n totalOpenInterest: bigint;\r\n longOi: bigint;\r\n shortOi: bigint;\r\n cTot: bigint;\r\n pnlPosTot: bigint;\r\n /**\r\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\r\n */\r\n pnlMaturedPosTot: bigint;\r\n liqCursor: number;\r\n gcCursor: number;\r\n lastSweepStartSlot: bigint;\r\n lastSweepCompleteSlot: bigint;\r\n crankCursor: number;\r\n sweepStartIdx: number;\r\n lifetimeLiquidations: bigint;\r\n lifetimeForceCloses: bigint;\r\n netLpPos: bigint;\r\n lpSumAbs: bigint;\r\n lpMaxAbs: bigint;\r\n lpMaxAbsSweep: bigint;\r\n emergencyOiMode: boolean;\r\n emergencyStartSlot: bigint;\r\n lastBreakerSlot: bigint;\r\n numUsedAccounts: number;\r\n nextAccountId: bigint;\r\n markPriceE6: bigint;\r\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\r\n oraclePriceE6: bigint;\r\n\r\n // ---- V12_17 engine fields ----\r\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\r\n fLongNum: bigint;\r\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\r\n fShortNum: bigint;\r\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\r\n negPnlAccountCount: bigint;\r\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\r\n fundPxLast: bigint;\r\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\r\n resolvedKLongTerminalDelta: bigint;\r\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\r\n resolvedKShortTerminalDelta: bigint;\r\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\r\n resolvedLivePrice: bigint;\r\n}\r\n\r\nexport enum AccountKind {\r\n User = 0,\r\n LP = 1,\r\n}\r\n\r\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\r\nexport type ReserveCohortBytes = Uint8Array;\r\n\r\nexport interface Account {\r\n kind: AccountKind;\r\n accountId: bigint;\r\n capital: bigint;\r\n pnl: bigint;\r\n reservedPnl: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupStartedAtSlot: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupSlopePerStep: bigint;\r\n positionSize: bigint;\r\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\r\n entryPrice: bigint;\r\n fundingIndex: bigint;\r\n matcherProgram: PublicKey;\r\n matcherContext: PublicKey;\r\n owner: PublicKey;\r\n feeCredits: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n lastFeeSlot: bigint;\r\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\r\n feesEarnedTotal: bigint;\r\n /**\r\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\r\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\r\n */\r\n exactReserveCohorts: ReserveCohortBytes[] | null;\r\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\r\n exactCohortCount: number | null;\r\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowOlder: ReserveCohortBytes | null;\r\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\r\n overflowOlderPresent: boolean | null;\r\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowNewest: ReserveCohortBytes | null;\r\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\r\n overflowNewestPresent: boolean | null;\r\n\r\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\r\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\r\n fSnap: bigint;\r\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\r\n adlABasis: bigint;\r\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\r\n adlKSnap: bigint;\r\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\r\n adlEpochSnap: bigint;\r\n\r\n // Scheduled reserve bucket (older, matures linearly)\r\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\r\n schedPresent: boolean | null;\r\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\r\n schedRemainingQ: bigint | null;\r\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\r\n schedAnchorQ: bigint | null;\r\n /** Start slot for scheduled bucket. null on pre-v12.17. */\r\n schedStartSlot: bigint | null;\r\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\r\n schedHorizon: bigint | null;\r\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\r\n schedReleaseQ: bigint | null;\r\n\r\n // Pending reserve bucket (newest, does not mature while pending)\r\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\r\n pendingPresent: boolean | null;\r\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\r\n pendingRemainingQ: bigint | null;\r\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\r\n pendingHorizon: bigint | null;\r\n /** Creation slot for pending bucket. null on pre-v12.17. */\r\n pendingCreatedSlot: bigint | null;\r\n}\r\n\r\n// =============================================================================\r\n// Fetch\r\n// =============================================================================\r\n\r\nexport async function fetchSlab(\r\n connection: Connection,\r\n slabPubkey: PublicKey,\r\n expectedOwner?: PublicKey\r\n): Promise {\r\n const info = await connection.getAccountInfo(slabPubkey);\r\n if (!info) {\r\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\r\n }\r\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\r\n throw new Error(\r\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\r\n );\r\n }\r\n return new Uint8Array(info.data);\r\n}\r\n\r\n// =============================================================================\r\n// PERC-302: Market Maturity OI Ramp\r\n// =============================================================================\r\n\r\nexport const RAMP_START_BPS = 1000n;\r\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\r\n\r\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\r\n const target = config.oiCapMultiplierBps;\r\n if (target === 0n) return 0n;\r\n if (config.oiRampSlots === 0n) return target;\r\n if (target <= RAMP_START_BPS) return target;\r\n const elapsed = currentSlot > config.marketCreatedSlot\r\n ? currentSlot - config.marketCreatedSlot\r\n : 0n;\r\n if (elapsed >= config.oiRampSlots) return target;\r\n const range = target - RAMP_START_BPS;\r\n const rampAdd = (range * elapsed) / config.oiRampSlots;\r\n const result = RAMP_START_BPS + rampAdd;\r\n return result < target ? result : target;\r\n}\r\n\r\n// =============================================================================\r\n// Header helpers\r\n// =============================================================================\r\n\r\nexport function readNonce(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\r\n return readU64LE(data, roff);\r\n}\r\n\r\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\r\n return readU64LE(data, roff + 8);\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Parse slab header (first 72 bytes — layout-independent).\r\n */\r\nexport function parseHeader(data: Uint8Array): SlabHeader {\r\n if (data.length < V0_HEADER_LEN) {\r\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\r\n }\r\n\r\n const magic = readU64LE(data, 0);\r\n if (magic !== MAGIC) {\r\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\r\n }\r\n\r\n const version = readU32LE(data, 8);\r\n const bump = readU8(data, 12);\r\n const flags = readU8(data, 13);\r\n const admin = new PublicKey(data.subarray(16, 48));\r\n\r\n // Reserved field location depends on layout\r\n const layout = detectSlabLayout(data.length, data);\r\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\r\n const nonce = readU64LE(data, roff);\r\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\r\n\r\n return {\r\n magic,\r\n version,\r\n bump,\r\n flags,\r\n resolved: (flags & FLAG_RESOLVED) !== 0,\r\n paused: (flags & 0x02) !== 0,\r\n admin,\r\n nonce,\r\n lastThrUpdateSlot,\r\n };\r\n}\r\n\r\n/**\r\n * Parse market config. Layout-version aware.\r\n * For V0 slabs, fields beyond the basic config are read if present in the data,\r\n * otherwise defaults are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\n/**\r\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\r\n * SBF layout (u128 align=8, total size 512 bytes):\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_bps_per_slot i64\r\n * 144 oracle_authority [32]\r\n * 176 authority_price_e6 u64\r\n * 184 authority_timestamp i64\r\n * 192 oracle_price_cap_e2bps u64\r\n * 200 last_effective_price_e6 u64\r\n * 208 max_insurance_floor u128\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\r\n * 240 insurance_withdraw_cooldown_slots u64\r\n * 248 _iw_padding2 [u64;2]\r\n * 264 last_hyperp_index_slot u64\r\n * 272 last_mark_push_slot u128\r\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\r\n * 304 mark_ewma_e6 u64\r\n * 312 mark_ewma_last_slot u64\r\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\r\n * 336 permissionless_resolve_stale_slots u64\r\n * 344 last_good_oracle_slot u64\r\n * 352 maintenance_fee_per_slot u128\r\n * 368 last_fee_charge_slot u64 (+ 8 pad)\r\n * 384 mark_min_fee u64\r\n * 392 force_close_delay_slots u64\r\n * 400 dex_pool [32]\r\n * 432 max_pnl_cap u64\r\n * 440 last_audit_pause_slot u64\r\n * 448 oi_cap_multiplier_bps u64\r\n * 456 dispute_window_slots u64\r\n * 464 dispute_bond_amount u64\r\n * 472 lp_collateral_enabled u8\r\n * 473 _pad u8\r\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\r\n * 480 pending_admin [32]\r\n * 512 end\r\n */\r\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_17_BYTES = 512;\r\n if (data.length < configOff + MIN_V12_17_BYTES) {\r\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\r\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\r\n // currently surfaced by the MarketConfig type; read them when/if callers\r\n // need them. Only dex_pool is consumed downstream.\r\n\r\n const dexPoolBytes = data.subarray(b + 400, b + 432);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n, // removed in v12.17\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 448),\r\n maxPnlCap: readU64LE(data, b + 432),\r\n adaptiveFundingEnabled: false, // removed in v12.17\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\r\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\r\n * --features small) on 2026-04-28.\r\n *\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_e9_per_slot i64\r\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\r\n * 176 hyperp_mark_e6 u64 ← v12.19 only\r\n * 184 last_oracle_publish_time i64\r\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\r\n * 200 insurance_withdraw_max_bps u16\r\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\r\n * 204 _iw_padding [u8;4]\r\n * 208 insurance_withdraw_cooldown_slots u64\r\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 last_hyperp_index_slot u64\r\n * 240 last_mark_push_slot u128\r\n * 256 last_insurance_withdraw_slot u64\r\n * 264 _pad u64\r\n * 272 mark_ewma_e6 u64\r\n * 280 mark_ewma_last_slot u64\r\n * 288 mark_ewma_halflife_slots u64\r\n * 296 init_restart_slot u64\r\n * 304 permissionless_resolve_stale_slots u64\r\n * 312 last_good_oracle_slot u64\r\n * 320 maintenance_fee_per_slot u128\r\n * 336 fee_sweep_cursor_word u64\r\n * 344 fee_sweep_cursor_bit u64\r\n * 352 mark_min_fee u64\r\n * 360 force_close_delay_slots u64\r\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\r\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\r\n * 408 last_audit_pause_slot u64\r\n * 416 oi_cap_multiplier_bps u64\r\n * 424 dispute_window_slots u64\r\n * 432 dispute_bond_amount u64\r\n * 440 lp_collateral_enabled u8\r\n * 441 _pad u8\r\n * 442 lp_collateral_ltv_bps u16\r\n * 444 _pad [u8;4]\r\n * 448 pending_admin [32]\r\n * 480 end\r\n */\r\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_19_BYTES = 480;\r\n if (data.length < configOff + MIN_V12_19_BYTES) {\r\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\r\n\r\n const dexPoolBytes = data.subarray(b + 368, b + 400);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n,\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 416),\r\n maxPnlCap: readU64LE(data, b + 400),\r\n adaptiveFundingEnabled: false,\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseConfig: invalid slab magic');\r\n }\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\r\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\r\n\r\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\r\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\r\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_19) {\r\n return parseConfigV12_19(data, configOff);\r\n }\r\n\r\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\r\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\r\n // sequential code below covers pre-v12.17 layouts.\r\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\r\n if (isV12_17) {\r\n return parseConfigV12_17(data, configOff);\r\n }\r\n\r\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\r\n // V1 extended fields are optional and guarded by their own `remaining` checks.\r\n const MIN_CONFIG_BYTES = 376;\r\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\r\n }\r\n\r\n let off = configOff;\r\n\r\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const maxStalenessSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const confFilterBps = readU16LE(data, off);\r\n off += 2;\r\n\r\n const vaultAuthorityBump = readU8(data, off);\r\n off += 1;\r\n\r\n const invert = readU8(data, off);\r\n off += 1;\r\n\r\n const unitScale = readU32LE(data, off);\r\n off += 4;\r\n\r\n // Funding rate parameters\r\n const fundingHorizonSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingKBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\r\n off += 16;\r\n\r\n const fundingMaxPremiumBps = readI64LE(data, off);\r\n off += 8;\r\n\r\n const fundingMaxBpsPerSlot = readI64LE(data, off);\r\n off += 8;\r\n\r\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\r\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\r\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\r\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\r\n\r\n // Threshold parameters\r\n const threshFloor = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshRiskBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshUpdateIntervalSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshStepBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshAlphaBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshMin = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMax = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMinStep = readU128LE(data, off);\r\n off += 16;\r\n\r\n // Oracle authority fields\r\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const authorityPriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n const authorityTimestamp = readI64LE(data, off);\r\n off += 8;\r\n\r\n // Oracle price circuit breaker\r\n const oraclePriceCapE2bps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const lastEffectivePriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n // OI cap\r\n const oiCapMultiplierBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const maxPnlCap = readU64LE(data, off);\r\n off += 8;\r\n\r\n // Check if we have enough data for V1-only fields\r\n const remaining = configOff + configLen - off;\r\n\r\n let adaptiveFundingEnabled = false;\r\n let adaptiveScaleBps = 0;\r\n let adaptiveMaxFundingBps = 0n;\r\n let marketCreatedSlot = 0n;\r\n let oiRampSlots = 0n;\r\n let resolvedSlot = 0n;\r\n let insuranceIsolationBps = 0;\r\n let oraclePhase = 0;\r\n let cumulativeVolumeE6 = 0n;\r\n let phase2DeltaSlots = 0;\r\n\r\n if (remaining >= 40) {\r\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\r\n // market_created_slot(u64), oi_ramp_slots(u64),\r\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\r\n // _pad2(u32), adaptive_max_funding_bps(u64),\r\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\r\n marketCreatedSlot = readU64LE(data, off);\r\n off += 8;\r\n\r\n oiRampSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n adaptiveFundingEnabled = readU8(data, off) !== 0;\r\n off += 1;\r\n off += 1; // _adaptive_pad\r\n adaptiveScaleBps = readU16LE(data, off);\r\n off += 2;\r\n off += 4; // _adaptive_pad2\r\n adaptiveMaxFundingBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n if (remaining >= 42) {\r\n insuranceIsolationBps = readU16LE(data, off);\r\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\r\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\r\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\r\n if (remaining >= 56) { // 42 + 14 bytes padding\r\n const padOff = off + 2;\r\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\r\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\r\n // phase2_delta_slots is u24 LE (3 bytes)\r\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\r\n }\r\n }\r\n }\r\n\r\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\r\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\r\n // All-zero pubkey means SetDexPool was never called.\r\n let dexPool: PublicKey | null = null;\r\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\r\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\r\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\r\n // Return null if all-zero (SetDexPool never called)\r\n if (dexPoolBytes.some(b => b !== 0)) {\r\n dexPool = new PublicKey(dexPoolBytes);\r\n }\r\n }\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor,\r\n threshRiskBps,\r\n threshUpdateIntervalSlots,\r\n threshStepBps,\r\n threshAlphaBps,\r\n threshMin,\r\n threshMax,\r\n threshMinStep,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps,\r\n maxPnlCap,\r\n adaptiveFundingEnabled,\r\n adaptiveScaleBps,\r\n adaptiveMaxFundingBps,\r\n marketCreatedSlot,\r\n oiRampSlots,\r\n resolvedSlot,\r\n insuranceIsolationBps,\r\n oraclePhase,\r\n cumulativeVolumeE6,\r\n phase2DeltaSlots,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * Parse RiskParams from engine data. Layout-version aware.\r\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\r\n * not present on-chain, so defaults (0) are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\r\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\r\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\r\n const base = engineOff + paramsOff;\r\n\r\n // Validate we have enough data for the fields we'll actually read.\r\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\r\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\r\n if (data.length < base + MIN_PARAMS_BYTES) {\r\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\r\n }\r\n\r\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\r\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\r\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\r\n const isV12_19Params = layout !== null && layout !== undefined &&\r\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\r\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\r\n\r\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\r\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\r\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\r\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\r\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\r\n\r\n // Basic params present in all layouts (offsets 0-55 are identical)\r\n const result: RiskParams = {\r\n warmupPeriodSlots: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\r\n maintenanceMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\r\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\r\n initialMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 8)\r\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\r\n tradingFeeBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 16)\r\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\r\n maxAccounts: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\r\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\r\n newAccountFee: isV12_19Params\r\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\r\n : isV12_15Params\r\n ? readU128LE(data, base + 32) // offset 32 in v12.15\r\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\r\n // Extended params: defaults; overwritten below if layout supports them\r\n riskReductionThreshold: 0n,\r\n maintenanceFeePerSlot: 0n,\r\n maxCrankStalenessSlots: 0n,\r\n liquidationFeeBps: 0n,\r\n liquidationFeeCap: 0n,\r\n liquidationBufferBps: 0n,\r\n minLiquidationAbs: 0n,\r\n minInitialDeposit: 0n,\r\n minNonzeroMmReq: 0n,\r\n minNonzeroImReq: 0n,\r\n insuranceFloor: 0n,\r\n hMin: 0n,\r\n hMax: 0n,\r\n };\r\n\r\n if (isV12_19Params) {\r\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\r\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\r\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\r\n result.riskReductionThreshold = 0n;\r\n result.maintenanceFeePerSlot = 0n;\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = 0n;\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = 0n;\r\n } else if (isV12_15Params) {\r\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\r\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\r\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\r\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\r\n result.riskReductionThreshold = 0n; // removed in v12.15\r\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\r\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\r\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\r\n result.liquidationFeeBps = readU64LE(data, base + 56);\r\n result.liquidationFeeCap = readU128LE(data, base + 64);\r\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\r\n result.minLiquidationAbs = readU128LE(data, base + 80);\r\n result.minInitialDeposit = readU128LE(data, base + 96);\r\n result.minNonzeroMmReq = readU128LE(data, base + 112);\r\n result.minNonzeroImReq = readU128LE(data, base + 128);\r\n } else if (isV12_1Sbf) {\r\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\r\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n } else if (paramsSize >= 144) {\r\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\r\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\r\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\r\n */\r\nexport function parseEngine(data: Uint8Array): EngineState {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseEngine: invalid slab magic');\r\n }\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\r\n }\r\n if (data.length < layout.accountsOff) {\r\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\r\n }\r\n\r\n const base = layout.engineOff;\r\n\r\n // Detect layout versions\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\r\n\r\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\r\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\r\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\r\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_17 || isV12_19) {\r\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\r\n\r\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\r\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\r\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\r\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\r\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\r\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\r\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\r\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\r\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\r\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\r\n // resolved_k offsets: native 304/320, SBF 288/304\r\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\r\n const resolvedKLongOff = isV12_19 ? 288\r\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\r\n const resolvedKShortOff = isV12_19 ? 304\r\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\r\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\r\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\r\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\r\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\r\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\r\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\r\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\r\n\r\n const longOi = readU128LE(data, base + oiEffLongOff);\r\n const shortOi = readU128LE(data, base + oiEffShortOff);\r\n\r\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\r\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: 0n,\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + currentSlotOff),\r\n fundingIndexQpbE6: 0n, // replaced by per-side funding\r\n lastFundingSlot: 0n,\r\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\r\n fundingRateE9: 0n, // no stored funding rate in v12.17\r\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\r\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\r\n maxCrankStalenessSlots: 0n,\r\n totalOpenInterest: longOi + shortOi,\r\n longOi,\r\n shortOi,\r\n cTot: readU128LE(data, base + cTotOff),\r\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\r\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\r\n liqCursor: 0,\r\n gcCursor: readU16LE(data, base + gcCursorOff),\r\n lastSweepStartSlot: 0n,\r\n lastSweepCompleteSlot: 0n,\r\n crankCursor: 0,\r\n sweepStartIdx: 0,\r\n lifetimeLiquidations: 0n,\r\n lifetimeForceCloses: 0n,\r\n netLpPos: 0n,\r\n lpSumAbs: 0n,\r\n lpMaxAbs: 0n,\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n,\r\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\r\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\r\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\r\n\r\n // V12_17 fields\r\n fLongNum: readI128LE(data, base + fLongNumOff),\r\n fShortNum: readI128LE(data, base + fShortNumOff),\r\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\r\n fundPxLast: readU64LE(data, base + fundPxLastOff),\r\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\r\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\r\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\r\n };\r\n }\r\n\r\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\r\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\r\n const fundingRateBpsPerSlotLast = isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + layout.engineInsuranceOff),\r\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\r\n feeRevenue: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\r\n : 0n,\r\n isolatedBalance: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\r\n : 0n,\r\n isolationBps: layout.hasInsuranceIsolation\r\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\r\n : 0,\r\n },\r\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\r\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\r\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\r\n : readI128LE(data, base + layout.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\r\n fundingRateBpsPerSlotLast,\r\n fundingRateE9: isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : 0n,\r\n marketMode: isV12_15\r\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\r\n : null,\r\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\r\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\r\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\r\n totalOpenInterest: layout.engineTotalOiOff >= 0\r\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\r\n longOi: layout.engineLongOiOff >= 0\r\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\r\n shortOi: layout.engineShortOiOff >= 0\r\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\r\n cTot: readU128LE(data, base + layout.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\r\n pnlMaturedPosTot: isV12_15\r\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\r\n : 0n,\r\n liqCursor: layout.engineLiqCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\r\n gcCursor: layout.engineGcCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\r\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\r\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\r\n crankCursor: layout.engineCrankCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\r\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\r\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\r\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\r\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\r\n netLpPos: layout.engineNetLpPosOff >= 0\r\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\r\n lpSumAbs: layout.engineLpSumAbsOff >= 0\r\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\r\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\r\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\r\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\r\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\r\n : false,\r\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\r\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\r\n markPriceE6: layout.engineMarkPriceOff >= 0\r\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\r\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\r\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\r\n oraclePriceE6: isV12_15\r\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\r\n : 0n,\r\n numUsedAccounts: (() => {\r\n if (layout.postBitmap < 18) return 0;\r\n const bw = layout.bitmapWords;\r\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\r\n })(),\r\n nextAccountId: (() => {\r\n if (layout.postBitmap < 18) return 0n;\r\n const bw = layout.bitmapWords;\r\n const numUsedOff = layout.engineBitmapOff + bw * 8;\r\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\r\n })(),\r\n\r\n // V12_17 fields (not present in pre-v12.17)\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n };\r\n}\r\n\r\n/**\r\n * Read bitmap to get list of used account indices.\r\n */\r\n/**\r\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\r\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\r\n */\r\nexport function parseUsedIndices(data: Uint8Array): number[] {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n if (data.length < base + layout.bitmapWords * 8) {\r\n throw new Error(\"Slab data too short for bitmap\");\r\n }\r\n\r\n const used: number[] = [];\r\n for (let word = 0; word < layout.bitmapWords; word++) {\r\n const bits = readU64LE(data, base + word * 8);\r\n if (bits === 0n) continue;\r\n for (let bit = 0; bit < 64; bit++) {\r\n if ((bits >> BigInt(bit)) & 1n) {\r\n used.push(word * 64 + bit);\r\n }\r\n }\r\n }\r\n return used;\r\n}\r\n\r\n/**\r\n * Check if a specific account index is used.\r\n */\r\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) return false;\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n const word = Math.floor(idx / 64);\r\n const bit = idx % 64;\r\n const bits = readU64LE(data, base + word * 8);\r\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\r\n}\r\n\r\n/**\r\n * Calculate the maximum valid account index for a given slab size.\r\n */\r\nexport function maxAccountIndex(dataLen: number): number {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return 0;\r\n const accountsEnd = dataLen - layout.accountsOff;\r\n if (accountsEnd <= 0) return 0;\r\n return Math.floor(accountsEnd / layout.accountSize);\r\n}\r\n\r\n/**\r\n * Parse a single account by index.\r\n */\r\nexport function parseAccount(data: Uint8Array, idx: number): Account {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const maxIdx = maxAccountIndex(data.length);\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\r\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\r\n }\r\n\r\n const base = layout.accountsOff + idx * layout.accountSize;\r\n if (data.length < base + layout.accountSize) {\r\n throw new Error(\"Slab data too short for account\");\r\n }\r\n\r\n // Select layout-dependent account field offsets.\r\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\r\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\r\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\r\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\r\n // Pre-ADL (account_size<312): original offsets.\r\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\r\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\r\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\r\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\r\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\r\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\r\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\r\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\r\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\r\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\r\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\r\n\r\n if (isV12_17) {\r\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\r\n //\r\n // SBF vs native alignment delta:\r\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\r\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\r\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\r\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\r\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\r\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\r\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\r\n\r\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: 0n, // removed in v12.17\r\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\r\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\r\n warmupStartedAtSlot: 0n, // removed\r\n warmupSlopePerStep: 0n, // removed\r\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\r\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\r\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\r\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\r\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\r\n lastFeeSlot: 0n, // removed\r\n feesEarnedTotal: 0n, // removed in v12.17\r\n exactReserveCohorts: null, // replaced by two-bucket warmup\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // V12_17 fields\r\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\r\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\r\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\r\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\r\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\r\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\r\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\r\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\r\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\r\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\r\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\r\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\r\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\r\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\r\n };\r\n }\r\n\r\n if (isV12_15) {\r\n // V12_15 fast path: fixed offsets, all fields explicit.\r\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n // Parse the 62 reserve cohorts\r\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\r\n const exactReserveCohorts: ReserveCohortBytes[] = [];\r\n for (let i = 0; i < 62; i++) {\r\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\r\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\r\n }\r\n\r\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\r\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\r\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: 0n, // removed in v12.15\r\n warmupSlopePerStep: 0n, // removed in v12.15\r\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\r\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\r\n fundingIndex: 0n, // not present in v12.15 account struct\r\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\r\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\r\n lastFeeSlot: 0n, // removed in v12.15\r\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\r\n exactReserveCohorts,\r\n exactCohortCount: cohortCount,\r\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\r\n overflowOlderPresent,\r\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\r\n overflowNewestPresent,\r\n\r\n // v12.17 fields (not present in v12.15)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n }\r\n\r\n // Pre-v12.15 path\r\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\r\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\r\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\r\n 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));\r\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\r\n 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));\r\n 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));\r\n 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));\r\n 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));\r\n\r\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\r\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\r\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\r\n positionSize: readI128LE(data, base + positionSizeOff),\r\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\r\n // V12_1/V12_1_EP: funding_index not present in SBF layout\r\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\r\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\r\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\r\n feeCredits: readI128LE(data, base + feeCreditsOff),\r\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\r\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\r\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // v12.17 fields (not present in pre-v12.17)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\r\n//\r\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\r\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\r\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\r\n// is a full account-layout break — every v16-version market account is\r\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\r\n// =============================================================================\r\n\r\n/**\r\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\r\n * Stored at bytes [0..8] of every v17 percolator-owned account.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\n/**\r\n * v17 account version (u16 at offset 8).\r\n *\r\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\r\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\r\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\r\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\r\n */\r\nexport const V17_EXPECTED_VERSION = 17;\r\n\r\n/**\r\n * v17 account-kind byte (offset 10 of the 16-byte header).\r\n *\r\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\r\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\r\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\r\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\r\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\r\n * discovery — every other kind shares the same magic+version and would falsely\r\n * pass the looser {@link isV17Account} check (#264).\r\n */\r\nexport const V17_KIND_MARKET = 1;\r\n\r\n/** Byte offset of the v17 account-kind discriminator within the header. */\r\nexport const V17_KIND_OFF = 10;\r\n\r\n/**\r\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\r\n *\r\n * Growth history, each stage purely additive at the tail with all earlier\r\n * offsets UNCHANGED:\r\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\r\n * @432, `protocol_fee_accrued_atoms` u128 @464,\r\n * `protocol_fee_withdrawn_atoms` u128 @480.\r\n * 496 -> 576 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\r\n * @496/512/528/544, three u16 shares @560/562/564, then\r\n * `_padding_split` [u8;10] @566.\r\n *\r\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\r\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\r\n * it is u128-aligned; placing the u16 shares first would push the u128s to\r\n * offset 502 and force the compiler to insert implicit padding, failing the\r\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\r\n * padding out to the 16-byte alignment boundary.\r\n *\r\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\r\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\r\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\r\n * at line 1159.\r\n *\r\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\r\n * still carries the 496-byte layout. Reading a market created by that build\r\n * with this decoder will throw \"data too short\"; a 576-byte read against a\r\n * 496-byte account is a length error, not a silent misparse.\r\n */\r\nexport const V17_WRAPPER_CONFIG_LEN = 576;\r\n\r\n/**\r\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\r\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\r\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\r\n *\r\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\r\n * `_padding_split` tail at the only 8-aligned slot inside it, so\r\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\r\n * 592, and NO pre-existing offset moves. Growing the config instead would have\r\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\r\n * markets — a repeat of the 496→576 incident. If you ever find yourself\r\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\r\n *\r\n * Source of truth: percolator-prog `src/v16_program.rs` struct\r\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\r\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\r\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\r\n */\r\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\r\n\r\n/** v17 AssetOracleProfileV16 length (400 bytes). */\r\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\r\n\r\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\r\nexport const V17_HEADER_LEN = 16;\r\n\r\n/**\r\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\r\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\r\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\r\n * downstream offset in this file chains off it.\r\n */\r\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\r\n\r\n/**\r\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\r\n * verified against percolator-prog `cargo run --example dump_layout`.\r\n */\r\nexport const V17_MARKET_GROUP_LEN = 758;\r\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\r\n\r\n/**\r\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\r\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\r\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\r\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\r\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\r\n */\r\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\r\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\r\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\r\n }\r\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\r\n}\r\n\r\n/**\r\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\r\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\r\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\r\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\r\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\r\n */\r\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\r\n\r\n/**\r\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\r\n *\r\n * Field offsets follow SBF alignment (u128 align=8, not 16).\r\n * Full offset table (verified against v17 wrapper source v16_program.rs,\r\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\r\n * 0 marketauth [32]\r\n * 32 collateral_mint [32]\r\n * 64 secondary_collateral_mint [32]\r\n * 96 maintenance_fee_per_slot u128\r\n * 112 permissionless_market_init_fee u128\r\n * 128 trade_fee_base_bps u64\r\n * 136 permissionless_resolve_stale_slots u64\r\n * 144 force_close_delay_slots u64\r\n * 152 last_good_oracle_slot u64\r\n * 160 insurance_withdraw_deposit_remaining u128\r\n * 176 insurance_withdraw_max_bps u16\r\n * 178 liquidation_cranker_fee_share_bps u16\r\n * 180 maintenance_cranker_fee_share_bps u16\r\n * 182 backing_trade_fee_bps_long u16\r\n * 184 unit_scale u32\r\n * 188 conf_filter_bps u16\r\n * 190 backing_trade_fee_bps_short u16\r\n * 192 insurance_withdraw_deposits_only u8\r\n * 193 oracle_mode u8\r\n * 194 oracle_leg_count u8\r\n * 195 oracle_leg_flags u8\r\n * 196 invert u8\r\n * 197 _padding0 u8\r\n * 198 free_market_slot_count u16\r\n * 200 insurance_withdraw_cooldown_slots u64\r\n * 208 last_insurance_withdraw_slot u64\r\n * 216 max_staleness_secs u64\r\n * 224 hybrid_soft_stale_slots u64\r\n * 232 mark_ewma_e6 u64\r\n * 240 mark_ewma_last_slot u64\r\n * 248 mark_ewma_halflife_slots u64\r\n * 256 mark_min_fee u64\r\n * 264 oracle_target_price_e6 u64\r\n * 272 oracle_target_publish_time i64\r\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 400 oracle_leg_publish_times [i64;3] (24B)\r\n * 424 backing_trade_fee_policy_count u16\r\n * 426 backing_trade_fee_insurance_share_bps_long u16\r\n * 428 backing_trade_fee_insurance_share_bps_short u16\r\n * 430 fee_redirect_to_market_0_bps u16\r\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\r\n * 432 protocol_fee_authority [32]\r\n * 464 protocol_fee_accrued_atoms u128\r\n * 480 protocol_fee_withdrawn_atoms u128\r\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\r\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\r\n * 496 lp_fee_accrued_atoms u128\r\n * 512 lp_fee_withdrawn_atoms u128\r\n * 528 insurance_reserve_accrued_atoms u128\r\n * 544 insurance_reserve_withdrawn_atoms u128\r\n * 560 creator_share_bps u16\r\n * 562 lp_share_bps u16\r\n * 564 insurance_share_bps u16\r\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\r\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\r\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\r\n * Total: 576\r\n */\r\nexport interface WrapperConfigV17 {\r\n marketauth: PublicKey;\r\n collateralMint: PublicKey;\r\n secondaryCollateralMint: PublicKey;\r\n maintenanceFeePerSlot: bigint;\r\n permissionlessMarketInitFee: bigint;\r\n tradeFeeBps: bigint;\r\n permissionlessResolveStaleSlots: bigint;\r\n forceCloseDelaySlots: bigint;\r\n lastGoodOracleSlot: bigint;\r\n insuranceWithdrawDepositRemaining: bigint;\r\n insuranceWithdrawMaxBps: number;\r\n liquidationCrankerFeeShareBps: number;\r\n maintenanceCrankerFeeShareBps: number;\r\n backingTradeFeeBpsLong: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsShort: number;\r\n insuranceWithdrawDepositsOnly: number;\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n freeMarketSlotCount: number;\r\n insuranceWithdrawCooldownSlots: bigint;\r\n lastInsuranceWithdrawSlot: bigint;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n backingTradeFeePolicyCount: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n feeRedirectToMarket0Bps: number;\r\n /**\r\n * Destination pubkey for the protocol's accrued fee share. Set to a\r\n * hardcoded program-level constant at InitMarket; rotatable only via\r\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\r\n * by marketauth/insurance_authority/any creator-facing gate.\r\n */\r\n protocolFeeAuthority: PublicKey;\r\n /**\r\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\r\n * itself credited into any domain's insurance budget — tracks an\r\n * unbudgeted slice of header.insurance no insurance_operator can reach.\r\n */\r\n protocolFeeAccruedAtoms: bigint;\r\n /**\r\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\r\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\r\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\r\n */\r\n protocolFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\r\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\r\n * principal.\r\n *\r\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\r\n * it can be impaired by backing losses between crank and redemption.\r\n *\r\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\r\n * can never be cranked. Outstanding = accrued - withdrawn.\r\n */\r\n lpFeeAccruedAtoms: bigint;\r\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\r\n lpFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\r\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\r\n * bound stake pool's vault.\r\n *\r\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\r\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\r\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\r\n * unbudgeted by construction. Keepers should crank before resolution.\r\n */\r\n insuranceReserveAccruedAtoms: bigint;\r\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\r\n insuranceReserveWithdrawnAtoms: bigint;\r\n /**\r\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\r\n * (3600). Lands in insurance_domain_budget; claimed via\r\n * WithdrawInsuranceAsset (tag 57).\r\n */\r\n creatorShareBps: number;\r\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\r\n lpShareBps: number;\r\n /**\r\n * Insurance/staker share of T in bps. Default 1600, floor\r\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\r\n * split_trade_fee computes this leg as the remainder.\r\n */\r\n insuranceShareBps: number;\r\n /**\r\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\r\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\r\n *\r\n * This is the honest claimable balance a creator-claim UI should display.\r\n * Before the creator-fee-claim change the creator leg was credited into the\r\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\r\n * had no on-chain representation at all and a claim button was really a\r\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\r\n * alone.\r\n *\r\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\r\n * / insurance legs above, this is a single live balance: trades add to it and\r\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\r\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\r\n * claimable right now. (Forced by the 10-byte pad budget; see\r\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\r\n *\r\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\r\n * were explicit padding, so the value is well-defined rather than garbage,\r\n * and the counter simply accrues fresh after an in-place upgrade.\r\n */\r\n creatorFeeClaimableAtoms: bigint;\r\n}\r\n\r\n/**\r\n * Parse a v17 WrapperConfigV16 block from raw account data.\r\n *\r\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\r\n *\r\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\r\n * This function reads the 496-byte wrapper config block directly. It does NOT\r\n * validate the account header magic or version — callers must do that separately.\r\n *\r\n * @param data Raw bytes of the market group account.\r\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\r\n * @returns Parsed WrapperConfigV17 object.\r\n *\r\n * @example\r\n * ```ts\r\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\r\n * if (!accountInfo) throw new Error(\"account not found\");\r\n * const magic = readU64FromBytes(accountInfo.data, 0);\r\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\r\n * const config = parseWrapperConfigV17(accountInfo.data);\r\n * console.log(config.collateralMint.toBase58());\r\n * ```\r\n */\r\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\r\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = configOff;\r\n\r\n // Offsets from the WrapperConfigV16 offset table above\r\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\r\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\r\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\r\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\r\n const tradeFeeBps = readU64LE(data, b + 128);\r\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\r\n const forceCloseDelaySlots = readU64LE(data, b + 144);\r\n const lastGoodOracleSlot = readU64LE(data, b + 152);\r\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\r\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\r\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\r\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\r\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\r\n const unitScale = readU32LE(data, b + 184);\r\n const confFilterBps = readU16LE(data, b + 188);\r\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\r\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\r\n const oracleMode = readU8(data, b + 193);\r\n const oracleLegCount = readU8(data, b + 194);\r\n const oracleLegFlags = readU8(data, b + 195);\r\n const invert = readU8(data, b + 196);\r\n // _padding0 at b+197\r\n const freeMarketSlotCount = readU16LE(data, b + 198);\r\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\r\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\r\n const maxStalenessSecs = readU64LE(data, b + 216);\r\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\r\n const markEwmaE6 = readU64LE(data, b + 232);\r\n const markEwmaLastSlot = readU64LE(data, b + 240);\r\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\r\n const markMinFee = readU64LE(data, b + 256);\r\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\r\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\r\n\r\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\r\n const ORACLE_LEG_CAP = 3;\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\r\n }\r\n\r\n // oracle_leg_prices_e6: [u64;3] at b+376\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\r\n }\r\n\r\n // oracle_leg_publish_times: [i64;3] at b+400\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\r\n }\r\n\r\n // Tail policy fields at b+424\r\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\r\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\r\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\r\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\r\n\r\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\r\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\r\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\r\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\r\n\r\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\r\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\r\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\r\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\r\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\r\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\r\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\r\n const creatorShareBps = readU16LE(data, b + 560);\r\n const lpShareBps = readU16LE(data, b + 562);\r\n const insuranceShareBps = readU16LE(data, b + 564);\r\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\r\n\r\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\r\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\r\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\r\n\r\n return {\r\n marketauth,\r\n collateralMint,\r\n secondaryCollateralMint,\r\n maintenanceFeePerSlot,\r\n permissionlessMarketInitFee,\r\n tradeFeeBps,\r\n permissionlessResolveStaleSlots,\r\n forceCloseDelaySlots,\r\n lastGoodOracleSlot,\r\n insuranceWithdrawDepositRemaining,\r\n insuranceWithdrawMaxBps,\r\n liquidationCrankerFeeShareBps,\r\n maintenanceCrankerFeeShareBps,\r\n backingTradeFeeBpsLong,\r\n unitScale,\r\n confFilterBps,\r\n backingTradeFeeBpsShort,\r\n insuranceWithdrawDepositsOnly,\r\n oracleMode,\r\n oracleLegCount,\r\n oracleLegFlags,\r\n invert,\r\n freeMarketSlotCount,\r\n insuranceWithdrawCooldownSlots,\r\n lastInsuranceWithdrawSlot,\r\n maxStalenessSecs,\r\n hybridSoftStaleSlots,\r\n markEwmaE6,\r\n markEwmaLastSlot,\r\n markEwmaHalflifeSlots,\r\n markMinFee,\r\n oracleTargetPriceE6,\r\n oracleTargetPublishTime,\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n backingTradeFeePolicyCount,\r\n backingTradeFeeInsuranceShareBpsLong,\r\n backingTradeFeeInsuranceShareBpsShort,\r\n feeRedirectToMarket0Bps,\r\n protocolFeeAuthority,\r\n protocolFeeAccruedAtoms,\r\n protocolFeeWithdrawnAtoms,\r\n lpFeeAccruedAtoms,\r\n lpFeeWithdrawnAtoms,\r\n insuranceReserveAccruedAtoms,\r\n insuranceReserveWithdrawnAtoms,\r\n creatorShareBps,\r\n lpShareBps,\r\n insuranceShareBps,\r\n creatorFeeClaimableAtoms,\r\n };\r\n}\r\n\r\n/**\r\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\r\n *\r\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\r\n * 0 oracle_mode u8\r\n * 1 oracle_leg_count u8\r\n * 2 oracle_leg_flags u8\r\n * 3 invert u8\r\n * 4 unit_scale u32\r\n * 8 conf_filter_bps u16\r\n * 10 backing_trade_fee_bps_long u16\r\n * 12 backing_trade_fee_bps_short u16\r\n * 14 backing_trade_fee_insurance_share_bps_long u16\r\n * 16 backing_trade_fee_insurance_share_bps_short u16\r\n * 18 _padding0 [u8;6]\r\n * 24 insurance_authority [32]\r\n * 56 insurance_operator [32]\r\n * 88 backing_bucket_authority [32]\r\n * 120 oracle_authority [32]\r\n * 152 max_staleness_secs u64\r\n * 160 hybrid_soft_stale_slots u64\r\n * 168 mark_ewma_e6 u64\r\n * 176 mark_ewma_last_slot u64\r\n * 184 mark_ewma_halflife_slots u64\r\n * 192 mark_min_fee u64\r\n * 200 oracle_target_price_e6 u64\r\n * 208 oracle_target_publish_time i64\r\n * 216 last_good_oracle_slot u64\r\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 344 oracle_leg_publish_times [i64;3] (24B)\r\n * 368 asset_admin [32] ← v17 NEW\r\n * Total: 400\r\n */\r\nexport interface AssetOracleProfileV17 {\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsLong: number;\r\n backingTradeFeeBpsShort: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n insuranceAuthority: PublicKey;\r\n insuranceOperator: PublicKey;\r\n backingBucketAuthority: PublicKey;\r\n oracleAuthority: PublicKey;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n lastGoodOracleSlot: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n /** v17 NEW: asset_admin pubkey at offset 368. */\r\n assetAdmin: PublicKey;\r\n}\r\n\r\n/**\r\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\r\n *\r\n * @param data Raw bytes containing the profile block.\r\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\r\n * @returns Parsed AssetOracleProfileV17 object.\r\n */\r\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\r\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = profileOff;\r\n const ORACLE_LEG_CAP = 3;\r\n\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\r\n }\r\n\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\r\n }\r\n\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\r\n }\r\n\r\n return {\r\n oracleMode: readU8(data, b + 0),\r\n oracleLegCount: readU8(data, b + 1),\r\n oracleLegFlags: readU8(data, b + 2),\r\n invert: readU8(data, b + 3),\r\n unitScale: readU32LE(data, b + 4),\r\n confFilterBps: readU16LE(data, b + 8),\r\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\r\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\r\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\r\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\r\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\r\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\r\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\r\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\r\n maxStalenessSecs: readU64LE(data, b + 152),\r\n hybridSoftStaleSlots: readU64LE(data, b + 160),\r\n markEwmaE6: readU64LE(data, b + 168),\r\n markEwmaLastSlot: readU64LE(data, b + 176),\r\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\r\n markMinFee: readU64LE(data, b + 192),\r\n oracleTargetPriceE6: readU64LE(data, b + 200),\r\n oracleTargetPublishTime: readI64LE(data, b + 208),\r\n lastGoodOracleSlot: readU64LE(data, b + 216),\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\r\n };\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer contains a v17 percolator account.\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\r\n */\r\nexport function isV17Account(data: Uint8Array): boolean {\r\n if (data.length < 10) return false;\r\n const magic = readU64LE(data, 0);\r\n const version = readU16LE(data, 8);\r\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer is a v17 percolator MARKET account.\r\n *\r\n * Stricter than {@link isV17Account}: requires both that the account is a valid\r\n * v17 account (magic + version) AND that the kind byte at offset 10 is\r\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\r\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\r\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\r\n */\r\nexport function isV17MarketAccount(data: Uint8Array): boolean {\r\n if (data.length < V17_KIND_OFF + 1) return false;\r\n if (!isV17Account(data)) return false;\r\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\r\n}\r\n\r\n// =============================================================================\r\n// V17 OI parser\r\n// =============================================================================\r\n\r\n/**\r\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\r\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\r\n */\r\nconst V17_HEADER_INSURANCE_OFF = 301;\r\n\r\n/**\r\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\r\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\r\n */\r\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\r\n\r\n/**\r\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\r\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\r\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\r\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\r\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\r\n * oi_eff_short_q follows at 273 + 16 = 289\r\n */\r\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\r\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\r\n\r\n/**\r\n * Aggregated open-interest parsed from a v17 market group account.\r\n *\r\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\r\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\r\n * slots in the account and also returns per-asset breakdown.\r\n *\r\n * All quantities are in token micro-units (raw, not scaled by decimals).\r\n */\r\nexport interface V17MarketGroupOI {\r\n /** Group-level insurance reserve (u128, micro-units) */\r\n insuranceBalance: bigint;\r\n /** Sum of oi_eff_long_q across all asset slots */\r\n totalLongOiQ: bigint;\r\n /** Sum of oi_eff_short_q across all asset slots */\r\n totalShortOiQ: bigint;\r\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\r\n assets: Array<{\r\n assetIndex: number;\r\n oiEffLongQ: bigint;\r\n oiEffShortQ: bigint;\r\n }>;\r\n}\r\n\r\n/**\r\n * Parse open-interest fields from a v17 market group account.\r\n *\r\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\r\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\r\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\r\n * which follows the 512-byte wrapper T at the start of each slot).\r\n *\r\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\r\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\r\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\r\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are exact byte offsets.\r\n *\r\n * The absolute offsets below follow from the CURRENT wrapper layout —\r\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\r\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\r\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\r\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\r\n * - insurance: 592 + 301 = 893\r\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\r\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\r\n *\r\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\r\n * giving insurance @ 813. The CODE was always correct — it composes the named\r\n * constants — but the stated numbers were stale. Verified against the first real\r\n * v17 market on the new devnet deployment.)\r\n *\r\n * @param data Raw bytes of the v17 market group account.\r\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\r\n * @throws Error if the buffer is not a valid v17 market account or is too short.\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketGroupPk);\r\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\r\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\r\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\r\n * ```\r\n */\r\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\r\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\r\n const insuranceBalance = readU128LE(data, insuranceOff);\r\n\r\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\r\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\r\n const numSlots = Math.floor(\r\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\r\n );\r\n\r\n let totalLongOiQ = 0n;\r\n let totalShortOiQ = 0n;\r\n const assets: V17MarketGroupOI[\"assets\"] = [];\r\n\r\n for (let i = 0; i < numSlots; i++) {\r\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\r\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\r\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\r\n const longOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\r\n const shortOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\r\n\r\n // Guard against a truncated buffer (should not happen on well-formed accounts).\r\n if (shortOff + 16 > data.length) break;\r\n\r\n const oiEffLongQ = readU128LE(data, longOff);\r\n const oiEffShortQ = readU128LE(data, shortOff);\r\n\r\n totalLongOiQ += oiEffLongQ;\r\n totalShortOiQ += oiEffShortQ;\r\n\r\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\r\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\r\n }\r\n }\r\n\r\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\r\n}\r\n\r\n// =============================================================================\r\n// V17 account decoders (DESYNC fixes — new standalone account types)\r\n// =============================================================================\r\n\r\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\r\nconst V17_ACCOUNT_HEADER_LEN = 16;\r\nconst V17_KIND_PORTFOLIO = 2;\r\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\r\nconst V17_KIND_LP_REDEMPTION = 6;\r\n\r\nfunction assertV17StandaloneHeader(\r\n data: Uint8Array,\r\n parserName: string,\r\n expectedKind: number,\r\n): void {\r\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\r\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\r\n }\r\n const magic = readU64LE(data, 0);\r\n if (magic !== V17_MAGIC) {\r\n throw new Error(`${parserName}: invalid v17 magic`);\r\n }\r\n const version = readU16LE(data, 8);\r\n if (version !== V17_EXPECTED_VERSION) {\r\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\r\n }\r\n const kind = readU8(data, 10);\r\n if (kind !== expectedKind) {\r\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\r\n }\r\n}\r\n\r\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\r\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\r\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\r\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\r\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\r\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\r\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\r\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\r\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\r\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\r\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\r\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\r\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\r\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\r\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\r\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\r\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\r\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\r\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\r\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\r\n// PortfolioLegV16Account (144 bytes each):\r\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\r\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\r\nconst PF_LEG_SIZE = 144;\r\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\r\nconst PF_LEGS_COUNT = 16;\r\n// PortfolioSourceDomainV16Account (196 bytes each):\r\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\r\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\r\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\r\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\r\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\r\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\r\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\r\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\r\nconst PF_SOURCE_DOMAIN_SIZE = 196;\r\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\r\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\r\n// HealthCertV16Account (121 bytes):\r\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\r\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\r\n// CloseProgressLedgerV16Account (188 bytes):\r\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\r\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\r\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\r\n// ResolvedPayoutReceiptV16Account (66 bytes):\r\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\r\n\r\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\r\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\r\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\r\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\r\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\r\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\r\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\r\n// noted above (188) does not even match its own field breakdown (sums to 184; see\r\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\r\n// the same anchor-from-the-end offset).\r\nconst PF_MATCHER_CONFIG_LEN = 104;\r\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\r\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\r\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\r\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\r\n\r\n/** Per-leg decoded data returned by parsePortfolioV17. */\r\nexport interface PortfolioLegV17 {\r\n active: boolean;\r\n assetIndex: number;\r\n marketId: bigint;\r\n /** 0 = long, 1 = short */\r\n side: number;\r\n basisPosQ: bigint;\r\n aBasis: bigint;\r\n kSnap: bigint;\r\n fSnap: bigint;\r\n epochSnap: bigint;\r\n lossWeight: bigint;\r\n bSnap: bigint;\r\n bRem: bigint;\r\n bEpochSnap: bigint;\r\n bStale: boolean;\r\n stale: boolean;\r\n}\r\n\r\n/** Per source-domain slot returned by parsePortfolioV17. */\r\nexport interface PortfolioSourceDomainV17 {\r\n domain: number;\r\n sourceClaimMarketId: bigint;\r\n sourceClaimBoundNum: bigint;\r\n sourceClaimLienedNum: bigint;\r\n sourceClaimCounterpartyLienedNum: bigint;\r\n sourceClaimInsuranceLienedNum: bigint;\r\n sourceLienEffectiveReserved: bigint;\r\n sourceLienCounterpartyBackingNum: bigint;\r\n sourceLienInsuranceBackingNum: bigint;\r\n sourceLienFeeLastSlot: bigint;\r\n sourceClaimImpairedNum: bigint;\r\n sourceLienImpairedEffectiveReserved: bigint;\r\n sourceLienCapitalAtRiskFeeRevenue: bigint;\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\r\n}\r\n\r\n/** Decoded v17 PortfolioAccountV16Account. */\r\nexport interface PortfolioV17 {\r\n /** Market group this portfolio belongs to. */\r\n marketGroupId: PublicKey;\r\n /** Portfolio account identity pubkey (immutable PDA). */\r\n portfolioAccountId: PublicKey;\r\n /** Owner wallet pubkey from the provenance header. */\r\n provenanceOwner: PublicKey;\r\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\r\n owner: PublicKey;\r\n /** Collateral capital in atoms (u128). */\r\n capital: bigint;\r\n /** Unrealised P&L in atoms (i128). */\r\n pnl: bigint;\r\n /** Capital reserved for pending payout (u128). */\r\n reservedPnl: bigint;\r\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\r\n residualCrystallizedLossAtomsTotal: bigint;\r\n /** Genesis farming: cumulative spent principal atoms (u128). */\r\n residualSpentPrincipalAtomsTotal: bigint;\r\n /** Genesis farming: cumulative received atoms (u128). */\r\n residualReceivedAtomsTotal: bigint;\r\n /** Fee credits (i128, can be negative). */\r\n feeCredits: bigint;\r\n /** Cancel-deposit escrow holding (u128). */\r\n cancelDepositEscrow: bigint;\r\n /** Slot when fees were last accrued. */\r\n lastFeeSlot: bigint;\r\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\r\n activeBitmap: bigint;\r\n /** All 16 position leg slots (active or empty). */\r\n legs: PortfolioLegV17[];\r\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\r\n sourceDomains: PortfolioSourceDomainV17[];\r\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\r\n matcherProgram: PublicKey;\r\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\r\n matcherContext: PublicKey;\r\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\r\n matcherDelegate: PublicKey;\r\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\r\n matcherEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Parse a v17 PortfolioAccountV16Account from raw account data.\r\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\r\n *\r\n * @param data - Raw account bytes from `connection.getAccountInfo`.\r\n * @returns Decoded portfolio state.\r\n * @throws If data is too short or magic does not match.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(portfolioPubkey);\r\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\r\n * console.log('capital:', portfolio.capital);\r\n * ```\r\n */\r\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\r\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\r\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\r\n if (data.length < MIN_PORTFOLIO_BYTES) {\r\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\r\n }\r\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\r\n\r\n // Provenance header\r\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\r\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\r\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\r\n\r\n // Body fields\r\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\r\n const capital = readU128LE(data, PF_CAPITAL_OFF);\r\n const pnl = readI128LE(data, PF_PNL_OFF);\r\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\r\n\r\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\r\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\r\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\r\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\r\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\r\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\r\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\r\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\r\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\r\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\r\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\r\n\r\n // Legs\r\n const legs: PortfolioLegV17[] = [];\r\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\r\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\r\n if (data.length < b + PF_LEG_SIZE) break;\r\n legs.push({\r\n active: data[b] !== 0,\r\n assetIndex: readU32LE(data, b + 1),\r\n marketId: readU64LE(data, b + 5),\r\n side: data[b + 13],\r\n basisPosQ: readI128LE(data, b + 14),\r\n aBasis: readU128LE(data, b + 30),\r\n kSnap: readI128LE(data, b + 46),\r\n fSnap: readI128LE(data, b + 62),\r\n epochSnap: readU64LE(data, b + 78),\r\n lossWeight: readU128LE(data, b + 86),\r\n bSnap: readU128LE(data, b + 102),\r\n bRem: readU128LE(data, b + 118),\r\n bEpochSnap: readU64LE(data, b + 134),\r\n bStale: data[b + 142] !== 0,\r\n stale: data[b + 143] !== 0,\r\n });\r\n }\r\n\r\n // Source domains\r\n const sourceDomains: PortfolioSourceDomainV17[] = [];\r\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\r\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\r\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\r\n sourceDomains.push({\r\n domain: readU32LE(data, b + 0),\r\n sourceClaimMarketId: readU64LE(data, b + 4),\r\n sourceClaimBoundNum: readU128LE(data, b + 12),\r\n sourceClaimLienedNum: readU128LE(data, b + 28),\r\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\r\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\r\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\r\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\r\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\r\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\r\n sourceClaimImpairedNum: readU128LE(data, b + 132),\r\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\r\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\r\n });\r\n }\r\n\r\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\r\n : PublicKey.default;\r\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\r\n : PublicKey.default;\r\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\r\n : PublicKey.default;\r\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\r\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\r\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\r\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\r\n // for an account the program itself would refuse to operate on.\r\n let matcherEnabled = false;\r\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\r\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\r\n if (rawEnabled > 1n) {\r\n throw new Error(\r\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\r\n );\r\n }\r\n matcherEnabled = rawEnabled === 1n;\r\n }\r\n\r\n return {\r\n marketGroupId,\r\n portfolioAccountId,\r\n provenanceOwner,\r\n owner,\r\n capital,\r\n pnl,\r\n reservedPnl,\r\n residualCrystallizedLossAtomsTotal,\r\n residualSpentPrincipalAtomsTotal,\r\n residualReceivedAtomsTotal,\r\n feeCredits,\r\n cancelDepositEscrow,\r\n lastFeeSlot,\r\n activeBitmap,\r\n legs,\r\n sourceDomains,\r\n matcherProgram,\r\n matcherContext,\r\n matcherDelegate,\r\n matcherEnabled,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpVaultRegistryV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\r\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\r\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\r\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\r\n// _padding[6]+_reserved[16] = 160 bytes.\r\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\r\n\r\n/** Decoded v17 LpVaultRegistryV16 account. */\r\nexport interface LpVaultRegistryV17 {\r\n marketGroup: PublicKey;\r\n lpMint: PublicKey;\r\n totalLpSharesOutstanding: bigint;\r\n insuranceFeeSnapshotAtoms: bigint;\r\n feeDistributionTotalAtoms: bigint;\r\n epoch: bigint;\r\n redemptionCooldownSlots: bigint;\r\n feeShareBps: number;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n paused: boolean;\r\n version: number;\r\n bump: number;\r\n mintBump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\r\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP vault registry state.\r\n * @throws If data is shorter than 176 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(registryPubkey);\r\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\r\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\r\n * ```\r\n */\r\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\r\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\r\n throw new Error(\r\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\r\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\r\n totalLpSharesOutstanding: readU128LE(data, b + 64),\r\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\r\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\r\n epoch: readU64LE(data, b + 112),\r\n redemptionCooldownSlots: readU64LE(data, b + 120),\r\n feeShareBps: readU16LE(data, b + 128),\r\n oiReservationThresholdBps: readU16LE(data, b + 130),\r\n domain: readU16LE(data, b + 132),\r\n paused: data[b + 134] !== 0,\r\n version: data[b + 135],\r\n bump: data[b + 136],\r\n mintBump: data[b + 137],\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpRedemptionV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\r\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\r\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\r\n\r\n/** Decoded v17 LpRedemptionV16 account. */\r\nexport interface LpRedemptionV17 {\r\n registry: PublicKey;\r\n redeemer: PublicKey;\r\n /** LP shares requested for redemption (u128). */\r\n shares: bigint;\r\n /** Slot when RequestRedeemLpShares was called. */\r\n requestSlot: bigint;\r\n version: number;\r\n bump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpRedemptionV16 account from raw bytes.\r\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP redemption request state.\r\n * @throws If data is shorter than 112 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(redemptionPubkey);\r\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\r\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\r\n * ```\r\n */\r\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\r\n if (data.length < LP_REDEMPTION_TOTAL) {\r\n throw new Error(\r\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\r\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\r\n shares: readU128LE(data, b + 64),\r\n requestSlot: readU64LE(data, b + 80),\r\n version: data[b + 88],\r\n bump: data[b + 89],\r\n };\r\n}\r\n\r\n/**\r\n * Parse all used accounts.\r\n */\r\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\r\n const indices = parseUsedIndices(data);\r\n const maxIdx = maxAccountIndex(data.length);\r\n const validIndices = indices.filter(idx => idx < maxIdx);\r\n const droppedCount = indices.length - validIndices.length;\r\n if (droppedCount > 0) {\r\n console.warn(\r\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\r\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\r\n );\r\n }\r\n return validIndices.map(idx => ({\r\n idx,\r\n account: parseAccount(data, idx),\r\n }));\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Encode a u16 as a 2-byte little-endian buffer.\r\n * Used for PDA seed segments that include a domain/index as u16 LE.\r\n */\r\nfunction u16LE(value: number): Uint8Array {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isInteger(value) ||\r\n value < 0 ||\r\n value > 0xffff\r\n ) {\r\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive vault authority PDA.\r\n * Seeds: [\"vault\", slab_key]\r\n *\r\n * Mirrors `derive_vault_authority(program_id, market_key)` in\r\n * `percolator-prog/src/v16_program.rs:17339-17341`.\r\n */\r\nexport function deriveVaultAuthority(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"vault\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * SPL Associated Token Account program.\r\n *\r\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\r\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\r\n */\r\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\r\n);\r\n\r\n/**\r\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\r\n *\r\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\r\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\r\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\r\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\r\n * ATA's middle seed is always this program id.\r\n */\r\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n);\r\n\r\n/**\r\n * Derive the CANONICAL vault token account for a market + collateral mint.\r\n *\r\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\r\n *\r\n * ```text\r\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\r\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\r\n * ```\r\n *\r\n * Mirrors `canonical_vault_address(vault_authority, mint)`\r\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\r\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\r\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\r\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\r\n * without it an attacker could route deposits to a second `vault_authority`-owned account\r\n * and strand honest withdrawals against the canonical one.\r\n *\r\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\r\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\r\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\r\n * address with a detected token program would produce a key the program rejects with\r\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\r\n *\r\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\r\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\r\n * token path.\r\n *\r\n * @param programId - The Percolator wrapper program ID (the market's owner).\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\r\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketData);\r\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * ```\r\n */\r\nexport function deriveCanonicalVault(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\r\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\r\n}\r\n\r\n/**\r\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\r\n *\r\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\r\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\r\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\r\n *\r\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\r\n * @param mint - The market's collateral mint.\r\n * @returns `[vaultTokenAccount, bump]`\r\n *\r\n * @example\r\n * ```ts\r\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\r\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\r\n * ```\r\n */\r\nexport function deriveCanonicalVaultForAuthority(\r\n vaultAuthority: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n vaultAuthority.toBytes(),\r\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n ASSOCIATED_TOKEN_PROGRAM_ID\r\n );\r\n}\r\n\r\n/** Both halves of a market's vault, as required by tags 84 and 87. */\r\nexport interface MarketVaultAccounts {\r\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\r\n vaultAuthority: PublicKey;\r\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\r\n vaultAuthorityBump: number;\r\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\r\n vaultToken: PublicKey;\r\n /** Bump for `vaultToken`. */\r\n vaultTokenBump: number;\r\n /** The token program that must be passed alongside — always legacy SPL Token. */\r\n tokenProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\r\n *\r\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\r\n * the vault token account, the vault authority PDA and the token program as three separate\r\n * accounts that must agree with one another; deriving them together makes disagreement\r\n * impossible.\r\n *\r\n * Account positions:\r\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\r\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\r\n *\r\n * @param programId - The Percolator wrapper program ID.\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint.\r\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\r\n *\r\n * @example\r\n * ```ts\r\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * const keys = [\r\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\r\n * { pubkey: marketPk, isSigner: false, isWritable: true },\r\n * { pubkey: destToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\r\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\r\n * ];\r\n * ```\r\n */\r\nexport function deriveMarketVaultAccounts(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): MarketVaultAccounts {\r\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\r\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\r\n vaultAuthority,\r\n mint\r\n );\r\n return {\r\n vaultAuthority,\r\n vaultAuthorityBump,\r\n vaultToken,\r\n vaultTokenBump,\r\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\r\n };\r\n}\r\n\r\n/**\r\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\r\n * Seeds: [\"lp_vault_mint\", slab_key]\r\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\r\n */\r\nexport function deriveInsuranceLpMint(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\nconst LP_INDEX_U16_MAX = 0xffff;\r\n\r\n/**\r\n * Derive LP PDA for TradeCpi.\r\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\r\n */\r\nexport function deriveLpPda(\r\n programId: PublicKey,\r\n slab: PublicKey,\r\n lpIdx: number\r\n): [PublicKey, number] {\r\n if (\r\n typeof lpIdx !== \"number\" ||\r\n !Number.isInteger(lpIdx) ||\r\n lpIdx < 0 ||\r\n lpIdx > LP_INDEX_U16_MAX\r\n ) {\r\n throw new Error(\r\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\r\n );\r\n }\r\n const idxBuf = new Uint8Array(2);\r\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DEX Program IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/** PumpSwap AMM program ID. */\r\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\r\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\r\n);\r\n\r\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\r\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\r\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\r\n);\r\n\r\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\r\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\r\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth Push Oracle\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Pyth Push Oracle program on mainnet. */\r\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\r\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Creator Lock PDA (PERC-627)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Seed used to derive the creator lock PDA.\r\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\r\n */\r\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\r\n\r\n/**\r\n * Derive the creator lock PDA for a given slab.\r\n * Seeds: [\"creator_lock\", slab_key]\r\n *\r\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\r\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\r\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\r\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\r\n *\r\n * @param programId - The percolator program ID.\r\n * @param slab - The slab (market) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * ```\r\n */\r\nexport function deriveCreatorLockPda(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// LP Vault PDAs (v17 — tags 74-80)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the LP Vault registry PDA.\r\n * Seeds: [\"lp_vault\", marketGroup]\r\n *\r\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\r\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\r\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\r\n *\r\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpVaultRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP redemption ticket PDA for a specific redeemer.\r\n * Seeds: [\"lp_redemption\", registry, redeemer]\r\n *\r\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\r\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\r\n * @param redeemer - The wallet public key of the redeemer.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\r\n * ```\r\n */\r\nexport function deriveLpRedemption(\r\n programId: PublicKey,\r\n registry: PublicKey,\r\n redeemer: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_redemption\"),\r\n registry.toBytes(),\r\n redeemer.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP backing-domain ledger PDA.\r\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\r\n *\r\n * Required by: DepositToLpVault (tag 75) at accounts[7],\r\n * LpVaultCrankFees (tag 78) at accounts[3].\r\n *\r\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\r\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\r\n * (line 3127) — domain is encoded as 2-byte little-endian.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\r\n * ```\r\n */\r\nexport function deriveLpBackingLedger(\r\n programId: PublicKey,\r\n marketGroup: PublicKey,\r\n domainIdx: number\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_backing_ledger\"),\r\n marketGroup.toBytes(),\r\n u16LE(domainIdx),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP escrow SPL token account PDA.\r\n * Seeds: [\"lp_escrow\", marketGroup]\r\n *\r\n * The escrow is owned by the registry PDA and holds LP tokens during the\r\n * redemption window. Required by ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\r\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpEscrow(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NFT Registry PDA (v17 — tag 73)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the per-market NFT program-id registry PDA.\r\n * Seeds: [\"nft_registry\", marketGroup]\r\n *\r\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\r\n * (TransferPortfolioOwnership, tag 72).\r\n *\r\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\r\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveNftRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the matcher delegate PDA.\r\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\r\n * (all six seed segments are 32-byte public keys)\r\n *\r\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\r\n * The program signs CPI calls to the external matcher program using this PDA.\r\n *\r\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\r\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param market - The market (slab) public key.\r\n * @param accountB - The maker/LP portfolio account public key.\r\n * @param accountBOwner - The owner of accountB.\r\n * @param matcherProg - The external matcher program public key.\r\n * @param matcherCtx - The matcher context account public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [delegatePda] = deriveMatcherDelegate(\r\n * PROGRAM_ID,\r\n * marketKey,\r\n * accountBKey,\r\n * accountBOwnerKey,\r\n * matcherProgKey,\r\n * matcherCtxKey,\r\n * );\r\n * ```\r\n */\r\nexport function deriveMatcherDelegate(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n accountB: PublicKey,\r\n accountBOwner: PublicKey,\r\n matcherProg: PublicKey,\r\n matcherCtx: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"matcher\"),\r\n market.toBytes(),\r\n accountB.toBytes(),\r\n accountBOwner.toBytes(),\r\n matcherProg.toBytes(),\r\n matcherCtx.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\r\nconst PYTH_FEED_ID_HEX_LEN = 64;\r\n\r\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\r\n let s = feedIdHex.trim();\r\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\r\n s = s.slice(2);\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Derive the Pyth Push Oracle PDA for a given feed ID.\r\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\r\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\r\n */\r\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\r\n const normalized = normalizePythFeedIdHex(feedIdHex);\r\n if (!FEED_HEX_RE.test(normalized)) {\r\n throw new Error(\r\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\r\n }\r\n const feedId = new Uint8Array(32);\r\n for (let i = 0; i < 32; i++) {\r\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\r\n }\r\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\r\n return PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n PYTH_PUSH_ORACLE_PROGRAM_ID,\r\n );\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n getAssociatedTokenAddress,\r\n getAssociatedTokenAddressSync,\r\n getAccount,\r\n Account,\r\n TOKEN_PROGRAM_ID,\r\n} from \"@solana/spl-token\";\r\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\r\n\r\n/**\r\n * Get the associated token address for an owner and mint.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport async function getAta(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Synchronous version of getAta.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport function getAtaSync(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): PublicKey {\r\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Fetch token account info.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n * Throws if account doesn't exist.\r\n */\r\nexport async function fetchTokenAccount(\r\n connection: Connection,\r\n address: PublicKey,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAccount(connection, address, undefined, tokenProgramId);\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n parseHeader,\r\n parseConfig,\r\n parseParams,\r\n detectSlabLayout,\r\n isV17MarketAccount,\r\n parseWrapperConfigV17,\r\n SLAB_TIERS_V1M,\r\n SLAB_TIERS_V1M2,\r\n SLAB_TIERS_V2,\r\n SLAB_TIERS_V_ADL,\r\n SLAB_TIERS_V12_1,\r\n SLAB_TIERS_V12_15,\r\n SLAB_TIERS_V12_17,\r\n SLAB_TIERS_V12_19,\r\n SLAB_TIERS_V_SETDEXPOOL,\r\n type SlabHeader,\r\n type MarketConfig,\r\n type EngineState,\r\n type RiskParams,\r\n type SlabLayout,\r\n type WrapperConfigV17,\r\n} from \"./slab.js\";\r\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\r\nimport { type Network } from \"../config/program-ids.js\";\r\n\r\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\r\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\r\n/** V0 bitmap offset within engine struct (deployed devnet program) */\r\nconst ENGINE_BITMAP_OFF_V0 = 320;\r\n\r\n/**\r\n * A discovered Percolator market from on-chain program accounts.\r\n */\r\nexport interface DiscoveredMarket {\r\n slabAddress: PublicKey;\r\n /** The program that owns this slab account */\r\n programId: PublicKey;\r\n /**\r\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\r\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\r\n */\r\n header: SlabHeader;\r\n /**\r\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\r\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\r\n */\r\n config: MarketConfig;\r\n /**\r\n * v12.x engine state (bitmap, account counts).\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n engine: EngineState;\r\n /**\r\n * v12.x risk parameters.\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n params: RiskParams;\r\n /**\r\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\r\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\r\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\r\n * Absent for v12 slab accounts.\r\n *\r\n * Use `isV17Market(m)` to narrow the type:\r\n * ```ts\r\n * if (m.configV17) {\r\n * console.log(m.configV17.collateralMint.toBase58());\r\n * }\r\n * ```\r\n */\r\n configV17?: WrapperConfigV17;\r\n}\r\n\r\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\r\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\r\n * These are the first 8 bytes of every v17 percolator-owned market group account.\r\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\r\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\r\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\r\n */\r\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\r\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\r\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\r\n *\r\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\r\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\r\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\r\n *\r\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\r\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\r\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\r\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\r\n *\r\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\r\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\r\n * See GH #1109, GH #1112.\r\n *\r\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\r\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\r\n */\r\n/**\r\n * Default slab tiers for the current mainnet program (v12.17).\r\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\r\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\r\n */\r\nexport const SLAB_TIERS = {\r\n small: SLAB_TIERS_V12_17[\"small\"],\r\n medium: SLAB_TIERS_V12_17[\"medium\"],\r\n large: SLAB_TIERS_V12_17[\"large\"],\r\n} as const;\r\n\r\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\r\nexport const SLAB_TIERS_V0 = {\r\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\r\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\r\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\r\n} as const;\r\n\r\n/**\r\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\r\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\r\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\r\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\r\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\r\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\r\n * micro = 17,064 (64 slots)\r\n * small = 65,088 (256 slots)\r\n * medium = 257,184 (1,024 slots)\r\n * large = 1,025,568 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D = {\r\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\r\n} as const;\r\n\r\n/**\r\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\r\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\r\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\r\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\r\n * micro = 17,080 (64 slots)\r\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\r\n * medium = 257,200 (1,024 slots)\r\n * large = 1,025,584 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D_LEGACY = {\r\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\r\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\r\n} as const;\r\n\r\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\r\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\r\n */\r\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\r\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\r\n\r\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\r\n\r\n/** Calculate slab data size for arbitrary account count.\r\n *\r\n * Layout (SBF, u128 align = 8):\r\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\r\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\r\n * + bitmap: ceil(N/64)*8\r\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\r\n * + next_free: N*2\r\n * + pad to 8-byte alignment for Account array\r\n * + accounts: N*248\r\n *\r\n * Must match the on-chain program's SLAB_LEN exactly.\r\n */\r\nexport function slabDataSize(maxAccounts: number): number {\r\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\r\n const ENGINE_OFF_V0 = 480;\r\n const ENGINE_BITMAP_OFF_V0 = 320;\r\n const ACCOUNT_SIZE_V0 = 240;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\r\n}\r\n\r\n/**\r\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\r\n *\r\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\r\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\r\n * difference at high account counts or a post-PERC-118 struct addition in the\r\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\r\n * verified on-chain) over this formula for production use.\r\n */\r\nexport function slabDataSizeV1(maxAccounts: number): number {\r\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\r\n const ENGINE_BITMAP_OFF_V1 = 656;\r\n const ACCOUNT_SIZE_V1 = 248;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\r\n}\r\n\r\n/**\r\n * Validate that a slab data size matches one of the known tier sizes.\r\n * Use this to catch tier↔program mismatches early (PERC-277).\r\n *\r\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\r\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\r\n * @returns true if sizes match, false if there's a mismatch\r\n */\r\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\r\n return dataSize === programSlabLen;\r\n}\r\n\r\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\r\nconst ALL_SLAB_SIZES = [\r\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\r\n];\r\n\r\n/** Legacy constant for backward compat */\r\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\r\n\r\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\r\nconst HEADER_SLICE_LENGTH = 1940;\r\n\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\r\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\r\n *\r\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\r\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\r\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\r\n */\r\nexport function parseEngineLight(\r\n data: Uint8Array,\r\n layout: SlabLayout | null,\r\n maxAccounts: number = 4096,\r\n): EngineState {\r\n const isV0 = !layout || layout.version === 0;\r\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\r\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\r\n\r\n const minLen = base + bitmapOff;\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\r\n }\r\n\r\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\r\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\r\n\r\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\r\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\r\n\r\n if (isV0) {\r\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\r\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\r\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\r\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\r\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\r\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\r\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\r\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: readU128LE(data, base + 32),\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + 104),\r\n fundingIndexQpbE6: readI128LE(data, base + 112),\r\n lastFundingSlot: readU64LE(data, base + 128),\r\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: readU64LE(data, base + 144),\r\n maxCrankStalenessSlots: readU64LE(data, base + 152),\r\n totalOpenInterest: readU128LE(data, base + 160),\r\n longOi: 0n,\r\n shortOi: 0n,\r\n cTot: readU128LE(data, base + 176),\r\n pnlPosTot: readU128LE(data, base + 192),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: readU16LE(data, base + 208),\r\n gcCursor: readU16LE(data, base + 210),\r\n lastSweepStartSlot: readU64LE(data, base + 216),\r\n lastSweepCompleteSlot: readU64LE(data, base + 224),\r\n crankCursor: readU16LE(data, base + 232),\r\n sweepStartIdx: readU16LE(data, base + 234),\r\n lifetimeLiquidations: readU64LE(data, base + 240),\r\n lifetimeForceCloses: readU64LE(data, base + 248),\r\n netLpPos: readI128LE(data, base + 256),\r\n lpSumAbs: readU128LE(data, base + 272),\r\n lpMaxAbs: readU128LE(data, base + 288),\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n, // V0 engine has no mark_price field\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\r\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\r\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\r\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\r\n // (the currently-deployed mainnet tier line) were being routed through this branch's\r\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\r\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\r\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\r\n // per the layout-driven branch's own comment below, which already documents that it\r\n // covers V12_15/17/19 — that was the intended path all along.\r\n\r\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\r\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\r\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\r\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\r\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\r\n // that share engineOff=640 but have different internal struct sizes.\r\n if (layout !== null) {\r\n const l = layout;\r\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\r\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\r\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\r\n // struct for that tier has no such field, and `base + (-1)` would read\r\n // garbage straddling the byte before the engine region rather than failing.\r\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\r\n // below goes through these instead of reading the offset directly.\r\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\r\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\r\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\r\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\r\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + l.engineInsuranceOff),\r\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\r\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\r\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\r\n },\r\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\r\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\r\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\r\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\r\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\r\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\r\n : readI128LE(data, base + l.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\r\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\r\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\r\n totalOpenInterest: u128At(l.engineTotalOiOff),\r\n longOi: u128At(l.engineLongOiOff),\r\n shortOi: u128At(l.engineShortOiOff),\r\n cTot: readU128LE(data, base + l.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: u16At(l.engineLiqCursorOff),\r\n gcCursor: u16At(l.engineGcCursorOff),\r\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\r\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\r\n crankCursor: u16At(l.engineCrankCursorOff),\r\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\r\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\r\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\r\n netLpPos: i128At(l.engineNetLpPosOff),\r\n lpSumAbs: u128At(l.engineLpSumAbsOff),\r\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\r\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\r\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\r\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\r\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\r\n markPriceE6: u64At(l.engineMarkPriceOff),\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // layout === null: unrecognized slab format — callers should have skipped via the\r\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\r\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\r\n}\r\n\r\n/** Options for `discoverMarkets`. */\r\nexport interface DiscoverMarketsOptions {\r\n /**\r\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\r\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\r\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\r\n * Default: false (preserves original parallel behaviour).\r\n *\r\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\r\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\r\n */\r\n sequential?: boolean;\r\n /**\r\n * Delay in ms between sequential tier queries (only used when sequential=true).\r\n * Default: 200 ms.\r\n */\r\n interTierDelayMs?: number;\r\n /**\r\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\r\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\r\n */\r\n rateLimitBackoffMs?: number[];\r\n\r\n /**\r\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\r\n * at once to avoid accidental RPC storms from client code.\r\n *\r\n * Default: 6\r\n */\r\n maxParallelTiers?: number;\r\n\r\n /**\r\n * Hard cap on how many tier dataSize queries are attempted.\r\n * Default: all known tiers.\r\n */\r\n maxTierQueries?: number;\r\n\r\n /**\r\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\r\n *\r\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\r\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\r\n * mainnet RPCs that reject `getProgramAccounts`).\r\n *\r\n * The API returns slab addresses which are then fetched on-chain via\r\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\r\n *\r\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * });\r\n * ```\r\n */\r\n apiBaseUrl?: string;\r\n\r\n /**\r\n * Timeout in ms for the API fallback HTTP request.\r\n * Only used when `apiBaseUrl` is set.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n apiTimeoutMs?: number;\r\n\r\n /**\r\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\r\n *\r\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\r\n * `discoverMarkets` will fall back to a bundled static list of known slab\r\n * addresses for the specified network. The addresses are fetched on-chain\r\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * If not set, tier-3 fallback is disabled.\r\n *\r\n * The static list can be extended at runtime via `registerStaticMarkets()`.\r\n *\r\n * @see {@link registerStaticMarkets} to add addresses at runtime\r\n * @see {@link getStaticMarkets} to inspect the current static list\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * network: \"mainnet\", // enables tier-3 static fallback\r\n * });\r\n * ```\r\n */\r\n network?: Network;\r\n}\r\n\r\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\r\nfunction isRateLimitError(err: unknown): boolean {\r\n if (!err) return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return (\r\n msg.includes(\"429\") ||\r\n msg.toLowerCase().includes(\"rate limit\") ||\r\n msg.toLowerCase().includes(\"too many requests\")\r\n );\r\n}\r\n\r\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\r\nfunction withJitter(delayMs: number): number {\r\n const half = Math.floor(delayMs / 2);\r\n return half + Math.floor(Math.random() * (delayMs - half + 1));\r\n}\r\n\r\n/**\r\n * Discover all Percolator markets owned by the given program.\r\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\r\n *\r\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\r\n */\r\nexport async function discoverMarkets(\r\n connection: Connection,\r\n programId: PublicKey,\r\n options: DiscoverMarketsOptions = {},\r\n): Promise {\r\n const {\r\n sequential = false,\r\n interTierDelayMs = 200,\r\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\r\n maxParallelTiers = 6,\r\n } = options;\r\n\r\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\r\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\r\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\r\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\r\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\r\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\r\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\r\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\r\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\r\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\r\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\r\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\r\n //\r\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\r\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\r\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\r\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\r\n const ALL_TIERS_RAW = [\r\n ...Object.values(SLAB_TIERS), // v12.17 (default)\r\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\r\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\r\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\r\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\r\n ...Object.values(SLAB_TIERS_V0),\r\n ...Object.values(SLAB_TIERS_V1D),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\r\n ...Object.values(SLAB_TIERS_V2),\r\n ...Object.values(SLAB_TIERS_V1M),\r\n ...Object.values(SLAB_TIERS_V1M2),\r\n ...Object.values(SLAB_TIERS_V_ADL),\r\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\r\n ];\r\n const tierBySize = new Map();\r\n for (const tier of ALL_TIERS_RAW) {\r\n const existing = tierBySize.get(tier.dataSize);\r\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\r\n tierBySize.set(tier.dataSize, tier);\r\n }\r\n }\r\n const ALL_TIERS = [...tierBySize.values()];\r\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\r\n let rawAccounts: RawEntry[] = [];\r\n\r\n /**\r\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\r\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\r\n */\r\n async function fetchTierWithRetry(\r\n tier: { dataSize: number; maxAccounts: number },\r\n ): Promise {\r\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\r\n try {\r\n const results = await connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\r\n } catch (err) {\r\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\r\n const delay = withJitter(rateLimitBackoffMs[attempt]);\r\n console.warn(\r\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\r\n );\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n // Non-429 or exhausted retries\r\n console.warn(\r\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n return [];\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\r\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\r\n\r\n // Avoid accidental `0`/negative or NaN causing infinite loops.\r\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\r\n\r\n try {\r\n if (sequential) {\r\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\r\n for (let i = 0; i < tiersToQuery.length; i++) {\r\n const tier = tiersToQuery[i];\r\n const entries = await fetchTierWithRetry(tier);\r\n rawAccounts.push(...entries);\r\n if (i < tiersToQuery.length - 1) {\r\n await new Promise(r => setTimeout(r, interTierDelayMs));\r\n }\r\n }\r\n } else {\r\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\r\n // getProgramAccounts calls at once from a single client call.\r\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\r\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\r\n const queries = chunk.map(tier =>\r\n connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n }).then(results =>\r\n results.map(entry => ({\r\n ...entry,\r\n maxAccounts: tier.maxAccounts,\r\n dataSize: tier.dataSize,\r\n })),\r\n ),\r\n );\r\n\r\n const results = await Promise.allSettled(queries);\r\n for (const result of results) {\r\n if (result.status === \"fulfilled\") {\r\n for (const entry of result.value) {\r\n rawAccounts.push(entry as RawEntry);\r\n }\r\n } else {\r\n console.warn(\r\n \"[discoverMarkets] Tier query rejected:\",\r\n result.reason instanceof Error ? result.reason.message : result.reason,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\r\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\r\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\r\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\r\n try {\r\n const v17Results = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\r\n encoding: \"base64\",\r\n },\r\n },\r\n ],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n for (const e of v17Results) {\r\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\r\n }\r\n } catch {\r\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\r\n }\r\n\r\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\r\n // account size changed; RPC returns no error, so we must fallback on empty results too.\r\n if (rawAccounts.length === 0) {\r\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\r\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\r\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\r\n err instanceof Error ? err.message : err,\r\n );\r\n try {\r\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n } catch (memcmpErr) {\r\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\r\n console.warn(\r\n \"[discoverMarkets] memcmp fallback also failed:\",\r\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\r\n );\r\n }\r\n }\r\n\r\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\r\n // rejects it) and an API base URL is configured, fall back to the REST API to\r\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\r\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\r\n console.warn(\r\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\r\n );\r\n try {\r\n const apiResult = await discoverMarketsViaApi(\r\n connection,\r\n programId,\r\n options.apiBaseUrl,\r\n { timeoutMs: options.apiTimeoutMs },\r\n );\r\n if (apiResult.length > 0) {\r\n return apiResult;\r\n }\r\n // API returned 0 markets — fall through to tier 3\r\n console.warn(\r\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\r\n );\r\n } catch (apiErr) {\r\n console.warn(\r\n \"[discoverMarkets] API fallback also failed:\",\r\n apiErr instanceof Error ? apiErr.message : apiErr,\r\n );\r\n // Fall through to tier 3\r\n }\r\n }\r\n\r\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\r\n // the REST API failed (or returned 0 results) and a network hint is provided,\r\n // use the bundled static market list as a last-resort address directory.\r\n if (rawAccounts.length === 0 && options.network) {\r\n const staticEntries = getStaticMarkets(options.network);\r\n if (staticEntries.length > 0) {\r\n console.warn(\r\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\r\n );\r\n try {\r\n return await discoverMarketsViaStaticBundle(\r\n connection,\r\n programId,\r\n staticEntries,\r\n );\r\n } catch (staticErr) {\r\n console.warn(\r\n \"[discoverMarkets] Static bundle fallback also failed:\",\r\n staticErr instanceof Error ? staticErr.message : staticErr,\r\n );\r\n // Fall through to return empty array\r\n }\r\n } else {\r\n console.warn(\r\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\r\n );\r\n }\r\n }\r\n\r\n const accounts = rawAccounts;\r\n\r\n const markets: DiscoveredMarket[] = [];\r\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\r\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\r\n const seenPubkeys = new Set();\r\n\r\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\r\n const pkStr = pubkey.toBase58();\r\n if (seenPubkeys.has(pkStr)) continue;\r\n seenPubkeys.add(pkStr);\r\n const data = new Uint8Array(account.data);\r\n\r\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\r\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\r\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\r\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\r\n // memcmp fallback or if the account happens to match a tier size by coincidence.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\r\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\r\n // — are not mis-parsed as markets.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) continue;\r\n\r\n // Detect layout from actual slab size — not slice length — so parse functions\r\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\r\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\r\n const layout = detectSlabLayout(dataSize, data);\r\n\r\n if (!layout) {\r\n console.warn(\r\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n/**\r\n * Options for `getMarketsByAddress`.\r\n */\r\nexport interface GetMarketsByAddressOptions {\r\n /**\r\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\r\n * Solana limits a single call to 100 accounts; callers may lower this\r\n * to reduce per-request payload size or avoid 429s.\r\n *\r\n * Default: 100 (Solana maximum).\r\n */\r\n batchSize?: number;\r\n\r\n /**\r\n * Delay in ms between batches when the address list exceeds `batchSize`.\r\n * Helps avoid rate-limiting on public RPCs.\r\n *\r\n * Default: 0 (no delay).\r\n */\r\n interBatchDelayMs?: number;\r\n}\r\n\r\n/**\r\n * Fetch and parse Percolator markets by their known slab addresses.\r\n *\r\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\r\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\r\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\r\n *\r\n * Callers must already know the market slab addresses (e.g. from an indexer,\r\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param programId - The Percolator program that owns these slabs\r\n * @param addresses - Array of slab account public keys to fetch\r\n * @param options - Optional batching/delay configuration\r\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection, PublicKey } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const slabs = [\r\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n * // ... more known slab addresses\r\n * ];\r\n *\r\n * const markets = await getMarketsByAddress(connection, programId, slabs);\r\n * console.log(`Found ${markets.length} markets`);\r\n * ```\r\n */\r\nexport async function getMarketsByAddress(\r\n connection: Connection,\r\n programId: PublicKey,\r\n addresses: PublicKey[],\r\n options: GetMarketsByAddressOptions = {},\r\n): Promise {\r\n if (addresses.length === 0) return [];\r\n\r\n const {\r\n batchSize = 100,\r\n interBatchDelayMs = 0,\r\n } = options;\r\n\r\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\r\n\r\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\r\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\r\n const fetched: AccountResult[] = [];\r\n\r\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\r\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\r\n\r\n const response = await connection.getMultipleAccountsInfo(batch);\r\n\r\n for (let i = 0; i < batch.length; i++) {\r\n const info = response[i];\r\n if (info && info.data) {\r\n if (!info.owner.equals(programId)) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\r\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\r\n );\r\n continue;\r\n }\r\n fetched.push({ pubkey: batch[i], data: info.data });\r\n }\r\n }\r\n\r\n // Inter-batch delay to avoid rate-limiting\r\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\r\n await new Promise(r => setTimeout(r, interBatchDelayMs));\r\n }\r\n }\r\n\r\n // Parse each account into a DiscoveredMarket\r\n const markets: DiscoveredMarket[] = [];\r\n\r\n for (const entry of fetched) {\r\n if (!entry) continue;\r\n const { pubkey, data: rawData } = entry;\r\n const data = new Uint8Array(rawData);\r\n\r\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\r\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n // v17 accounts have no slab header/config/engine/params; supply defaults so\r\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\r\n // to detect a v17 market.\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n // Validate v12 magic bytes\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\r\n );\r\n continue;\r\n }\r\n\r\n // Detect layout from full account data length\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// REST API-based market discovery (GH#59 / PERC-8424)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Shape of a single market entry returned by the Percolator REST API\r\n * (`GET /markets`). Only the fields needed for discovery are typed here;\r\n * the full API response may contain additional statistics fields.\r\n */\r\nexport interface ApiMarketEntry {\r\n slab_address: string;\r\n symbol?: string;\r\n name?: string;\r\n decimals?: number;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Options for {@link discoverMarketsViaApi}. */\r\nexport interface DiscoverMarketsViaApiOptions {\r\n /**\r\n * Timeout in ms for the HTTP request to the REST API.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n timeoutMs?: number;\r\n\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets by first querying the REST API for slab addresses,\r\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\r\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\r\n *\r\n * This is the recommended discovery path for mainnet users who do not have a\r\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\r\n *\r\n * The REST API acts as an address directory only — all market data is verified\r\n * on-chain via `getMarketsByAddress`, so the caller gets the same\r\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\r\n *\r\n * @param connection - Solana RPC connection (any endpoint, including public)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param apiBaseUrl - Base URL of the Percolator REST API\r\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\r\n * @param options - Optional timeout and on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts discovered via the API\r\n *\r\n * @example\r\n * ```ts\r\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const markets = await discoverMarketsViaApi(\r\n * connection,\r\n * programId,\r\n * \"https://percolatorlaunch.com/api\",\r\n * );\r\n * console.log(`Discovered ${markets.length} markets via API fallback`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaApi(\r\n connection: Connection,\r\n programId: PublicKey,\r\n apiBaseUrl: string,\r\n options: DiscoverMarketsViaApiOptions = {},\r\n): Promise {\r\n const { timeoutMs = 10_000, onChainOptions } = options;\r\n\r\n // Normalise base URL — strip trailing slash to avoid double-slash in path\r\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\r\n const url = `${base}/markets`;\r\n\r\n // Fetch market list from REST API\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: \"GET\",\r\n headers: { Accept: \"application/json\" },\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\r\n );\r\n }\r\n\r\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\r\n const apiMarkets = body.markets;\r\n\r\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\r\n return [];\r\n }\r\n\r\n // Extract valid slab addresses\r\n const addresses: PublicKey[] = [];\r\n for (const entry of apiMarkets) {\r\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slab_address));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\r\n );\r\n\r\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\r\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Static bundle fallback (PERC-8435 — tier 3)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options for {@link discoverMarketsViaStaticBundle}. */\r\nexport interface DiscoverMarketsViaStaticBundleOptions {\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets from a static list of known slab addresses.\r\n *\r\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\r\n * a bundled list of known slab addresses and fetches their full account data\r\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * The static list acts as an address directory only — all market data is verified\r\n * on-chain, so stale entries are silently skipped (the account won't have valid\r\n * magic bytes or will have been closed).\r\n *\r\n * @param connection - Solana RPC connection (any endpoint)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\r\n * @param options - Optional on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import {\r\n * discoverMarketsViaStaticBundle,\r\n * getStaticMarkets,\r\n * getProgramId,\r\n * } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const entries = getStaticMarkets(\"mainnet\");\r\n *\r\n * const markets = await discoverMarketsViaStaticBundle(\r\n * connection,\r\n * programId,\r\n * entries,\r\n * );\r\n * console.log(`Recovered ${markets.length} markets from static bundle`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaStaticBundle(\r\n connection: Connection,\r\n programId: PublicKey,\r\n entries: StaticMarketEntry[],\r\n options: DiscoverMarketsViaStaticBundleOptions = {},\r\n): Promise {\r\n if (entries.length === 0) return [];\r\n\r\n // Extract valid slab addresses from static entries\r\n const addresses: PublicKey[] = [];\r\n for (const entry of entries) {\r\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slabAddress));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\r\n );\r\n\r\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\r\n}\r\n","/**\r\n * Static market registry — bundled list of known Percolator slab addresses.\r\n *\r\n * This is the tier-3 fallback for `discoverMarkets()`: when both\r\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\r\n * the SDK falls back to this bundled list to bootstrap market discovery.\r\n *\r\n * The addresses are fetched on-chain via `getMarketsByAddress`\r\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\r\n * list only provides the *address directory* — no cached market data is used.\r\n *\r\n * ## Maintenance\r\n *\r\n * Update this list when new markets are deployed or old ones are retired.\r\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\r\n * or the REST API.\r\n *\r\n * @module\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport type { Network } from \"../config/program-ids.js\";\r\n\r\n/**\r\n * A single entry in the static market registry.\r\n *\r\n * Only the slab address (base58) is required. Optional metadata fields\r\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\r\n * they are **not** used for on-chain data and may become stale.\r\n */\r\nexport interface StaticMarketEntry {\r\n /** Base58-encoded slab account address. */\r\n slabAddress: string;\r\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\r\n symbol?: string;\r\n /** Optional descriptive name. */\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Known mainnet market slab addresses.\r\n *\r\n * These are the markets deployed to the mainnet Percolator program\r\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\r\n *\r\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\r\n */\r\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\r\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\r\n];\r\n\r\n/**\r\n * Known devnet market slab addresses.\r\n *\r\n * These are discovered from the devnet Percolator program\r\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\r\n *\r\n * **Last updated:** 2026-04-04.\r\n */\r\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\r\n // Populated from prior discoverMarkets() runs on devnet.\r\n // These serve as the tier-3 safety net for devnet users.\r\n];\r\n\r\n/**\r\n * Full static registry indexed by network.\r\n */\r\nconst STATIC_REGISTRY: Record = {\r\n mainnet: MAINNET_MARKETS,\r\n devnet: DEVNET_MARKETS,\r\n};\r\n\r\n/**\r\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\r\n * Keyed by network.\r\n */\r\nconst USER_MARKETS: Record = {\r\n mainnet: [],\r\n devnet: [],\r\n};\r\n\r\n/**\r\n * Get the bundled static market list for a given network.\r\n *\r\n * Returns the built-in list merged with any entries added via\r\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\r\n * automatically — user-registered entries take precedence.\r\n *\r\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\r\n * @returns Array of static market entries (may be empty if no markets are known)\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * const markets = getStaticMarkets(\"mainnet\");\r\n * console.log(`${markets.length} known mainnet slab addresses`);\r\n * ```\r\n */\r\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\r\n const builtin = STATIC_REGISTRY[network] ?? [];\r\n const user = USER_MARKETS[network] ?? [];\r\n\r\n if (user.length === 0) return [...builtin];\r\n\r\n // Merge: user entries override builtin entries with same slabAddress\r\n const seen = new Map();\r\n for (const entry of builtin) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n for (const entry of user) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n return [...seen.values()];\r\n}\r\n\r\n/**\r\n * Register additional static market entries at runtime.\r\n *\r\n * Use this to inject known slab addresses before calling `discoverMarkets()`\r\n * so that tier-3 fallback has addresses to work with — especially useful\r\n * right after mainnet launch when the bundled list may be empty.\r\n *\r\n * Entries are deduplicated by `slabAddress` — calling this multiple times\r\n * with the same address is safe.\r\n *\r\n * @param network - Target network\r\n * @param entries - One or more static market entries to register\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * registerStaticMarkets(\"mainnet\", [\r\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\r\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\r\n * ]);\r\n * ```\r\n */\r\nexport function registerStaticMarkets(\r\n network: Network,\r\n entries: StaticMarketEntry[],\r\n): void {\r\n const existing = USER_MARKETS[network];\r\n const seen = new Set(existing.map(e => e.slabAddress));\r\n\r\n for (const entry of entries) {\r\n if (!entry.slabAddress) continue;\r\n if (seen.has(entry.slabAddress)) continue;\r\n // Validate that slabAddress is a valid base58 public key\r\n try {\r\n new PublicKey(entry.slabAddress);\r\n } catch {\r\n console.warn(\r\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\r\n );\r\n continue;\r\n }\r\n seen.add(entry.slabAddress);\r\n existing.push(entry);\r\n }\r\n}\r\n\r\n/**\r\n * Clear all user-registered static market entries for a network.\r\n *\r\n * Useful in tests or when resetting state.\r\n *\r\n * @param network - Target network to clear (omit to clear all networks)\r\n */\r\nexport function clearStaticMarkets(network?: Network): void {\r\n if (network) {\r\n USER_MARKETS[network] = [];\r\n } else {\r\n USER_MARKETS.mainnet = [];\r\n USER_MARKETS.devnet = [];\r\n }\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n PUMPSWAP_PROGRAM_ID,\r\n RAYDIUM_CLMM_PROGRAM_ID,\r\n METEORA_DLMM_PROGRAM_ID,\r\n} from \"./pda.js\";\r\n\r\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\r\n\r\nexport interface DexPoolInfo {\r\n dexType: DexType;\r\n poolAddress: PublicKey;\r\n baseMint: PublicKey;\r\n quoteMint: PublicKey;\r\n baseVault?: PublicKey; // PumpSwap only\r\n quoteVault?: PublicKey; // PumpSwap only\r\n}\r\n\r\n/**\r\n * Detect DEX type from the program that owns the pool account.\r\n *\r\n * @param ownerProgramId - The program ID that owns the pool account\r\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\r\n *\r\n * Supported DEX programs:\r\n * - PumpSwap (constant-product AMM)\r\n * - Raydium CLMM (concentrated liquidity)\r\n * - Meteora DLMM (discretized liquidity)\r\n */\r\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\r\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\r\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\r\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\r\n *\r\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\r\n * @param poolAddress - The on-chain address of the pool account\r\n * @param data - Raw account data bytes\r\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\r\n * @throws Error if data is too short for the given DEX type\r\n */\r\nexport function parseDexPool(\r\n dexType: DexType,\r\n poolAddress: PublicKey,\r\n data: Uint8Array,\r\n): DexPoolInfo {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n return parsePumpSwapPool(poolAddress, data);\r\n case \"raydium-clmm\":\r\n return parseRaydiumClmmPool(poolAddress, data);\r\n case \"meteora-dlmm\":\r\n return parseMeteoraPool(poolAddress, data);\r\n }\r\n}\r\n\r\n/**\r\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\r\n *\r\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\r\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\r\n * markets, prefer Pyth or Chainlink oracles.\r\n *\r\n * @param dexType - The type of DEX\r\n * @param data - Raw pool account data\r\n * @param vaultData - For PumpSwap only: base and quote vault account data\r\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\r\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\r\n * ignored for raydium-clmm (decimals are embedded in the pool account).\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\r\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\r\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\r\n * and for PumpSwap pools quoted in a non-WSOL mint.\r\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\r\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\r\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\r\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\r\n * price mislabeled as USD.\r\n * @throws Error if data is too short, required params are missing, or computation fails\r\n */\r\nexport function computeDexSpotPriceE6(\r\n dexType: DexType,\r\n data: Uint8Array,\r\n vaultData?: { base: Uint8Array; quote: Uint8Array },\r\n decimals?: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\r\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\r\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\r\n // MUST supply decimals (fetched from the base/quote mints), matching the\r\n // meteora-dlmm contract below.\r\n if (!decimals) {\r\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\r\n case \"raydium-clmm\":\r\n return computeRaydiumClmmPriceE6(data);\r\n case \"meteora-dlmm\":\r\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\r\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\r\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\r\n if (!decimals) {\r\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Mint decimals helper\r\n// ============================================================================\r\n\r\n/**\r\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\r\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\r\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\r\n * can read this field directly instead of duplicating the magic number.\r\n */\r\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\r\n\r\n/**\r\n * Read the `decimals` field of any SPL mint account (including native WSOL).\r\n *\r\n * This replaces `getMint(connection, mint).decimals` for callers that need to\r\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\r\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\r\n * because the system account is not a valid token-program mint; this function\r\n * reads raw account data and extracts byte 44 directly, which works for all\r\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param mint - The mint public key to query\r\n * @returns The `decimals` field value (0–255)\r\n * @throws Error if the account does not exist or is too short to hold a mint\r\n *\r\n * @example\r\n * ```ts\r\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\r\n *\r\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\r\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\r\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\r\n * base: baseDecimals,\r\n * quote: quoteDecimals,\r\n * });\r\n * ```\r\n */\r\nexport async function fetchMintDecimals(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) {\r\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\r\n }\r\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\r\n throw new Error(\r\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\r\n );\r\n }\r\n return info.data[SPL_MINT_DECIMALS_OFFSET];\r\n}\r\n\r\n// ============================================================================\r\n// PumpSwap\r\n// ============================================================================\r\n\r\n/**\r\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\r\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\r\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\r\n */\r\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\r\n\r\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\r\n// account layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8] pool_bump u8\r\n// [9:11] index u16\r\n// [11:43] creator Pubkey\r\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\r\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\r\n// [107:139] lp_mint Pubkey\r\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\r\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\r\n// [203:211] lp_supply u64\r\n// [211:243] coin_creator Pubkey\r\n//\r\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\r\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\r\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\r\n// pubkeys. Verified against the live ANSEM pool on mainnet\r\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\r\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\r\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\r\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\r\n// balance at verification time). Note the base vault (holding the pump.fun token)\r\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\r\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\r\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\r\n\r\n/**\r\n * Parse a PumpSwap constant-product AMM pool account.\r\n * @internal\r\n */\r\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"pumpswap\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(43, 75)),\r\n quoteMint: new PublicKey(data.slice(75, 107)),\r\n baseVault: new PublicKey(data.slice(139, 171)),\r\n quoteVault: new PublicKey(data.slice(171, 203)),\r\n };\r\n}\r\n\r\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\r\n\r\n/**\r\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\r\n * converted to USD.\r\n *\r\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\r\n *\r\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\r\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\r\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\r\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\r\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\r\n * at all unless multiplied by the SOL/USD rate.\r\n *\r\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\r\n * whether SOL→USD conversion applies)\r\n * @param vaultData - Base and quote vault (SPL token account) raw data\r\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\r\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\r\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\r\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\r\n * PumpSwap pool).\r\n * @internal\r\n */\r\nfunction computePumpSwapPriceE6(\r\n poolData: Uint8Array,\r\n vaultData: { base: Uint8Array; quote: Uint8Array },\r\n decimals: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n if (poolData.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\r\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\r\n\r\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\r\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\r\n\r\n const baseAmount = readU64LE(baseDv, 64);\r\n const quoteAmount = readU64LE(quoteDv, 64);\r\n\r\n if (baseAmount === 0n) return 0n;\r\n\r\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\r\n // the numerator by both the base-decimal correction AND the 1e6 output scale\r\n // before the single division, so low-priced tokens don't truncate to 0n.\r\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\r\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\r\n const baseScale = 10n ** BigInt(decimals.base);\r\n const quoteScale = 10n ** BigInt(decimals.quote);\r\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\r\n\r\n const quoteMint = new PublicKey(poolData.slice(75, 107));\r\n if (quoteMint.equals(WSOL_MINT)) {\r\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\r\n if (solPriceE6 === undefined) {\r\n throw new Error(\r\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\r\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\r\n );\r\n }\r\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\r\n }\r\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\r\n // already ~USD once decimal-adjusted — no further conversion needed.\r\n return quotePerBaseE6;\r\n}\r\n\r\n// ============================================================================\r\n// Raydium CLMM\r\n// ============================================================================\r\n\r\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\r\n\r\n/**\r\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\r\n * @internal\r\n */\r\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"raydium-clmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(73, 105)),\r\n quoteMint: new PublicKey(data.slice(105, 137)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\r\n *\r\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\r\n *\r\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\r\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\r\n *\r\n * @internal\r\n */\r\nconst MAX_TOKEN_DECIMALS = 24;\r\n\r\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\r\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n}\r\n\r\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n const decimals0 = data[233];\r\n const decimals1 = data[234];\r\n\r\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n\r\n const sqrtPriceX64 = readU128LE(dv, 253);\r\n\r\n if (sqrtPriceX64 === 0n) return 0n;\r\n\r\n // #210: defer truncation to a single shift at the very end. The previous form\r\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\r\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\r\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\r\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\r\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\r\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\r\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\r\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\r\n\r\n const decimalDiff = 6 + decimals0 - decimals1;\r\n const adjustedDiff = decimalDiff - 6;\r\n\r\n if (adjustedDiff >= 0) {\r\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\r\n } else {\r\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Meteora DLMM\r\n// ============================================================================\r\n\r\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8:40] parameters (StaticParameters, 32 bytes)\r\n// [40:72] v_parameters (VariableParameters, 32 bytes)\r\n// [72] bump_seed u8\r\n// [73:75] bin_step_seed [u8;2]\r\n// [75] pair_type u8\r\n// [76:80] active_id i32\r\n// [80:82] bin_step u16\r\n// [82] status u8\r\n// [83] require_base_factor_seed u8\r\n// [84:86] base_factor_seed [u8;2]\r\n// [86] activation_type u8\r\n// [87] creator_pool_on_off_control u8\r\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\r\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\r\n// [152:184] reserve_x Pubkey\r\n// [184:216] reserve_y Pubkey\r\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\r\n\r\n/**\r\n * Parse a Meteora DLMM (discretized liquidity) pool account.\r\n *\r\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\r\n * on-chain `LbPair` struct layout (verified against mainnet pool\r\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\r\n *\r\n * @internal\r\n */\r\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"meteora-dlmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(88, 120)),\r\n quoteMint: new PublicKey(data.slice(120, 152)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Meteora DLMM spot price from active_id and bin_step.\r\n *\r\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\r\n *\r\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\r\n * For negative active_id, computes the inverse.\r\n *\r\n * @internal\r\n */\r\nconst MAX_BIN_STEP = 10_000;\r\nconst MAX_ACTIVE_ID_ABS = 500_000;\r\n\r\nfunction computeMeteoraDlmmPriceE6(\r\n data: Uint8Array,\r\n decimalsBase: number,\r\n decimalsQuote: number,\r\n): bigint {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\r\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\r\n // They happen to encode the same integer for most pools (explaining why the\r\n // old code produced correct prices), but reading the correct field is required\r\n // for correctness once those fields diverge.\r\n const binStep = dv.getUint16(80, true);\r\n const activeId = dv.getInt32(76, true);\r\n\r\n if (binStep === 0) return 0n;\r\n if (binStep > MAX_BIN_STEP) {\r\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\r\n }\r\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\r\n throw new Error(\r\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\r\n );\r\n }\r\n\r\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\r\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\r\n\r\n const isNeg = activeId < 0;\r\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\r\n\r\n let result = SCALE;\r\n let b = base;\r\n\r\n while (exp > 0n) {\r\n if (exp & 1n) {\r\n result = (result * b) / SCALE;\r\n }\r\n exp >>= 1n;\r\n if (exp > 0n) {\r\n b = (b * b) / SCALE;\r\n }\r\n }\r\n\r\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\r\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\r\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\r\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\r\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\r\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\r\n // arbitrary-precision, so the intermediate products cannot overflow.\r\n const diff = decimalsBase - decimalsQuote;\r\n\r\n if (isNeg) {\r\n if (result === 0n) return 0n;\r\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\r\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\r\n if (diff >= 0) {\r\n return (num * 10n ** BigInt(diff)) / result;\r\n }\r\n return num / (result * 10n ** BigInt(-diff));\r\n } else {\r\n // price_e6 = (result / 1e12) * 10^diff\r\n if (diff >= 0) {\r\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\r\n }\r\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Read a little-endian u64 from a DataView. */\r\nfunction readU64LE(dv: DataView, offset: number): bigint {\r\n const lo = BigInt(dv.getUint32(offset, true));\r\n const hi = BigInt(dv.getUint32(offset + 4, true));\r\n return lo | (hi << 32n);\r\n}\r\n\r\n/** Read a little-endian u128 from a DataView. */\r\nfunction readU128LE(dv: DataView, offset: number): bigint {\r\n const lo = readU64LE(dv, offset);\r\n const hi = readU64LE(dv, offset + 8);\r\n return lo | (hi << 64n);\r\n}\r\n","/**\r\n * Oracle account parsing utilities.\r\n *\r\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\r\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\r\n * so that this parser and the on-chain program agree byte-for-byte:\r\n *\r\n * CHAINLINK_HEADER_SIZE = 192\r\n * offset 8: version (u8) CL_OFF_VERSION\r\n * offset 138: decimals (u8) CL_OFF_DECIMALS\r\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\r\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\r\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\r\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\r\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\r\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\r\n *\r\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\r\n *\r\n * These utilities validate oracle data BEFORE parsing to prevent silent\r\n * propagation of stale or malformed Chainlink data as price.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Minimum buffer size to read Chainlink price data.\r\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\r\n * The previous value (224) was smaller than the program's own floor, so the SDK\r\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\r\n * answer at offset 216.\r\n */\r\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\r\n\r\n/** Maximum reasonable decimals for a price feed */\r\nconst MAX_DECIMALS = 18;\r\n\r\n/** Offset of decimals field in Chainlink aggregator account */\r\nconst CHAINLINK_DECIMALS_OFFSET = 138;\r\n\r\n/**\r\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\r\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\r\n */\r\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\r\n\r\n/**\r\n * Offset of the latest answer.\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\r\n */\r\nconst CHAINLINK_ANSWER_OFFSET = 216;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface OraclePrice {\r\n price: bigint;\r\n decimals: number;\r\n /** Unix timestamp (seconds) of the last oracle update, if available. */\r\n updatedAt?: number;\r\n}\r\n\r\nexport interface ParseChainlinkOptions {\r\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\r\n maxStalenessSeconds?: number;\r\n /**\r\n * How far ahead of the local clock a publish timestamp may be before it is\r\n * treated as invalid rather than as clock skew. Defaults to 60s.\r\n * Only consulted when `maxStalenessSeconds` is set.\r\n */\r\n futureToleranceSeconds?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Browser-compatible read helpers using DataView\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n return data[off];\r\n}\r\n\r\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\r\n}\r\n\r\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\r\n}\r\n\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\r\n}\r\n\r\n/**\r\n * Default tolerance for a publish timestamp that appears to be in the future.\r\n *\r\n * The program compares the feed timestamp against the on-chain clock\r\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\r\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\r\n * between a user's machine and the cluster would otherwise reject a perfectly\r\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\r\n */\r\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse price data from a Chainlink aggregator account buffer.\r\n *\r\n * Validates:\r\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\r\n * program's own CHAINLINK_FEED_MIN_LEN)\r\n * - Decimals are in a reasonable range (0-18)\r\n * - Price is positive (non-zero)\r\n *\r\n * @param data - Raw account data from Chainlink aggregator\r\n * @param options - Optional staleness check (maxStalenessSeconds)\r\n * @returns Parsed oracle price with decimals and last-update timestamp\r\n * @throws if the buffer is invalid, contains unreasonable data, or (when\r\n * maxStalenessSeconds is set) the last update is older than that bound\r\n */\r\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\r\n if (data.length < CHAINLINK_MIN_SIZE) {\r\n throw new Error(\r\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\r\n );\r\n }\r\n\r\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\r\n if (decimals > MAX_DECIMALS) {\r\n throw new Error(\r\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\r\n );\r\n }\r\n\r\n // The program reads the answer as a full i128 LE (read_i128_le at\r\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\r\n // high (signed) halves rather than reading only the low 8 bytes, which would\r\n // silently truncate a large answer into a different price than the chain sees.\r\n //\r\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\r\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\r\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\r\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\r\n // on-chain. `price` is a bigint and holds the full i128 range.\r\n const answer =\r\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\r\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\r\n if (answer <= 0n) {\r\n throw new Error(\r\n `Oracle price is non-positive: ${answer}`\r\n );\r\n }\r\n const price = answer;\r\n\r\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\r\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\r\n\r\n if (options?.maxStalenessSeconds !== undefined) {\r\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\r\n // skipping the check: a zero timestamp means the feed has never published,\r\n // which is maximally stale, not exempt from staleness.\r\n if (updatedAt <= 0) {\r\n throw new Error(\r\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\r\n );\r\n }\r\n const now = Math.floor(Date.now() / 1000);\r\n const age = now - updatedAt;\r\n // The program rejects a negative age, but it measures against the on-chain\r\n // clock. We only have the local one, so a couple of seconds of ordinary skew\r\n // must not condemn a healthy feed — only an implausible jump ahead should.\r\n const futureTolerance =\r\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\r\n if (age < -futureTolerance) {\r\n throw new Error(\r\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\r\n `check the feed or the local clock`\r\n );\r\n }\r\n if (age > options.maxStalenessSeconds) {\r\n throw new Error(\r\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\r\n );\r\n }\r\n }\r\n\r\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\r\n}\r\n\r\n/**\r\n * Validate that a buffer looks like a valid Chainlink aggregator account.\r\n * Returns true if the buffer passes all validation checks, false otherwise.\r\n * Use this for non-throwing validation.\r\n */\r\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\r\n try {\r\n parseChainlinkPrice(data);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-export constants for consumers\r\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Token2022 (Token Extensions) program ID.\r\n */\r\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\r\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\r\n);\r\n\r\n/**\r\n * Detect which token program owns a given mint account.\r\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\r\n *\r\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\r\n * attacker-controlled account owned by an arbitrary program (or a non-mint\r\n * account) would be accepted and its owner propagated as the \"token program\",\r\n * letting a forged program be passed into a later token CPI. Now we branch on\r\n * the owner and accept ONLY the two real token programs, throwing otherwise.\r\n *\r\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\r\n * Token-2022.\r\n */\r\nexport async function detectTokenProgram(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\r\n\r\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\r\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\r\n\r\n throw new Error(\r\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\r\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\r\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\r\n );\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is Token2022.\r\n */\r\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is the standard SPL Token program.\r\n */\r\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\r\n}\r\n","/**\r\n * @module stake\r\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\r\n *\r\n * Program: percolator-stake (dcccrypto/percolator-stake)\r\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\r\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\r\n * `src/config/program-ids.ts`)\r\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\r\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\r\n * this writing; treat as a placeholder until DevOps confirms)\r\n *\r\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\r\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\r\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\r\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\r\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\r\n * do not use it for new integrations).\r\n */\r\n\r\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\r\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\r\nexport { TOKEN_2022_PROGRAM_ID };\r\nimport { safeEnv } from '../config/program-ids.js';\r\nimport { concatBytes } from '../abi/encode.js';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Known stake program addresses per network.\r\n *\r\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\r\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\r\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\r\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\r\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\r\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\r\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\r\n * module targets — see the module doc above.\r\n *\r\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\r\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\r\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\r\n * confirms.\r\n *\r\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\r\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\r\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\r\n * silently default to mainnet: an unconfigured browser caller would have resolved to\r\n * a real, executing mainnet program rather than failing safe.\r\n */\r\nexport const STAKE_PROGRAM_IDS = {\r\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\r\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\r\n} as const;\r\nObject.freeze(STAKE_PROGRAM_IDS);\r\n\r\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\r\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\r\n\r\n/**\r\n * Resolve the stake program ID for the given network.\r\n *\r\n * Priority:\r\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\r\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\r\n *\r\n * Throws a clear error on mainnet when no address is available so callers\r\n * surface the gap instead of silently hitting the devnet program.\r\n */\r\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\r\n // Only consult the env override when no explicit network arg is provided.\r\n // An explicit network argument always wins so tests and multi-network callers\r\n // are not silently redirected to a DevOps-set override address.\r\n if (!network) {\r\n const override = safeEnv('STAKE_PROGRAM_ID');\r\n if (override) {\r\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\r\n // ambient env poisoning while allowing fresh pre-deploy addresses).\r\n if (\r\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\r\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\r\n ) {\r\n throw new Error(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\r\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\r\n );\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n const detectedNetwork =\r\n network ??\r\n (() => {\r\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\r\n safeEnv('NETWORK')?.toLowerCase() ?? '';\r\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\r\n if (n === 'devnet') return 'devnet' as const;\r\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\r\n // i.e. in every browser bundle, where process.env is empty because env vars\r\n // are not inlined into third-party SDK code. An unconfigured frontend caller\r\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\r\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\r\n //\r\n // We deliberately do NOT substitute a devnet default here. Unlike\r\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\r\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\r\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\r\n // defaulting to devnet would merely defer it to the day mainnet launches and\r\n // a forgotten env var silently points a mainnet UI at the devnet vault.\r\n // Refuse to guess: the network must be explicit.\r\n // The message must not assert a cause it has not established. This fires in\r\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\r\n // with process.env fully available — so claiming \"browser bundle\" would send\r\n // a server-side caller chasing the wrong thing.\r\n throw new Error(\r\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\r\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\r\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\r\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\r\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\r\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\r\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\r\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\r\n 'for the wrong network.',\r\n );\r\n })();\r\n\r\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\r\n if (!id) {\r\n throw new Error(\r\n `Stake program not deployed on ${detectedNetwork}. ` +\r\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\r\n );\r\n }\r\n return new PublicKey(id);\r\n}\r\n\r\n/**\r\n * Default export — resolves for the current runtime network.\r\n * Use getStakeProgramId() with an explicit network argument where possible.\r\n *\r\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\r\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\r\n * resolving to the devnet address.\r\n */\r\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Tags — ADOPTED percolator-stake lineage\r\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\r\n//\r\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\r\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\r\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\r\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\r\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\r\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\r\n// side-by-side tag-delta table this was verified against. The comparison is now\r\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\r\n// NEW address that already runs the ADOPTED lineage below — there is no more\r\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport const STAKE_IX = {\r\n InitPool: 0,\r\n Deposit: 1,\r\n Withdraw: 2,\r\n FlushToInsurance: 3,\r\n UpdateConfig: 4,\r\n /**\r\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\r\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\r\n * zero pubkey CANCELS an outstanding proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\r\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\r\n * wrapper marketauth rotation (a completely different key, done via the\r\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\r\n *\r\n * Wire: tag(1) + new_admin(32) = 33 bytes.\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\n ProposeAdmin: 5,\r\n /**\r\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to take ownership; requires an outstanding proposal\r\n * and the signer to equal `pool.pending_admin`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\r\n * removed `AdminSetOracleAuthority` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\n AcceptAdmin: 6,\r\n /**\r\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\r\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\r\n * LP holders an exit window. A decrease/unchanged value is rejected here\r\n * (use UpdateConfig, which applies decreases immediately).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\r\n * removed `AdminSetRiskThreshold` (rejects on-chain).\r\n *\r\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n ProposeCooldownIncrease: 7,\r\n /**\r\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\r\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n CommitCooldownIncrease: 8,\r\n /**\r\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\r\n * proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\r\n * removed `AdminResolveMarket` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n CancelCooldownIncrease: 9,\r\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\r\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\r\n TransferAdmin: 5,\r\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\r\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\r\n AdminSetOracleAuthority: 6,\r\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\r\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\r\n AdminSetRiskThreshold: 7,\r\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\r\n * CommitCooldownIncrease. */\r\n AdminSetMaintenanceFee: 8,\r\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\r\n * CancelCooldownIncrease. */\r\n AdminResolveMarket: 9,\r\n /**\r\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\r\n * percolator-vault program: transfer withdrawn insurance back into the pool\r\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\r\n * books admin-ATA -> pool-vault).\r\n */\r\n ReturnInsurance: 10,\r\n /** @deprecated Legacy alias for ReturnInsurance. */\r\n AdminWithdrawInsurance: 10,\r\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\r\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\r\n AdminSetInsurancePolicy: 11,\r\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\r\n AccrueFees: 12,\r\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\r\n InitTradingPool: 13,\r\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\r\n AdminSetHwmConfig: 14,\r\n /**\r\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\r\n * tranches. Sets `junior_fee_mult_bps`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * below). Sending this payload against the DEPLOYED vault program would\r\n * execute BindInsuranceAuthority instead; only send it against the\r\n * ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n AdminSetTrancheConfig: 15,\r\n /**\r\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\r\n * Same account shape as Deposit (tag 1).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\n DepositJunior: 16,\r\n /**\r\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\r\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\r\n * binds both in one call, unlike the deployed vault program which only\r\n * bound insurance_authority. The human admin signs the outer tx as the\r\n * current authority/operator; vault_auth signs via invoke_signed.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n BindInsuranceAuthority: 19,\r\n /**\r\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\r\n * escape that moves the market's `insurance_authority` OFF our vault_auth\r\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\r\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\r\n * authority. NEW in the adopted lineage — no equivalent in the deployed\r\n * percolator-vault program (which has no un-bind escape at all).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceAuthority: 20,\r\n /**\r\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\r\n * has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\r\n */\r\n BurnAssetAdmin: 21,\r\n /**\r\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceOperator: 22,\r\n /**\r\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\r\n * insurance_operator, not asset_admin. `amount` capped to\r\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\r\n * NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\r\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\r\n * tokenProgram, percolatorProgram]\r\n */\r\n RecoverFlushedInsurance: 23,\r\n /**\r\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\r\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\r\n * without this proxy every stake-initialized market would be permanently\r\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\r\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\r\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\r\n * percolator-stake (see src/instruction.rs / src/processor.rs\r\n * `process_admin_resolve_market`, tag 24).\r\n *\r\n * NOTE on the name: the on-chain enum variant is literally\r\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\r\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\r\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\r\n * avoid re-using that already-claimed object key/export name — the tag-9\r\n * alias and this tag-24 instruction are unrelated aside from sharing an\r\n * on-chain name across two different lineages.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n */\r\n AdminResolveMarketCpi: 24,\r\n /**\r\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n SetMarketResolved: 18,\r\n /**\r\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\r\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\r\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\r\n * signs the CPI via invoke_signed.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\r\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\r\n * Custom(52)/Custom(51) through the CPI.\r\n */\r\n AdminUpdateFeeSplit: 25,\r\n /**\r\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\r\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\r\n * signer model as tag 25.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\r\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\r\n * `read_u128`.\r\n */\r\n AdminUpdateMaintenanceFeePerSlot: 26,\r\n /**\r\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\r\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\r\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\r\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\r\n *\r\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\r\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\r\n *\r\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n AdminUpdateBackingFeePolicy: 27,\r\n /**\r\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\r\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\r\n * model as tag 27.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\r\n * `read_u64`, wrapper tag 88 with `read_u128`.\r\n */\r\n AdminUpdateTradeFeePolicy: 28,\r\n} as const;\r\nObject.freeze(STAKE_IX);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * User-facing hint text for `StakeError` custom program error codes\r\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\r\n *\r\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\r\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\r\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\r\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\r\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\r\n * error\" for 25-27 despite them being named enum variants); the hints below\r\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\r\n * (missing) on-chain string.\r\n */\r\nexport const STAKE_ERRORS: Record = {\r\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\r\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\r\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\r\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\r\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\r\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\r\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\r\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\r\n 8: \"Market is resolved — no new deposits allowed after resolution\",\r\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\r\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\r\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\r\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\r\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\r\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\r\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\r\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\r\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\r\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\r\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\r\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\r\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\r\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\r\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\r\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\r\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\r\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\r\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\r\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\r\n};\r\nObject.freeze(STAKE_ERRORS);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PDA Derivation\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\n/** Derive the stake pool PDA for a given slab (market). */\r\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\r\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\r\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getBigUint64(off, /* littleEndian= */ true);\r\n}\r\n\r\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getUint16(off, /* littleEndian= */ true);\r\n}\r\n\r\nfunction requireDiscriminator(\r\n accountName: string,\r\n data: Uint8Array,\r\n offset: number,\r\n expected: Uint8Array,\r\n): void {\r\n for (let i = 0; i < expected.length; i += 1) {\r\n if (data[offset + i] !== expected[i]) {\r\n throw new Error(`${accountName} invalid discriminator`);\r\n }\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Encoders\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction u64Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\r\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\r\n const arr = new Uint8Array(8);\r\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\r\n}\r\n\r\nfunction u128Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\r\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\r\n const arr = new Uint8Array(16);\r\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\r\n view.setBigUint64(8, big >> 64n, true);\r\n return arr;\r\n}\r\n\r\nfunction u16Le(v: number): Uint8Array {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\r\n return arr;\r\n}\r\n\r\n/** Tag 0: InitPool — create stake pool for a slab. */\r\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\r\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\r\n}\r\n\r\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\r\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\r\n}\r\n\r\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\r\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\r\n}\r\n\r\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\r\nexport function encodeStakeUpdateConfig(\r\n newCooldownSlots?: bigint | number,\r\n newDepositCap?: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.UpdateConfig]),\r\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\r\n u64Le(newCooldownSlots ?? 0n),\r\n new Uint8Array([newDepositCap != null ? 1 : 0]),\r\n u64Le(newDepositCap ?? 0n),\r\n );\r\n}\r\n\r\nfunction removedStakeInstruction(name: string, tag: number): never {\r\n throw new Error(\r\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\r\n );\r\n}\r\n\r\n/**\r\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\r\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\r\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\r\n * proposal.\r\n *\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeAdmin]),\r\n newAdmin.toBytes(),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to become admin. Requires an outstanding proposal.\r\n *\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAcceptAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\r\n}\r\n\r\n/**\r\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\r\n * until CommitCooldownIncrease is called after the on-chain timelock has\r\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\r\n u64Le(newCooldownSlots),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\r\n * increase proposal.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\r\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\r\n * percolator-stake lineage this module targets, tag 5 is the two-step\r\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\r\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\r\n */\r\nexport function encodeStakeTransferAdmin(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\r\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\r\n void newAuthority;\r\n throw new Error(\r\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\r\n 'lineage — use encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\r\n void newThreshold;\r\n throw new Error(\r\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\r\n void newFee;\r\n throw new Error(\r\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\r\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ReturnInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\r\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\r\n return encodeStakeReturnInsurance(amount);\r\n}\r\n\r\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\r\nexport function encodeStakeAccrueFees(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AccrueFees]);\r\n}\r\n\r\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\r\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitTradingPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\r\nexport function encodeStakeAdminSetHwmConfig(\r\n enabled: boolean,\r\n hwmFloorBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\r\n new Uint8Array([enabled ? 1 : 0]),\r\n u16Le(hwmFloorBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\r\n * percolator-stake lineage; sending it against the currently-deployed vault\r\n * program would silently execute BindInsuranceAuthority instead.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\r\n u16Le(juniorFeeMultBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\r\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\r\n}\r\n\r\n/**\r\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeSetMarketResolved(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\r\n}\r\n\r\n/**\r\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\r\n * then kind=2) — a broader bind than the deployed vault program's\r\n * single-CPI version (insurance_authority only). Must be called once after\r\n * InitPool, before FlushToInsurance will work.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\r\n *\r\n * @returns 1-byte Uint8Array `[0x13]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBindInsuranceAuthority();\r\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\r\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\r\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\r\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BindInsuranceAuthorityAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * Account order matches src/processor.rs process_bind_insurance_authority\r\n * (adopted lineage — same account shape as the deployed vault program's tag\r\n * 15, only the tag byte moved):\r\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\r\n * [1] pool_pda writable (stake pool PDA)\r\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n *\r\n * @example\r\n * ```ts\r\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\r\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\r\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function bindInsuranceAuthorityAccounts(\r\n a: BindInsuranceAuthorityAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\r\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\r\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\r\n * the deployed percolator-vault program (which has no un-bind escape).\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceAuthority();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceOperator();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\r\n}\r\n\r\n/**\r\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\r\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA.\r\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\r\n * @param newTarget The successor authority/operator — co-signs the outer tx.\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RotateInsuranceAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n newTarget: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\r\n * (tag 22) — identical account order in both (src/processor.rs\r\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only\r\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\r\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\r\n * [4] slab writable (wrapper market; needed for CPI)\r\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function rotateInsuranceAccounts(\r\n a: RotateInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after\r\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBurnAssetAdmin();\r\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\r\n}\r\n\r\n/**\r\n * Account inputs for BurnAssetAdmin (tag 21).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\r\n * @param poolPda Stake pool PDA (writable — records the burn).\r\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BurnAssetAdminAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\r\n * process_burn_asset_admin:\r\n * [0] admin signer, writable (current asset_admin == pool.admin)\r\n * [1] pool_pda writable (records asset_admin_burned)\r\n * [2] vault_auth read-only (placeholder new_authority slot)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function burnAssetAdminAccounts(\r\n a: BurnAssetAdminAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\r\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\r\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\r\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\r\n * adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n *\r\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\r\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\r\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for RecoverFlushedInsurance (tag 23).\r\n *\r\n * @param caller Permissionless caller — no signer check required.\r\n * @param poolPda Stake pool PDA (writable).\r\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\r\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\r\n * @param wrapperMarket Wrapper market/slab account (writable).\r\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\r\n * @param wrapperVaultAuth Wrapper vault authority PDA.\r\n * @param tokenProgram Token program.\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RecoverFlushedInsuranceAccounts {\r\n caller: PublicKey;\r\n poolPda: PublicKey;\r\n poolVault: PublicKey;\r\n vaultAuth: PublicKey;\r\n wrapperMarket: PublicKey;\r\n wrapperVault: PublicKey;\r\n wrapperVaultAuth: PublicKey;\r\n tokenProgram: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\r\n * process_recover_flushed_insurance:\r\n * [0] caller (no signer check — permissionless)\r\n * [1] pool_pda writable\r\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\r\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\r\n * [4] market (wrapper) writable\r\n * [5] wrapper_vault writable (source — wrapper insurance vault)\r\n * [6] wrapper_vault_auth read-only\r\n * [7] token_program read-only\r\n * [8] percolator_program read-only\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function recoverFlushedInsuranceAccounts(\r\n a: RecoverFlushedInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.caller, isSigner: false, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\r\n * can call the wrapper's ResolveMarket directly; this instruction has the\r\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\r\n * the (human) admin can trigger resolution. Does not mutate any local\r\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\r\n * separately afterward for local bookkeeping.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n *\r\n * @returns 1-byte Uint8Array `[24]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminResolveMarketCpi();\r\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\r\n}\r\n\r\n/**\r\n * Account inputs for AdminResolveMarketCpi (tag 24).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\r\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface AdminResolveMarketCpiAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\r\n * process_admin_resolve_market:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\r\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function adminResolveMarketCpiAccounts(\r\n a: AdminResolveMarketCpiAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\r\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\r\n//\r\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\r\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\r\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\r\n// transaction, so the affected wrapper setters become reachable ONLY through a\r\n// stake-program CPI proxy. Before these four, exactly one proxy existed\r\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\r\n// wrapper handlers reachable — which is the mechanical reason the fee split\r\n// was unachievable on a staked market.\r\n//\r\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\r\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\r\n// VAULT_AUTH PDA signs.\r\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n//\r\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\r\n * whose length is not exactly 6 bytes after the tag.\r\n *\r\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\r\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\r\n *\r\n * Share validation happens in the WRAPPER, not here: a split that does not sum\r\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\r\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\r\n *\r\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\r\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\r\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\r\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateFeeSplit(\r\n creatorShareBps: number,\r\n lpShareBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\r\n u16Le(creatorShareBps),\r\n u16Le(lpShareBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\r\n * wrapper tag 88.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\r\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\r\n * u64 fails at the stake program before the CPI is even attempted.\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\r\n * 0 (maintenance fee disabled). The wrapper\r\n * range-checks against MAX_PROTOCOL_FEE_ABS.\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\r\n maintenanceFeePerSlot: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\r\n u128Le(maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\r\n * tag 51, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\r\n * = 7 bytes.\r\n *\r\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\r\n * @param feeBps Backing fee in bps (u16).\r\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\r\n * const keys = adminUpdateBackingFeePolicyAccounts({\r\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\r\n * });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateBackingFeePolicy(\r\n domain: number,\r\n feeBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\r\n u16Le(domain),\r\n u16Le(feeBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\r\n * 55, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\r\n * checks `rest.len() == 8`.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\r\n * values above the market's `max_trading_fee_bps` or\r\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateTradeFeePolicy(\r\n tradeFeeBaseBps: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\r\n u64Le(tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\r\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupAProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP A proxies — src/processor.rs\r\n * `process_admin_update_fee_split` (tag 25) and\r\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\r\n * identical layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\r\n * [2] slab writable (wrapper market; CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupAProxyAccounts(\r\n a: StakeGroupAProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\r\n\r\n/**\r\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\r\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\r\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\r\n * insurance_authority; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupBProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP B proxies — src/processor.rs\r\n * `process_admin_update_backing_fee_policy` (tag 27) and\r\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\r\n * layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\r\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; CPI target)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\r\n * difference from GROUP A, and getting it wrong makes the CPI fail its\r\n * authority check rather than fail loudly at the account level.\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupBProxyAccounts(\r\n a: StakeGroupBProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\r\nexport function encodeStakeAdminSetInsurancePolicy(\r\n authority: PublicKey,\r\n minWithdrawBase: bigint | number,\r\n maxWithdrawBps: number,\r\n cooldownSlots: bigint | number,\r\n): Uint8Array {\r\n void authority;\r\n void minWithdrawBase;\r\n void maxWithdrawBps;\r\n void cooldownSlots;\r\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// On-Chain State Layout — StakePool decoded fields\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\r\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\r\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\r\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\r\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\r\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\r\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\r\n * and PERC-303 (tranches).\r\n *\r\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\r\n * `_reserved` layout (verified against `state.rs` on\r\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\r\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\r\n * whatever bytes the program actually writes):\r\n *\r\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\r\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\r\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\r\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\r\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\r\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\r\n * (added later, #242) write into [10..18]/[18..26] regardless.\r\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\r\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\r\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\r\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\r\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\r\n * - This decoder reads both field sets as the raw bytes currently define\r\n * them (matching on-chain reality); it does NOT attempt to reconcile or\r\n * invalidate one set when the other is in use. Callers combining HWM and\r\n * the cooldown timelock on one pool should treat both `hwm*` and\r\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\r\n * against a direct on-chain read before trusting either.\r\n */\r\nexport interface StakePoolState {\r\n isInitialized: boolean;\r\n bump: number;\r\n vaultAuthorityBump: number;\r\n adminTransferred: boolean;\r\n marketResolved: boolean;\r\n\r\n slab: PublicKey;\r\n admin: PublicKey;\r\n collateralMint: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n\r\n totalDeposited: bigint;\r\n totalLpSupply: bigint;\r\n cooldownSlots: bigint;\r\n depositCap: bigint;\r\n totalFlushed: bigint;\r\n totalReturned: bigint;\r\n totalWithdrawn: bigint;\r\n\r\n percolatorProgram: PublicKey;\r\n\r\n /**\r\n * Pending admin for the two-step rotation (stake v2, offset 288).\r\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\r\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\r\n */\r\n pendingAdmin: PublicKey | null;\r\n\r\n // PERC-272: Fee yield fields\r\n totalFeesEarned: bigint;\r\n lastFeeAccrualSlot: bigint;\r\n lastVaultSnapshot: bigint;\r\n poolMode: number;\r\n\r\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\r\n // [0..8] discriminator\r\n // [8] version\r\n // [9] market_resolved\r\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\r\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\r\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\r\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\r\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\r\n // [24..32] PERC-313 hwm_last_epoch (u64)\r\n // [32] PERC-303 tranche_enabled\r\n // [33..41] PERC-303 junior_balance (u64)\r\n // [41..49] PERC-303 junior_total_lp (u64)\r\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\r\n // [51..59] N-realized_junior_loss (u64) — issue #161\r\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\r\n // [60..64] free\r\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\r\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\r\n\r\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\r\n hwmEnabled: boolean;\r\n epochHighWaterTvl: bigint;\r\n hwmFloorBps: number;\r\n hwmLastEpoch: bigint;\r\n\r\n // PERC-303: Tranche fields (from _reserved[32..51])\r\n trancheEnabled: boolean;\r\n juniorBalance: bigint;\r\n juniorTotalLp: bigint;\r\n juniorFeeMultBps: number;\r\n\r\n /**\r\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\r\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n pendingCooldownSlots: bigint;\r\n /**\r\n * #242 timelock: the slot at which the pending cooldown increase was\r\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n cooldownProposedAtSlot: bigint;\r\n /**\r\n * Cumulative insurance loss a fully-exited junior tranche permanently\r\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\r\n * total_pool_value() so recovered tokens don't windfall senior.\r\n */\r\n realizedJuniorLoss: bigint;\r\n /**\r\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\r\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\r\n * stay disabled — the wrapper roles cannot be moved back to an\r\n * admin-controlled key.\r\n */\r\n assetAdminBurned: boolean;\r\n /**\r\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\r\n * collateral actually recovered from the WRAPPER via the tag-23\r\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\r\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\r\n * insurance back out of the wrapper. Real struct field at offset 384..392\r\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\r\n *\r\n * Deliberately separate from `totalReturned`, which is also bumped by two\r\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\r\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\r\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\r\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\r\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\r\n */\r\n totalRecoveredFromWrapper: bigint | null;\r\n}\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v1 layout.\r\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\r\n * The _reserved block in v1 starts at offset 288; version byte = 1.\r\n *\r\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\r\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\r\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\r\n * migration is needed\"). v1/352-byte pools can only ever be observed as\r\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\r\n * redeploy (which abandons every existing market/pool wholesale — VERSION\r\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\r\n * detection exists purely to decode those pre-redeploy artifacts if you ever\r\n * need to; the ADOPTED program itself never creates a v1 pool.\r\n */\r\nexport const STAKE_POOL_SIZE_V1 = 352;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v2 layout.\r\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\r\n * The _reserved block in v2 starts at offset 320; version byte = 2.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\r\n * padding (every u64 field lands on an 8-aligned cumulative offset).\r\n *\r\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\r\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\r\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\r\n * still needs to construct a v2-shaped buffer explicitly.\r\n */\r\nexport const STAKE_POOL_SIZE_V2 = 384;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\r\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\r\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\r\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\r\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\r\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\r\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\r\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\r\n * instead of the broader (and gameable) `total_returned` counter — see\r\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\r\n * padding (the appended u64 lands on the already-8-aligned offset 384).\r\n */\r\nexport const STAKE_POOL_SIZE_V3 = 392;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\r\n * ADOPTED percolator-stake lineage creates. Currently equal to\r\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\r\n * constants in new code so a future version bump doesn't silently change the\r\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\r\n */\r\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\r\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\r\nexport const STAKE_POOL_CURRENT_VERSION = 3;\r\n\r\n/**\r\n * Decode a StakePool account from raw data buffer.\r\n *\r\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\r\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\r\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\r\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\r\n * v2 and v3). The layout version is detected from the data length before\r\n * reading the discriminator.\r\n *\r\n * v1/v2 support exists only to decode legacy pools created before the\r\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\r\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\r\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\r\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\r\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\r\n * on-chain `_reserved` layout collision).\r\n *\r\n * Uses DataView for all u64/u16 reads — browser-safe.\r\n */\r\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\r\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\r\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\r\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\r\n if (!isV3 && !isV2 && !isV1) {\r\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\r\n }\r\n\r\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\r\n // AFTER _reserved, not inside it, so the block start doesn't move again).\r\n const reservedOffset = isV1 ? 288 : 320;\r\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\r\n const version = data[reservedOffset + 8];\r\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\r\n if (version !== expectedVersion) {\r\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\r\n }\r\n\r\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\r\n let off = 0;\r\n const isInitialized = bytes[off] === 1; off += 1;\r\n const bump = bytes[off]; off += 1;\r\n const vaultAuthorityBump = bytes[off]; off += 1;\r\n const adminTransferred = bytes[off] === 1; off += 1;\r\n off += 4; // _padding\r\n\r\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n const totalDeposited = readU64LE(bytes, off); off += 8;\r\n const totalLpSupply = readU64LE(bytes, off); off += 8;\r\n const cooldownSlots = readU64LE(bytes, off); off += 8;\r\n const depositCap = readU64LE(bytes, off); off += 8;\r\n const totalFlushed = readU64LE(bytes, off); off += 8;\r\n const totalReturned = readU64LE(bytes, off); off += 8;\r\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\r\n\r\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n // PERC-272 fields (offset 256..288 in both v1 and v2)\r\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\r\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\r\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\r\n const poolMode = bytes[off]; off += 1;\r\n off += 7; // _mode_padding (off is now 288)\r\n\r\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\r\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\r\n let pendingAdmin: PublicKey | null = null;\r\n if (isV2 || isV3) {\r\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\r\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\r\n ? null\r\n : new PublicKey(pendingAdminBytes);\r\n }\r\n\r\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\r\n const reservedStart = off;\r\n // _reserved[8] = version (skipped)\r\n // _reserved[9] = market_resolved\r\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\r\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\r\n const marketResolved = bytes[reservedStart + 9] === 1;\r\n const hwmEnabled = bytes[reservedStart + 10] === 1;\r\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\r\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\r\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\r\n\r\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\r\n const trancheEnabled = bytes[reservedStart + 32] === 1;\r\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\r\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\r\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\r\n\r\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\r\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\r\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\r\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\r\n\r\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\r\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\r\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\r\n\r\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\r\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\r\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\r\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\r\n const totalRecoveredFromWrapper = isV3\r\n ? readU64LE(bytes, reservedStart + 64)\r\n : null;\r\n\r\n return {\r\n isInitialized,\r\n bump,\r\n vaultAuthorityBump,\r\n adminTransferred,\r\n marketResolved,\r\n slab,\r\n admin,\r\n collateralMint,\r\n lpMint,\r\n vault,\r\n totalDeposited,\r\n totalLpSupply,\r\n cooldownSlots,\r\n depositCap,\r\n totalFlushed,\r\n totalReturned,\r\n totalWithdrawn,\r\n percolatorProgram,\r\n pendingAdmin,\r\n totalFeesEarned,\r\n lastFeeAccrualSlot,\r\n lastVaultSnapshot,\r\n poolMode,\r\n hwmEnabled,\r\n epochHighWaterTvl,\r\n hwmFloorBps,\r\n hwmLastEpoch,\r\n trancheEnabled,\r\n juniorBalance,\r\n juniorTotalLp,\r\n juniorFeeMultBps,\r\n pendingCooldownSlots,\r\n cooldownProposedAtSlot,\r\n realizedJuniorLoss,\r\n assetAdminBurned,\r\n totalRecoveredFromWrapper,\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// StakeDeposit PDA decoder\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Size of StakeDeposit on-chain (bytes). */\r\nexport const STAKE_DEPOSIT_SIZE = 152;\r\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\r\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\r\n\r\n/** Decoded StakeDeposit PDA state. */\r\nexport interface StakeDepositState {\r\n isInitialized: boolean;\r\n bump: number;\r\n pool: PublicKey;\r\n user: PublicKey;\r\n lastDepositSlot: bigint;\r\n lpAmount: bigint;\r\n}\r\n\r\n/**\r\n * Decode a StakeDeposit PDA account from raw data.\r\n *\r\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\r\n * [0] is_initialized u8\r\n * [1] bump u8\r\n * [2..8] _padding\r\n * [8..40] pool [u8; 32]\r\n * [40..72] user [u8; 32]\r\n * [72..80] last_deposit_slot u64\r\n * [80..88] lp_amount u64\r\n * [88..152] _reserved\r\n */\r\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\r\n if (data.length < STAKE_DEPOSIT_SIZE) {\r\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\r\n }\r\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\r\n return {\r\n isInitialized: data[0] === 1,\r\n bump: data[1],\r\n pool: new PublicKey(data.subarray(8, 40)),\r\n user: new PublicKey(data.subarray(40, 72)),\r\n lastDepositSlot: readU64LE(data, 72),\r\n lpAmount: readU64LE(data, 80),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Account Specs (for building TransactionInstructions)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface StakeAccounts {\r\n /** InitPool accounts */\r\n initPool: {\r\n admin: PublicKey;\r\n slab: PublicKey;\r\n pool: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n collateralMint: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n /** Deposit accounts */\r\n deposit: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vault: PublicKey;\r\n lpMint: PublicKey;\r\n userLpAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** Withdraw accounts */\r\n withdraw: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userLpAta: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** FlushToInsurance accounts (CPI from stake → percolator) */\r\n flushToInsurance: {\r\n caller: PublicKey;\r\n pool: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n wrapperVault: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n}\r\n\r\n/**\r\n * Build account keys for InitPool instruction.\r\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\r\n *\r\n * @param a - Named accounts for the InitPool instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function initPoolAccounts(\r\n a: StakeAccounts['initPool'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Deposit instruction.\r\n *\r\n * @param a - Named accounts for the Deposit instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function depositAccounts(\r\n a: StakeAccounts['deposit'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Withdraw instruction.\r\n *\r\n * @param a - Named accounts for the Withdraw instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function withdrawAccounts(\r\n a: StakeAccounts['withdraw'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for FlushToInsurance instruction.\r\n *\r\n * @param a - Named accounts for the FlushToInsurance instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function flushToInsuranceAccounts(\r\n a: StakeAccounts['flushToInsurance'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.caller, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n","/**\r\n * @module adl\r\n * Percolator ADL (Auto-Deleveraging) client utilities.\r\n *\r\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\r\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\r\n * The most profitable positions on the dominant side are deleveraged first.\r\n *\r\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\r\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\r\n * instruction being structurally available to any signer.\r\n *\r\n * API surface:\r\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\r\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\r\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\r\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\r\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\r\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\r\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\r\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\r\n * - AdlRankingResult — full ranking with trigger status\r\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\r\n * - AdlApiRanking — single ranked position from /api/adl/rankings\r\n * - AdlApiResult — full result from /api/adl/rankings\r\n * - AdlSide — \"long\" | \"short\"\r\n */\r\n\r\nimport {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n} from \"@solana/web3.js\";\r\nimport {\r\n fetchSlab,\r\n parseAllAccounts,\r\n parseEngine,\r\n parseConfig,\r\n detectSlabLayout,\r\n AccountKind,\r\n Account,\r\n SlabLayout,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Position side derived from positionSize sign. */\r\nexport type AdlSide = \"long\" | \"short\";\r\n\r\nconst V17_ADL_UNSUPPORTED_MESSAGE =\r\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\r\n\r\n/**\r\n * A ranked open position for ADL purposes.\r\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\r\n * and will be deleveraged first.\r\n */\r\nexport interface AdlRankedPosition {\r\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\r\n idx: number;\r\n /** Owner public key. */\r\n owner: PublicKey;\r\n /** Raw position size (i128 — negative = short, positive = long). */\r\n positionSize: bigint;\r\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\r\n pnl: bigint;\r\n /** Capital at entry in lamports (u128). */\r\n capital: bigint;\r\n /**\r\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\r\n * pnlPct = pnl * 10_000 / capital.\r\n * Higher = more profitable = deleveraged first.\r\n */\r\n pnlPct: bigint;\r\n /** Long or short. */\r\n side: AdlSide;\r\n /**\r\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\r\n * `-1` if position size is zero (inactive).\r\n */\r\n adlRank: number;\r\n}\r\n\r\n/**\r\n * Result of `fetchAdlRankedPositions`.\r\n */\r\nexport interface AdlRankingResult {\r\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\r\n ranked: AdlRankedPosition[];\r\n /**\r\n * Longs ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\r\n */\r\n longs: AdlRankedPosition[];\r\n /**\r\n * Shorts ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\r\n * unrealised gain for the short-side holder).\r\n */\r\n shorts: AdlRankedPosition[];\r\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\r\n isTriggered: boolean;\r\n /** pnl_pos_tot from engine state. */\r\n pnlPosTot: bigint;\r\n /** max_pnl_cap from market config. */\r\n maxPnlCap: bigint;\r\n /**\r\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\r\n *\r\n * `null` when the side cannot be determined — either engine state could not be\r\n * parsed at all, OR the detected slab layout carries no open-interest fields.\r\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\r\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\r\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\r\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\r\n *\r\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\r\n * convention, not an on-chain guarantee — the deployed wrapper\r\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\r\n */\r\n dominantSide: AdlSide | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute PnL% in basis points for a position.\r\n * Returns 0n when capital is 0 to avoid division by zero.\r\n */\r\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\r\n if (capital === 0n) return 0n;\r\n return (pnl * 10_000n) / capital;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check whether ADL is currently triggered on a slab.\r\n *\r\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\r\n *\r\n * @param slabData - Raw slab account bytes.\r\n * @returns true if ADL is triggered.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = await fetchSlab(connection, slabKey);\r\n * if (isAdlTriggered(data)) {\r\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\r\n * }\r\n * ```\r\n */\r\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n if (!layout) return false;\r\n try {\r\n const engine = parseEngine(slabData);\r\n if (engine.pnlPosTot === 0n) return false;\r\n const config = parseConfig(slabData, layout);\r\n if (config.maxPnlCap === 0n) return false;\r\n return engine.pnlPosTot > config.maxPnlCap;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\r\n *\r\n * Positions are ranked separately per side:\r\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\r\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\r\n *\r\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\r\n * the position at rank 0 of the dominant side is deleveraged first.\r\n *\r\n * @param connection - Solana connection.\r\n * @param slab - Slab (market) public key.\r\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\r\n *\r\n * @example\r\n * ```ts\r\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\r\n * if (isTriggered && longs.length > 0) {\r\n * const target = longs[0]; // highest PnL long\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankedPositions(\r\n connection: Connection,\r\n slab: PublicKey\r\n): Promise {\r\n const data = await fetchSlab(connection, slab);\r\n return rankAdlPositions(data);\r\n}\r\n\r\n/**\r\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\r\n * Useful when you already have the slab data (e.g., from a subscription).\r\n */\r\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n\r\n let pnlPosTot = 0n;\r\n let dominantSide: AdlSide | null = null;\r\n try {\r\n const engine = parseEngine(slabData);\r\n pnlPosTot = engine.pnlPosTot;\r\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\r\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\r\n // comparing them would fabricate \"long\" from absent data.\r\n const hasOiFields =\r\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\r\n if (hasOiFields) {\r\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\r\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\r\n }\r\n } catch (err) {\r\n console.warn(\r\n `[rankAdlPositions] parseEngine failed:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n let maxPnlCap = 0n;\r\n let isTriggered = false;\r\n if (layout) {\r\n try {\r\n const config = parseConfig(slabData, layout);\r\n maxPnlCap = config.maxPnlCap;\r\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\r\n } catch {\r\n // If config parse fails, leave isTriggered=false; ranking still useful.\r\n }\r\n }\r\n\r\n // Parse all used accounts.\r\n const accounts = parseAllAccounts(slabData);\r\n\r\n // Build ranked position list (user accounts with non-zero position only).\r\n const positions: AdlRankedPosition[] = [];\r\n for (const { idx, account } of accounts) {\r\n if (account.kind !== AccountKind.User) continue;\r\n if (account.positionSize === 0n) continue;\r\n\r\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\r\n // For shorts, positionSize is negative — PnL computation is symmetric:\r\n // a short profits when price falls, so pnl stored in the slab already\r\n // reflects mark-to-market gain/loss for both sides.\r\n const pnlPct = computePnlPct(account.pnl, account.capital);\r\n\r\n positions.push({\r\n idx,\r\n owner: account.owner,\r\n positionSize: account.positionSize,\r\n pnl: account.pnl,\r\n capital: account.capital,\r\n pnlPct,\r\n side,\r\n adlRank: -1, // assigned below\r\n });\r\n }\r\n\r\n // Rank longs: descending pnlPct (most profitable first).\r\n const longs = positions\r\n .filter(p => p.side === \"long\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n longs.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\r\n // magnitude, but pnlPct can be negative; sort descending still puts\r\n // the \"least negative\" aka \"most profitable\" short first).\r\n const shorts = positions\r\n .filter(p => p.side === \"short\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n shorts.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\r\n const ranked = [...longs, ...shorts].sort(\r\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\r\n );\r\n\r\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\r\n}\r\n\r\n/**\r\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\r\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\r\n * utilities remain available.\r\n *\r\n * This function is kept as a deprecated compatibility stub so consumers get a\r\n * deterministic error instead of a lower-level removed-instruction throw.\r\n *\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key for this market.\r\n * @param programId - Percolator program ID.\r\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\r\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\r\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\r\n */\r\nexport function buildAdlInstruction(\r\n _caller: PublicKey,\r\n _slab: PublicKey,\r\n _oracle: PublicKey,\r\n _programId: PublicKey,\r\n targetIdx: number,\r\n _backupOracles: PublicKey[] = []\r\n): TransactionInstruction {\r\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\r\n throw new Error(\r\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\r\n );\r\n }\r\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\r\n}\r\n\r\n/**\r\n * Choose which ranked position an ADL should target.\r\n *\r\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\r\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\r\n * a test routed through it could not observe the choice.\r\n *\r\n * - An explicit `preferSide` always wins.\r\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\r\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\r\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\r\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\r\n * a candidate, nothing more.\r\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\r\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\r\n * rather than guessing a side.\r\n */\r\nexport function selectAdlTarget(\r\n ranking: Pick,\r\n preferSide?: AdlSide,\r\n): AdlRankedPosition | undefined {\r\n if (preferSide === \"long\") return ranking.longs[0];\r\n if (preferSide === \"short\") return ranking.shorts[0];\r\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\r\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\r\n return ranking.ranked[0];\r\n}\r\n\r\n/**\r\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\r\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\r\n *\r\n * Returns `null` when ADL is not triggered or no eligible positions exist.\r\n *\r\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\r\n * When a target IS found it calls `buildAdlInstruction`, which throws\r\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\r\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\r\n * revision of this note claimed it did, which was simply wrong.) It is kept for\r\n * v12 slabs and for when an equivalent v17 instruction lands; the target\r\n * selection in `selectAdlTarget` stays valid either way.\r\n *\r\n * @param connection - Solana connection.\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key.\r\n * @param programId - Percolator program ID.\r\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\r\n * If omitted, picks the dominant side's (greater net OI)\r\n * top-ranked position — or the overall top-ranked position\r\n * when dominantSide is null (engine unparseable, or a\r\n * layout with no OI fields such as V0/V2/v12.15).\r\n * @param backupOracles - Optional extra oracle accounts.\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = await buildAdlTransaction(\r\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\r\n * );\r\n * if (ix) {\r\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\r\n * }\r\n * ```\r\n */\r\nexport async function buildAdlTransaction(\r\n connection: Connection,\r\n caller: PublicKey,\r\n slab: PublicKey,\r\n oracle: PublicKey,\r\n programId: PublicKey,\r\n preferSide?: AdlSide,\r\n backupOracles: PublicKey[] = []\r\n): Promise {\r\n const ranking = await fetchAdlRankedPositions(connection, slab);\r\n\r\n if (!ranking.isTriggered) return null;\r\n\r\n const target = selectAdlTarget(ranking, preferSide);\r\n\r\n if (!target) return null;\r\n\r\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AdlEvent — on-chain log decoder (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\r\n *\r\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\r\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\r\n *\r\n * Fields:\r\n * - `tag` — always `0xAD1E_0001` (2970353665n)\r\n * - `targetIdx` — slab account index that was deleveraged\r\n * - `price` — oracle price used (in market price units, e.g. e6)\r\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\r\n *\r\n * @example\r\n * ```ts\r\n * const logs = tx.meta?.logMessages ?? [];\r\n * const event = parseAdlEvent(logs);\r\n * if (event) {\r\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\r\n * }\r\n * ```\r\n */\r\nexport interface AdlEvent {\r\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\r\n tag: bigint;\r\n /** Slab account index that was deleveraged. */\r\n targetIdx: number;\r\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\r\n price: bigint;\r\n /**\r\n * Absolute position size closed (reassembled from lo+hi u64).\r\n * This is the i128 absolute value — always non-negative.\r\n */\r\n closedAbs: bigint;\r\n}\r\n\r\n/** Magic discriminator for the ADL event log line. */\r\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\r\n\r\n/**\r\n * Parse the AdlEvent from a transaction's log messages.\r\n *\r\n * Searches for a \"Program log: \" line where the first\r\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\r\n *\r\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\r\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\r\n * by this program ID are accepted. Events from CPI-called programs (which can\r\n * produce identical `Program log:` lines) are silently ignored. Pass the\r\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\r\n * Omit only in contexts where the full log has already been filtered.\r\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\r\n *\r\n * @example\r\n * ```ts\r\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\r\n * if (event) {\r\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\r\n * }\r\n * ```\r\n */\r\nexport function parseAdlEvent(\r\n logs: string[],\r\n percolatorProgramId?: string,\r\n): AdlEvent | null {\r\n // Track whether we are currently inside a top-level Percolator invocation.\r\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\r\n let insidePercolator = percolatorProgramId === undefined;\r\n let cpiDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n if (percolatorProgramId !== undefined) {\r\n // Detect Percolator entry / exit.\r\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\r\n insidePercolator = true;\r\n cpiDepth = 0;\r\n continue;\r\n }\r\n if (\r\n line.startsWith(`Program ${percolatorProgramId} success`) ||\r\n line.startsWith(`Program ${percolatorProgramId} failed`)\r\n ) {\r\n insidePercolator = false;\r\n continue;\r\n }\r\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\r\n if (insidePercolator) {\r\n if (/^Program \\S+ invoke/.test(line)) {\r\n cpiDepth++;\r\n continue;\r\n }\r\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\r\n cpiDepth = Math.max(0, cpiDepth - 1);\r\n continue;\r\n }\r\n }\r\n // Skip log lines that are not inside Percolator or are from a CPI callee.\r\n if (!insidePercolator || cpiDepth > 0) continue;\r\n }\r\n\r\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\r\n const match = line.match(\r\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\r\n );\r\n if (!match) continue;\r\n\r\n let tag: bigint;\r\n try {\r\n tag = BigInt(match[1]);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (tag !== ADL_EVENT_TAG) continue;\r\n\r\n try {\r\n const targetIdx = Number(BigInt(match[2]));\r\n const price = BigInt(match[3]);\r\n const closedLo = BigInt(match[4]);\r\n const closedHi = BigInt(match[5]);\r\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\r\n const closedAbs = (closedHi << 64n) | closedLo;\r\n return { tag, targetIdx, price, closedAbs };\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A single ranked position as returned by the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiRanking {\r\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\r\n rank: number;\r\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\r\n idx: number;\r\n /** Absolute PnL (lamports) as a decimal string. */\r\n pnlAbs: string;\r\n /** Capital at entry (lamports) as a decimal string. */\r\n capital: string;\r\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\r\n pnlPctMillionths: string;\r\n}\r\n\r\n/**\r\n * Full result from the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiResult {\r\n slabAddress: string;\r\n /** pnl_pos_tot from slab engine state (decimal string). */\r\n pnlPosTot: string;\r\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\r\n maxPnlCap: string;\r\n /** Insurance fund balance (decimal string). */\r\n insuranceFundBalance: string;\r\n /** Insurance fund lifetime fee revenue (decimal string). */\r\n insuranceFundFeeRevenue: string;\r\n /** Insurance utilization in basis points (0–10000). */\r\n insuranceUtilizationBps: number;\r\n /** true if pnlPosTot > maxPnlCap. */\r\n capExceeded: boolean;\r\n /** true if insurance fund is fully depleted (balance == 0). */\r\n insuranceDepleted: boolean;\r\n /** true if utilization BPS exceeds the configured ADL threshold. */\r\n utilizationTriggered: boolean;\r\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\r\n adlNeeded: boolean;\r\n /** Excess PnL above cap (decimal string). */\r\n excess: string;\r\n /** Ranked positions (empty if adlNeeded=false). */\r\n rankings: AdlApiRanking[];\r\n}\r\n\r\n/**\r\n * Fetch ADL rankings from the Percolator API.\r\n *\r\n * Calls `GET /api/adl/rankings?slab=
` and returns the\r\n * parsed result. Use this from the frontend or keeper to determine ADL\r\n * trigger status and pick the target index.\r\n *\r\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\r\n * @param slab - Slab (market) public key or base58 address string.\r\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\r\n * @returns Parsed `AdlApiResult`.\r\n * @throws On HTTP error or JSON parse failure.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\r\n * if (result.adlNeeded && result.rankings.length > 0) {\r\n * const target = result.rankings[0]; // rank 1 = highest PnL%\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankings(\r\n apiBase: string,\r\n slab: PublicKey | string,\r\n fetchFn: typeof fetch = fetch,\r\n): Promise {\r\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\r\n const base = apiBase.replace(/\\/$/, \"\");\r\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\r\n\r\n const res = await fetchFn(url);\r\n if (!res.ok) {\r\n let body = \"\";\r\n try { body = await res.text(); } catch { /* ignore */ }\r\n throw new Error(\r\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\r\n );\r\n }\r\n\r\n const json: unknown = await res.json();\r\n\r\n // Runtime validation — the API response shape is not guaranteed\r\n if (typeof json !== \"object\" || json === null) {\r\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\r\n }\r\n const obj = json as Record;\r\n if (!Array.isArray(obj.rankings)) {\r\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\r\n }\r\n if (typeof obj.adlNeeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\r\n }\r\n if (typeof obj.capExceeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\r\n }\r\n if (typeof obj.slabAddress !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\r\n }\r\n if (typeof obj.pnlPosTot !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\r\n }\r\n if (typeof obj.maxPnlCap !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\r\n }\r\n for (const entry of obj.rankings) {\r\n if (typeof entry !== \"object\" || entry === null) {\r\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\r\n }\r\n const r = entry as Record;\r\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\r\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\r\n }\r\n }\r\n\r\n return json as AdlApiResult;\r\n}\r\n","/**\r\n * @module backing-bucket\r\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\r\n *\r\n * ## Why this module exists\r\n *\r\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\r\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\r\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\r\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\r\n * predicate.\r\n *\r\n * ## Why lapsing is routine, not exceptional\r\n *\r\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\r\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\r\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\r\n * bucket and only computes a fresh horizon once the bucket is no longer\r\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\r\n * far-future expiry defers the lapse; it does not prevent it.\r\n *\r\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\r\n *\r\n * | Attempt against a lapsed domain | Result |\r\n * |---|---|\r\n * | settle a **loss** | `EngineLockActive` Custom(21) |\r\n * | settle a **gain** | `EngineStale` Custom(19) |\r\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\r\n *\r\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\r\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\r\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\r\n * keeper duty, alongside the fee crank.\r\n *\r\n * ## Layout provenance\r\n *\r\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\r\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\r\n *\r\n * ```\r\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\r\n * BackingBucketV16Account size=97\r\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\r\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\r\n * 88 expiry_slot 96 status\r\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\r\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\r\n * ```\r\n *\r\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\r\n */\r\n\r\nimport {\r\n V17_MARKET_GROUP_OFF,\r\n V17_MARKET_GROUP_LEN,\r\n V17_MARKET_ASSET_SLOT_LEN,\r\n isV17MarketAccount,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Little-endian readers (module-local, matching slab.ts's private helpers)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8At(data: Uint8Array, off: number): number {\r\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\r\n return data[off]!;\r\n}\r\n\r\nfunction readU32LEAt(data: Uint8Array, off: number): number {\r\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\r\n}\r\n\r\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\r\n}\r\n\r\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\r\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\r\n const lo = dv.getBigUint64(0, true);\r\n const hi = dv.getBigUint64(8, true);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Layout constants — all verified with offset_of! (see module doc)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\r\nexport const V17_GROUP_CONFIG_REL = 32;\r\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\r\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\r\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\r\nexport const V17_GROUP_MODE_REL = 626;\r\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\r\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\r\n\r\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\r\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\r\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\r\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\r\n/** `size_of::()`. */\r\nexport const V17_BACKING_BUCKET_LEN = 97;\r\n\r\n// BackingBucketV16Account field offsets, relative to the bucket start.\r\nconst BB_MARKET_ID = 0;\r\nconst BB_FRESH_UNLIENED = 8;\r\nconst BB_VALID_LIENED = 24;\r\nconst BB_CONSUMED_LIENED = 40;\r\nconst BB_IMPAIRED_LIENED = 56;\r\nconst BB_UTILIZATION_FEE = 72;\r\nconst BB_EXPIRY_SLOT = 88;\r\nconst BB_STATUS = 96;\r\n\r\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\r\nexport const V17_MARKET_MODE_LIVE = 0;\r\n\r\n/**\r\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\r\n * serialized as a single `u8` in declaration order.\r\n *\r\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\r\n */\r\nexport enum BackingBucketStatus {\r\n Empty = 0,\r\n Fresh = 1,\r\n Expired = 2,\r\n Impaired = 3,\r\n}\r\n\r\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\r\nexport function backingBucketStatusName(status: number): string {\r\n switch (status) {\r\n case BackingBucketStatus.Empty:\r\n return \"Empty\";\r\n case BackingBucketStatus.Fresh:\r\n return \"Fresh\";\r\n case BackingBucketStatus.Expired:\r\n return \"Expired\";\r\n case BackingBucketStatus.Impaired:\r\n return \"Impaired\";\r\n default:\r\n return `Unknown(${status})`;\r\n }\r\n}\r\n\r\n/** One source-domain backing bucket, decoded from a v17 market account. */\r\nexport interface BackingBucketV17 {\r\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\r\n domain: number;\r\n /** `domain / 2` — the asset slot this domain belongs to. */\r\n assetIndex: number;\r\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\r\n side: \"long\" | \"short\";\r\n /** `BackingBucketV16Account::market_id`. */\r\n marketId: bigint;\r\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\r\n freshUnlienedBackingNum: bigint;\r\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\r\n validLienedBackingNum: bigint;\r\n /** Principal already consumed by settlement. */\r\n consumedLienedBackingNum: bigint;\r\n /** Principal whose lien has been impaired. */\r\n impairedLienedBackingNum: bigint;\r\n /** Utilization fees accrued to this bucket. */\r\n utilizationFeeEarnings: bigint;\r\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\r\n expirySlot: bigint;\r\n /** Raw status byte. */\r\n status: number;\r\n /** `backingBucketStatusName(status)`. */\r\n statusName: string;\r\n /**\r\n * `status === Fresh && nowSlot >= expirySlot`.\r\n *\r\n * This is the *deadlock* condition — settlement against this domain fails in both\r\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\r\n * which additionally applies the wrapper's mode and domain-bound gates.\r\n */\r\n lapsed: boolean;\r\n /**\r\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\r\n * See {@link isBackingBucketExpirable} for the full derivation.\r\n */\r\n expirable: boolean;\r\n}\r\n\r\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\r\nexport interface BackingBucketMarketState {\r\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\r\n mode: number;\r\n /** `header.current_slot` — the engine's own monotone slot counter. */\r\n headerCurrentSlot: bigint;\r\n /**\r\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\r\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\r\n */\r\n nowSlot: bigint;\r\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\r\n maxMarketSlots: number;\r\n /** Asset slots physically present in the account buffer. */\r\n physicalAssetSlots: number;\r\n /**\r\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\r\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\r\n * this index are never expirable; see {@link isBackingBucketExpirable}.\r\n */\r\n addressableDomainCount: number;\r\n /** One entry per addressable domain, ascending by `domain`. */\r\n buckets: BackingBucketV17[];\r\n}\r\n\r\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\r\nexport interface BackingBucketExpiryContext {\r\n /** `header.mode`. */\r\n mode: number;\r\n /** `max(chainSlot, header.current_slot)`. */\r\n nowSlot: bigint;\r\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\r\n addressableDomainCount: number;\r\n}\r\n\r\n/**\r\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\r\n *\r\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\r\n * program rather than from prose. In order of evaluation on chain:\r\n *\r\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\r\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\r\n * market reaches the same transition through the engine's own\r\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\r\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\r\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\r\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\r\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\r\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\r\n * may be *configured* for more slots than its account was *sized* for.\r\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\r\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\r\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\r\n * both deadlocked and expirable, and the two boundaries agree\r\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\r\n *\r\n * `now_slot` is never caller-supplied — the program computes\r\n * `max(Clock::get().slot, header.current_slot)` itself\r\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\r\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\r\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\r\n * bricked. It cannot produce a false positive, because the program recomputes the same\r\n * `max` and no caller can lower it.\r\n *\r\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\r\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\r\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\r\n * two more u128 reads to defend against something that indicates corruption anyway.\r\n *\r\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\r\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\r\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\r\n *\r\n * @example\r\n * ```ts\r\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\r\n * for (const b of state.buckets) {\r\n * if (isBackingBucketExpirable(b, state)) {\r\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isBackingBucketExpirable(\r\n bucket: Pick,\r\n ctx: BackingBucketExpiryContext,\r\n): boolean {\r\n // (1) Live-only mode gate.\r\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\r\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\r\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\r\n // (4) The lapse condition, exactly as the engine states it.\r\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\r\n return ctx.nowSlot >= bucket.expirySlot;\r\n}\r\n\r\n/** Options for {@link parseBackingBucketsV17}. */\r\nexport interface ParseBackingBucketsOptions {\r\n /**\r\n * The current chain slot (`connection.getSlot()`).\r\n *\r\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\r\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\r\n * lapses, never over-report them) but a keeper should always supply it — a market whose\r\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\r\n * bricked.\r\n */\r\n chainSlot?: bigint | number;\r\n}\r\n\r\n/**\r\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\r\n *\r\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\r\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\r\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\r\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\r\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketPk);\r\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\r\n * chainSlot: await connection.getSlot(),\r\n * });\r\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\r\n * ```\r\n */\r\nexport function parseBackingBucketsV17(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): BackingBucketMarketState {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n const groupOff = V17_MARKET_GROUP_OFF;\r\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\r\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\r\n const maxMarketSlots = readU32LEAt(\r\n data,\r\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\r\n );\r\n\r\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\r\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\r\n const chainSlot =\r\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\r\n if (chainSlot < 0n) {\r\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\r\n }\r\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\r\n\r\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\r\n const physicalAssetSlots = Math.max(\r\n 0,\r\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\r\n );\r\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\r\n const addressableDomainCount = addressableAssetSlots * 2;\r\n\r\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\r\n const buckets: BackingBucketV17[] = [];\r\n\r\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\r\n const engineBase =\r\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\r\n for (const side of [\"long\", \"short\"] as const) {\r\n const bucketOff =\r\n engineBase +\r\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\r\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\r\n\r\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\r\n const status = readU8At(data, bucketOff + BB_STATUS);\r\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\r\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\r\n\r\n const bucket: BackingBucketV17 = {\r\n domain,\r\n assetIndex,\r\n side,\r\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\r\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\r\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\r\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\r\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\r\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\r\n expirySlot,\r\n status,\r\n statusName: backingBucketStatusName(status),\r\n lapsed,\r\n expirable: false,\r\n };\r\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\r\n buckets.push(bucket);\r\n }\r\n }\r\n\r\n return {\r\n mode,\r\n headerCurrentSlot,\r\n nowSlot,\r\n maxMarketSlots,\r\n physicalAssetSlots,\r\n addressableDomainCount,\r\n buckets,\r\n };\r\n}\r\n\r\n/**\r\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\r\n *\r\n * Returns domain indices in ascending order, ready to feed straight into\r\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\r\n * common case on a healthy market, and the case in which a keeper must send nothing.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns Ascending list of expirable domain indices; empty when none are due.\r\n *\r\n * @example\r\n * ```ts\r\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\r\n * for (const domain of domains) {\r\n * tx.add(new TransactionInstruction({\r\n * programId: WRAPPER_ID,\r\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\r\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\r\n * }));\r\n * }\r\n * ```\r\n */\r\nexport function findExpirableBackingDomains(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): number[] {\r\n return parseBackingBucketsV17(data, opts)\r\n .buckets.filter((b) => b.expirable)\r\n .map((b) => b.domain);\r\n}\r\n","import {\r\n Connection,\r\n type Commitment,\r\n type ConnectionConfig,\r\n} from \"@solana/web3.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Configuration for exponential-backoff retry on RPC calls.\r\n *\r\n * @example\r\n * ```ts\r\n * const retryConfig: RetryConfig = {\r\n * maxRetries: 3,\r\n * baseDelayMs: 500,\r\n * maxDelayMs: 10_000,\r\n * retryableStatusCodes: [429, 502, 503],\r\n * };\r\n * ```\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts after the initial request fails.\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Base delay in ms for exponential backoff.\r\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\r\n * @default 500\r\n */\r\n baseDelayMs?: number;\r\n\r\n /**\r\n * Maximum delay in ms (backoff cap).\r\n * @default 10_000\r\n */\r\n maxDelayMs?: number;\r\n\r\n /**\r\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\r\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\r\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\r\n * jitter entirely (deterministic backoff).\r\n * @default 0.25\r\n */\r\n jitterFactor?: number;\r\n\r\n /**\r\n * HTTP status codes considered retryable.\r\n * Errors matching these codes (or containing their string representation)\r\n * will be retried.\r\n * @default [429, 502, 503, 504]\r\n */\r\n retryableStatusCodes?: number[];\r\n}\r\n\r\n/**\r\n * Configuration for a single RPC endpoint in the pool.\r\n *\r\n * @example\r\n * ```ts\r\n * const endpoint: RpcEndpointConfig = {\r\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\r\n * weight: 10,\r\n * label: \"helius-primary\",\r\n * };\r\n * ```\r\n */\r\nexport interface RpcEndpointConfig {\r\n /** RPC endpoint URL. */\r\n url: string;\r\n\r\n /**\r\n * Relative weight for round-robin selection.\r\n * Higher weight = more requests routed here.\r\n * @default 1\r\n */\r\n weight?: number;\r\n\r\n /**\r\n * Human-readable label for logging / diagnostics.\r\n * @default url hostname\r\n */\r\n label?: string;\r\n\r\n /**\r\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\r\n * merged into the Solana `Connection` constructor for this endpoint.\r\n */\r\n connectionConfig?: ConnectionConfig;\r\n}\r\n\r\n/**\r\n * Strategy for selecting the next RPC endpoint from the pool.\r\n *\r\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\r\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\r\n */\r\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\r\n\r\n/**\r\n * Full configuration for the RPC connection pool.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3, baseDelayMs: 500 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Use like a Connection — same surface\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n * ```\r\n */\r\nexport interface RpcPoolConfig {\r\n /**\r\n * One or more RPC endpoints. At least one is required.\r\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\r\n */\r\n endpoints: (RpcEndpointConfig | string)[];\r\n\r\n /**\r\n * How to pick the next endpoint.\r\n * @default \"failover\"\r\n */\r\n strategy?: SelectionStrategy;\r\n\r\n /**\r\n * Retry config applied to every `call()`.\r\n * Set to `false` to disable retries entirely.\r\n * @default { maxRetries: 3, baseDelayMs: 500 }\r\n */\r\n retry?: RetryConfig | false;\r\n\r\n /**\r\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\r\n * calls where supported, and is used as a deadline for the health probe.\r\n * @default 30_000\r\n */\r\n requestTimeoutMs?: number;\r\n\r\n /**\r\n * Default Solana commitment level for connections.\r\n * @default \"confirmed\"\r\n */\r\n commitment?: Commitment;\r\n\r\n /**\r\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n\r\n /**\r\n * Time in ms after which a continuously unhealthy endpoint is automatically\r\n * restored to healthy so it can be retried. Set to 0 to disable time-based\r\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\r\n * endpoints are exhausted).\r\n * @default 60_000\r\n */\r\n recoveryAfterMs?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Health Probe\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Result of an RPC health probe.\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\r\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\r\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\r\n * ```\r\n */\r\nexport interface RpcHealthResult {\r\n /** The endpoint that was probed. */\r\n endpoint: string;\r\n /** Whether the probe succeeded (getSlot returned without error). */\r\n healthy: boolean;\r\n /** Round-trip latency in milliseconds (0 if unhealthy). */\r\n latencyMs: number;\r\n /** Current slot height (0 if unhealthy). */\r\n slot: number;\r\n /** Error message if the probe failed. */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\r\n *\r\n * @param endpoint - RPC URL to probe\r\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\r\n * @returns Health result with latency and slot height\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\r\n * if (result.healthy) {\r\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\r\n * } else {\r\n * console.error(`RPC down: ${result.error}`);\r\n * }\r\n * ```\r\n */\r\nexport async function checkRpcHealth(\r\n endpoint: string,\r\n timeoutMs: number = 5_000,\r\n): Promise {\r\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\r\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\r\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\r\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\r\n const start = performance.now();\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: 1,\r\n method: \"getSlot\",\r\n params: [{ commitment: \"processed\" }],\r\n }),\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n const latencyMs = Math.round(performance.now() - start);\r\n if (!res.ok) {\r\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\r\n }\r\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\r\n if (json?.error || typeof json?.result !== \"number\") {\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: json?.error?.message ?? \"invalid getSlot response\",\r\n };\r\n }\r\n return { endpoint, healthy: true, latencyMs, slot: json.result };\r\n } catch (err) {\r\n const latencyMs = Math.round(performance.now() - start);\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved defaults for RetryConfig. */\r\ninterface ResolvedRetryConfig {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n jitterFactor: number;\r\n retryableStatusCodes: number[];\r\n}\r\n\r\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\r\n if (cfg === false) return null;\r\n const c = cfg ?? {};\r\n return {\r\n maxRetries: c.maxRetries ?? 3,\r\n baseDelayMs: c.baseDelayMs ?? 500,\r\n maxDelayMs: c.maxDelayMs ?? 10_000,\r\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\r\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\r\n };\r\n}\r\n\r\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\r\n if (typeof ep === \"string\") return { url: ep };\r\n return ep;\r\n}\r\n\r\nfunction endpointLabel(ep: RpcEndpointConfig): string {\r\n if (ep.label) return ep.label;\r\n try {\r\n return new URL(ep.url).hostname;\r\n } catch {\r\n return ep.url.slice(0, 40);\r\n }\r\n}\r\n\r\nfunction isRetryable(err: unknown, codes: number[]): boolean {\r\n if (!err) return false;\r\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\r\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\r\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\r\n // error shapes by name BEFORE any substring match below.\r\n const errName = (err as { name?: unknown })?.name;\r\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n for (const code of codes) {\r\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\r\n let timer: ReturnType;\r\n const promise = new Promise((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(message)), ms);\r\n });\r\n return { promise, cancel: () => clearTimeout(timer!) };\r\n}\r\n\r\n/** Sleep utility. */\r\nfunction sleep(ms: number): Promise {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\r\n * key, password) from a URL so it is safe for logging / status output.\r\n */\r\nfunction redactUrl(raw: string): string {\r\n try {\r\n const u = new URL(raw);\r\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\r\n for (const k of [...u.searchParams.keys()]) {\r\n if (sensitive.test(k)) {\r\n u.searchParams.set(k, \"***\");\r\n }\r\n }\r\n return u.toString();\r\n } catch {\r\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\r\n return raw;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// RpcPool\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-endpoint tracked state. */\r\ninterface EndpointState {\r\n config: RpcEndpointConfig;\r\n connection: Connection;\r\n label: string;\r\n weight: number;\r\n /** Consecutive failure count. Resets on success. */\r\n failures: number;\r\n /** Whether this endpoint is considered healthy. */\r\n healthy: boolean;\r\n /** Last probe latency (ms), -1 if never probed. */\r\n lastLatencyMs: number;\r\n /**\r\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\r\n * failure streak. Cleared on success or manual recovery. Used by the\r\n * time-based auto-recovery logic in `selectEndpoint`.\r\n */\r\n unhealthySince?: number;\r\n}\r\n\r\n/**\r\n * RPC connection pool with retry, failover, and round-robin support.\r\n *\r\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\r\n * that automatically retries transient errors and fails over to alternate\r\n * endpoints when one goes down.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Execute any Connection method through the pool\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n *\r\n * // Or get a raw connection for one-off use\r\n * const conn = pool.getConnection();\r\n *\r\n * // Health check all endpoints\r\n * const results = await pool.healthCheck();\r\n * ```\r\n */\r\nexport class RpcPool {\r\n private readonly endpoints: EndpointState[];\r\n private readonly strategy: SelectionStrategy;\r\n private readonly retryConfig: ResolvedRetryConfig | null;\r\n private readonly requestTimeoutMs: number;\r\n private readonly verbose: boolean;\r\n /** Time-based recovery window in ms (0 = disabled). */\r\n private readonly recoveryAfterMs: number;\r\n\r\n /** Round-robin index tracker. */\r\n private rrIndex: number = 0;\r\n\r\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\r\n private static readonly UNHEALTHY_THRESHOLD = 3;\r\n\r\n /** Minimum endpoints before auto-recovery is attempted. */\r\n private static readonly MIN_HEALTHY = 1;\r\n\r\n constructor(config: RpcPoolConfig) {\r\n if (!config.endpoints || config.endpoints.length === 0) {\r\n throw new Error(\"RpcPool: at least one endpoint is required\");\r\n }\r\n\r\n this.strategy = config.strategy ?? \"failover\";\r\n this.retryConfig = resolveRetryConfig(config.retry);\r\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\r\n this.verbose = config.verbose ?? true;\r\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\r\n\r\n const commitment = config.commitment ?? \"confirmed\";\r\n\r\n this.endpoints = config.endpoints.map(raw => {\r\n const ep = normalizeEndpoint(raw);\r\n const connConfig: ConnectionConfig = {\r\n commitment,\r\n ...ep.connectionConfig,\r\n };\r\n return {\r\n config: ep,\r\n connection: new Connection(ep.url, connConfig),\r\n label: endpointLabel(ep),\r\n weight: Math.max(1, ep.weight ?? 1),\r\n failures: 0,\r\n healthy: true,\r\n lastLatencyMs: -1,\r\n };\r\n });\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Public API\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Execute a function against a pooled connection with automatic retry\r\n * and failover.\r\n *\r\n * @param fn - Async function that receives a `Connection` and returns a result.\r\n * @returns The result of `fn`.\r\n * @throws The last error if all retries and failovers are exhausted.\r\n *\r\n * @example\r\n * ```ts\r\n * const balance = await pool.call(c => c.getBalance(pubkey));\r\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\r\n * ```\r\n */\r\n async call(fn: (connection: Connection) => Promise): Promise {\r\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\r\n let lastError: unknown;\r\n\r\n // Track which endpoints we have tried in this call to avoid infinite loops.\r\n const triedEndpoints = new Set();\r\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\r\n const maxTotalIterations = maxAttempts + this.endpoints.length;\r\n let totalIterations = 0;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (++totalIterations > maxTotalIterations) break;\r\n const epIdx = this.selectEndpoint(triedEndpoints);\r\n if (epIdx === -1) {\r\n // All endpoints exhausted\r\n break;\r\n }\r\n const ep = this.endpoints[epIdx];\r\n\r\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\r\n try {\r\n const result = await Promise.race([\r\n fn(ep.connection),\r\n timeout.promise,\r\n ]);\r\n\r\n // Success — reset failure count\r\n ep.failures = 0;\r\n ep.healthy = true;\r\n ep.unhealthySince = undefined;\r\n return result;\r\n } catch (err) {\r\n lastError = err;\r\n ep.failures++;\r\n\r\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\r\n ep.healthy = false;\r\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\r\n );\r\n }\r\n }\r\n\r\n const retryable = this.retryConfig\r\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\r\n : false;\r\n\r\n if (!retryable) {\r\n // For non-retryable errors in failover mode, try the next endpoint\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n // Don't count this as a retry attempt — just failover\r\n attempt--;\r\n if (triedEndpoints.size >= this.endpoints.length) break;\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Retryable error\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n // In failover mode, try next endpoint before retrying same one\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n }\r\n\r\n // Backoff before retry\r\n if (attempt < maxAttempts - 1 && this.retryConfig) {\r\n const delay = computeDelay(attempt, this.retryConfig);\r\n await sleep(delay);\r\n }\r\n } finally {\r\n timeout.cancel();\r\n }\r\n }\r\n\r\n // All attempts exhausted — try recovery before giving up\r\n this.maybeRecoverEndpoints();\r\n\r\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\r\n }\r\n\r\n /**\r\n * Get a raw `Connection` from the current preferred endpoint.\r\n * Useful when you need to pass a Connection to external code.\r\n *\r\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\r\n *\r\n * @returns Solana Connection from the current preferred endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const conn = pool.getConnection();\r\n * const balance = await conn.getBalance(pubkey);\r\n * ```\r\n */\r\n getConnection(): Connection {\r\n const idx = this.selectEndpoint();\r\n if (idx === -1) {\r\n // All marked unhealthy — reset and use first\r\n this.maybeRecoverEndpoints();\r\n return this.endpoints[0].connection;\r\n }\r\n return this.endpoints[idx].connection;\r\n }\r\n\r\n /**\r\n * Run a health check against all endpoints in the pool.\r\n *\r\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\r\n * @returns Array of health results, one per endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await pool.healthCheck();\r\n * for (const r of results) {\r\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\r\n * }\r\n * ```\r\n */\r\n async healthCheck(timeoutMs: number = 5_000): Promise {\r\n const results = await Promise.all(\r\n this.endpoints.map(async (ep) => {\r\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\r\n ep.lastLatencyMs = result.latencyMs;\r\n ep.healthy = result.healthy;\r\n if (result.healthy) {\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n result.endpoint = redactUrl(result.endpoint);\r\n return result;\r\n }),\r\n );\r\n return results;\r\n }\r\n\r\n /**\r\n * Get the number of endpoints in the pool.\r\n */\r\n get size(): number {\r\n return this.endpoints.length;\r\n }\r\n\r\n /**\r\n * Get the number of currently healthy endpoints.\r\n */\r\n get healthyCount(): number {\r\n return this.endpoints.filter(ep => ep.healthy).length;\r\n }\r\n\r\n /**\r\n * Get endpoint labels and their current status.\r\n *\r\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\r\n */\r\n status(): Array<{\r\n label: string;\r\n url: string;\r\n healthy: boolean;\r\n failures: number;\r\n lastLatencyMs: number;\r\n }> {\r\n return this.endpoints.map(ep => ({\r\n label: ep.label,\r\n url: redactUrl(ep.config.url),\r\n healthy: ep.healthy,\r\n failures: ep.failures,\r\n lastLatencyMs: ep.lastLatencyMs,\r\n }));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Internals\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Select the next endpoint based on strategy.\r\n * Returns -1 if no endpoint is available.\r\n */\r\n private selectEndpoint(exclude?: Set): number {\r\n // Time-based auto-recovery: restore endpoints that have been unhealthy\r\n // for longer than recoveryAfterMs so they can be retried.\r\n if (this.recoveryAfterMs > 0) {\r\n const now = Date.now();\r\n for (const ep of this.endpoints) {\r\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n if (this.verbose) {\r\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthy = this.endpoints\r\n .map((ep, i) => ({ ep, i }))\r\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\r\n\r\n if (healthy.length === 0) {\r\n // No healthy endpoints — try all non-excluded\r\n const remaining = this.endpoints\r\n .map((_, i) => i)\r\n .filter(i => !(exclude?.has(i)));\r\n return remaining.length > 0 ? remaining[0] : -1;\r\n }\r\n\r\n if (this.strategy === \"failover\") {\r\n // Return first healthy (by insertion order)\r\n return healthy[0].i;\r\n }\r\n\r\n // Weighted round-robin\r\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\r\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\r\n\r\n let cumulative = 0;\r\n for (const { ep, i } of healthy) {\r\n cumulative += ep.weight;\r\n if (this.rrIndex < cumulative) return i;\r\n }\r\n\r\n return healthy[healthy.length - 1].i;\r\n }\r\n\r\n /**\r\n * If all endpoints are unhealthy, reset them so we at least try again.\r\n */\r\n private maybeRecoverEndpoints(): void {\r\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\r\n if (healthyCount < RpcPool.MIN_HEALTHY) {\r\n if (this.verbose) {\r\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\r\n }\r\n for (const ep of this.endpoints) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone retry wrapper (for use without a full pool)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute an async function with exponential-backoff retry.\r\n *\r\n * Use this when you already have a `Connection` and just want retry logic\r\n * without a full pool.\r\n *\r\n * @param fn - Async function to execute\r\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\r\n * @returns Result of `fn`\r\n * @throws The last error if all retries are exhausted\r\n *\r\n * @example\r\n * ```ts\r\n * import { withRetry } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const slot = await withRetry(\r\n * () => conn.getSlot(),\r\n * { maxRetries: 3, baseDelayMs: 1000 },\r\n * );\r\n * ```\r\n */\r\nexport async function withRetry(\r\n fn: () => Promise,\r\n config?: RetryConfig,\r\n): Promise {\r\n const resolved = resolveRetryConfig(config) ?? {\r\n maxRetries: 3,\r\n baseDelayMs: 500,\r\n maxDelayMs: 10_000,\r\n jitterFactor: 0.25,\r\n retryableStatusCodes: [429, 502, 503, 504],\r\n };\r\n\r\n let lastError: unknown;\r\n const maxAttempts = resolved.maxRetries + 1;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (err) {\r\n lastError = err;\r\n\r\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\r\n throw err;\r\n }\r\n\r\n if (attempt < maxAttempts - 1) {\r\n const delay = computeDelay(attempt, resolved);\r\n await sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-export helpers for testing\r\n// ---------------------------------------------------------------------------\r\n\r\n/** @internal — exposed for unit tests only */\r\nexport const _internal = {\r\n isRetryable,\r\n computeDelay,\r\n resolveRetryConfig,\r\n normalizeEndpoint,\r\n endpointLabel,\r\n} as const;\r\n","import {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n Transaction,\r\n Keypair,\r\n SendOptions,\r\n Commitment,\r\n AccountMeta,\r\n ComputeBudgetProgram,\r\n} from \"@solana/web3.js\";\r\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\r\n\r\n/**\r\n * Rank of the three cluster confirmation levels the RPC reports in\r\n * `SignatureStatus.confirmationStatus`.\r\n */\r\nconst CONFIRMATION_RANK = {\r\n processed: 0,\r\n confirmed: 1,\r\n finalized: 2,\r\n} as const;\r\n\r\n/**\r\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\r\n * The deprecated aliases map onto their modern equivalents exactly as\r\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\r\n * recent -> processed.\r\n */\r\nfunction requiredConfirmationRank(commitment: Commitment): number {\r\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\r\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\r\n // aliases as:\r\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\r\n // 'finalized' | 'max' | 'root' -> requires finalized\r\n // everything else ('processed', 'recent') -> requires >= processed\r\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\r\n // meant a caller asking for `singleGossip` and observing only a `processed`\r\n // status was told the transaction had SETTLED — reintroducing exactly the\r\n // premature-settlement bug this function exists to prevent.\r\n switch (commitment) {\r\n case \"confirmed\":\r\n case \"single\":\r\n case \"singleGossip\":\r\n return CONFIRMATION_RANK.confirmed;\r\n case \"finalized\":\r\n case \"max\":\r\n case \"root\":\r\n return CONFIRMATION_RANK.finalized;\r\n case \"processed\":\r\n case \"recent\":\r\n default:\r\n return CONFIRMATION_RANK.processed;\r\n }\r\n}\r\n\r\n/**\r\n * True when an observed signature status is at least as strong as the level the\r\n * caller asked for. A merely \"processed\" transaction can still be dropped or\r\n * rolled back, so treating it as settled would reintroduce exactly the premature\r\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\r\n */\r\nfunction meetsCommitment(\r\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\r\n required: Commitment\r\n): boolean {\r\n if (!observed) return false;\r\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\r\n}\r\n\r\nexport interface BuildIxParams {\r\n programId: PublicKey;\r\n keys: AccountMeta[];\r\n data: Uint8Array | Buffer;\r\n}\r\n\r\n/**\r\n * Build a transaction instruction.\r\n */\r\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\r\n return new TransactionInstruction({\r\n programId: params.programId,\r\n keys: params.keys,\r\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\r\n // Cast to avoid Buffer polyfill issues in the browser.\r\n data: params.data as Buffer,\r\n });\r\n}\r\n\r\nexport interface TxResult {\r\n signature: string;\r\n slot: number;\r\n err: string | null;\r\n hint?: string;\r\n logs: string[];\r\n unitsConsumed?: number;\r\n}\r\n\r\nexport interface SimulateOrSendParams {\r\n connection: Connection;\r\n ix: TransactionInstruction;\r\n signers: Keypair[];\r\n simulate: boolean;\r\n commitment?: Commitment;\r\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\r\n /**\r\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\r\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\r\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\r\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\r\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\r\n * multiple of 1024 in [32768, 262144].\r\n */\r\n heapFrameBytes?: number;\r\n}\r\n\r\n/**\r\n * Simulate or send a transaction.\r\n * Returns consistent output for both modes.\r\n */\r\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\r\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\r\n\r\n/**\r\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\r\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\r\n */\r\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\r\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\r\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\r\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\r\n\r\nexport async function simulateOrSend(\r\n params: SimulateOrSendParams\r\n): Promise {\r\n const {\r\n connection,\r\n ix,\r\n signers,\r\n simulate,\r\n commitment,\r\n computeUnitLimit,\r\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\r\n } = params;\r\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\r\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\r\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\r\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\r\n\r\n if (typeof simulate !== \"boolean\") {\r\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\r\n }\r\n\r\n if (!signers.length) {\r\n throw new Error(\"simulateOrSend: at least one signer is required\");\r\n }\r\n\r\n if (computeUnitLimit !== undefined) {\r\n if (\r\n typeof computeUnitLimit !== \"number\" ||\r\n !Number.isInteger(computeUnitLimit) ||\r\n computeUnitLimit < 1 ||\r\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\r\n ) {\r\n throw new Error(\r\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\r\n );\r\n }\r\n }\r\n\r\n if (heapFrameBytes !== 0) {\r\n if (\r\n typeof heapFrameBytes !== \"number\" ||\r\n !Number.isInteger(heapFrameBytes) ||\r\n heapFrameBytes % 1024 !== 0 ||\r\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\r\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\r\n ) {\r\n throw new Error(\r\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\r\n );\r\n }\r\n }\r\n\r\n const tx = new Transaction();\r\n\r\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\r\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\r\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\r\n if (heapFrameBytes !== 0) {\r\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\r\n }\r\n\r\n // Add compute budget instruction if custom limit is specified\r\n if (computeUnitLimit !== undefined) {\r\n tx.add(\r\n ComputeBudgetProgram.setComputeUnitLimit({\r\n units: computeUnitLimit,\r\n })\r\n );\r\n }\r\n\r\n tx.add(ix);\r\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\r\n tx.recentBlockhash = latestBlockhash.blockhash;\r\n tx.feePayer = signers[0].publicKey;\r\n\r\n if (simulate) {\r\n try {\r\n tx.sign(...signers);\r\n const result = await connection.simulateTransaction(tx, signers);\r\n const logs = result.value.logs ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (result.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(result.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature: \"(simulated)\",\r\n slot: result.context.slot,\r\n err,\r\n hint,\r\n logs,\r\n unitsConsumed: result.value.unitsConsumed ?? undefined,\r\n };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"(simulated)\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n }\r\n\r\n // Send\r\n const options: SendOptions = {\r\n skipPreflight: false,\r\n preflightCommitment: effectiveCommitment,\r\n };\r\n\r\n // sendTransaction is its own try/catch: only here is it true that no\r\n // signature was ever produced, so signature: \"\" is the correct result.\r\n let signature: string;\r\n try {\r\n signature = await connection.sendTransaction(tx, signers, options);\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n\r\n // Fetch logs at the same finality level used for confirmation.\r\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\r\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\r\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\r\n\r\n try {\r\n const confirmation = await connection.confirmTransaction(\r\n {\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n },\r\n effectiveCommitment\r\n );\r\n\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (confirmation.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(confirmation.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature,\r\n slot: txInfo?.slot ?? 0,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n } catch (e: unknown) {\r\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\r\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\r\n // only that we didn't observe confirmation in time. Previously this branch discarded\r\n // the real signature obtained above and returned signature: \"\", which left the caller\r\n // with no way to check whether it's safe to retry — for a non-idempotent operation\r\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\r\n // transaction that had actually already landed. Check the real on-chain status before\r\n // reporting failure, and always return the real signature so the caller can verify\r\n // it themselves even if this fallback check also fails.\r\n const message = e instanceof Error ? e.message : String(e);\r\n try {\r\n const status = await connection.getSignatureStatus(signature, {\r\n searchTransactionHistory: true,\r\n });\r\n // Only treat the fallback lookup as authoritative when the observed level\r\n // actually satisfies the commitment the caller asked for. `status.value`\r\n // being non-null merely means the cluster has SEEN the transaction — at\r\n // \"processed\" it can still be dropped or rolled back, and reporting that\r\n // as a settled success would be the same premature-settlement bug #311 fixed.\r\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n if (status.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(status.value.err);\r\n }\r\n }\r\n return {\r\n signature,\r\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\r\n // `status.context.slot` is the RPC's head slot at query time — a\r\n // different, much later number — so it must not be used as the tx slot.\r\n slot: txInfo?.slot ?? status.value.slot,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n }\r\n if (status.value) {\r\n // Seen, but weaker than requested. Report it as unresolved rather than\r\n // settled, while still handing back the signature and the real landing slot.\r\n const observed = status.value.confirmationStatus ?? \"unknown\";\r\n return {\r\n signature,\r\n slot: status.value.slot,\r\n err:\r\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\r\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\r\n `Check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n } catch {\r\n // Status lookup itself failed too — fall through to the ambiguous result below,\r\n // which still carries the real signature instead of discarding it.\r\n }\r\n return {\r\n signature,\r\n slot: 0,\r\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Format transaction result for output.\r\n */\r\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\r\n if (jsonMode) {\r\n return JSON.stringify(result, null, 2);\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n if (result.err) {\r\n lines.push(`Error: ${result.err}`);\r\n if (result.hint) {\r\n lines.push(`Hint: ${result.hint}`);\r\n }\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.logs.length > 0) {\r\n lines.push(\"Logs:\");\r\n result.logs.forEach((log) => lines.push(` ${log}`));\r\n }\r\n } else {\r\n lines.push(`Signature: ${result.signature}`);\r\n lines.push(`Slot: ${result.slot}`);\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.signature !== \"(simulated)\") {\r\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * @module lighthouse\r\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\r\n *\r\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\r\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\r\n * scanning service. It adds assertion instructions to transactions that verify account\r\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\r\n * X lamports\").\r\n *\r\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\r\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\r\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\r\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\r\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\r\n * logic is correct.\r\n *\r\n * **Solution:** The SDK provides utilities to:\r\n * 1. Detect Lighthouse instructions in a transaction\r\n * 2. Strip them before sending\r\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\r\n * 4. Provide clear, actionable error messages for end users\r\n *\r\n * @example\r\n * ```ts\r\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\r\n *\r\n * // Before sending: strip injected Lighthouse IXs\r\n * const cleanIxs = stripLighthouseInstructions(instructions);\r\n *\r\n * // After error: classify and give user-friendly message\r\n * if (isLighthouseError(error)) {\r\n * console.warn(\"Wallet middleware blocked the transaction\");\r\n * }\r\n * ```\r\n */\r\n\r\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\r\n *\r\n * This is an immutable Anchor program deployed at slot 294,179,293.\r\n * Wallets like Phantom inject instructions from this program into user\r\n * transactions to enforce Blowfish security assertions.\r\n */\r\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\r\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\r\n);\r\n\r\n/** Base58 string form for fast comparison without PublicKey instantiation. */\r\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\r\n\r\n/**\r\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\r\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\r\n * when an account constraint check fails.\r\n */\r\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\r\n\r\n/**\r\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\r\n * All are in the Anchor error range (0x1770–0x1900+).\r\n */\r\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\r\n 0x1770, // InstructionMissing\r\n 0x1771, // InstructionFallbackNotFound\r\n 0x1772, // InstructionDidNotDeserialize\r\n 0x1773, // InstructionDidNotSerialize\r\n 0x1780, // IdlInstructionStub\r\n 0x1790, // ConstraintMut\r\n 0x1791, // ConstraintHasOne\r\n 0x1792, // ConstraintSigner\r\n 0x1793, // ConstraintRaw\r\n 0x1794, // ConstraintOwner\r\n 0x1795, // ConstraintRentExempt\r\n 0x1796, // ConstraintSeeds\r\n 0x1797, // ConstraintExecutable\r\n 0x1798, // ConstraintState\r\n 0x1799, // ConstraintAssociated\r\n 0x179a, // ConstraintAssociatedInit\r\n 0x179b, // ConstraintClose\r\n 0x1900, // ConstraintAddress (the one we hit most often)\r\n] as const);\r\n\r\n// ============================================================================\r\n// Detection\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a TransactionInstruction is from the Lighthouse program.\r\n *\r\n * @param ix - A Solana transaction instruction.\r\n * @returns `true` if the instruction's programId is Lighthouse.\r\n *\r\n * @example\r\n * ```ts\r\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\r\n * ```\r\n */\r\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\r\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if an error message or error object indicates a Lighthouse assertion failure.\r\n *\r\n * Detects:\r\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\r\n * - References to the Lighthouse program ID in error text\r\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\r\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\r\n * failing program is Lighthouse (identified by program ID in logs)\r\n *\r\n * @param error - An Error object, error message string, or transaction logs array.\r\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await sendTransaction(tx);\r\n * } catch (e) {\r\n * if (isLighthouseError(e)) {\r\n * // Retry with skipPreflight or notify user about wallet middleware\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isLighthouseError(error: unknown): boolean {\r\n const msg = extractErrorMessage(error);\r\n if (!msg) return false;\r\n\r\n // Direct program ID reference\r\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\r\n\r\n // 0x1900 hex error code (case-insensitive)\r\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\r\n\r\n // JSON InstructionError format: {\"Custom\": 6400}\r\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if transaction logs contain evidence of a Lighthouse failure.\r\n *\r\n * More precise than `isLighthouseError` on a string — examines the program\r\n * invocation chain to confirm the error originates from Lighthouse, not from\r\n * a Percolator instruction that happens to return a similar code.\r\n *\r\n * @param logs - Array of transaction log lines from `getTransaction()`.\r\n * @returns `true` if logs show a Lighthouse program failure.\r\n */\r\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\r\n if (!Array.isArray(logs)) return false;\r\n\r\n let lighthouseDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n // Track Lighthouse program invocation depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\r\n lighthouseDepth++;\r\n continue;\r\n }\r\n\r\n // Lighthouse program returned success — decrement depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\r\n if (lighthouseDepth > 0) lighthouseDepth--;\r\n continue;\r\n }\r\n\r\n // Only report failure when the Lighthouse program itself explicitly fails\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// Stripping / Mitigation\r\n// ============================================================================\r\n\r\n/**\r\n * Remove all Lighthouse assertion instructions from an instruction array.\r\n *\r\n * Call this before building a Transaction to prevent Lighthouse assertion\r\n * failures. Safe to call even if no Lighthouse instructions are present.\r\n *\r\n * @param instructions - Array of transaction instructions.\r\n * @returns Filtered array with Lighthouse instructions removed.\r\n *\r\n * @example\r\n * ```ts\r\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\r\n *\r\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\r\n * const clean = stripLighthouseInstructions(instructions);\r\n * const tx = new Transaction().add(...clean);\r\n * ```\r\n */\r\nexport function stripLighthouseInstructions(\r\n instructions: TransactionInstruction[],\r\n percolatorProgramId?: PublicKey,\r\n): TransactionInstruction[] {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions — prevents misuse on\r\n // arbitrary transactions where Lighthouse guards are legitimate protection.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) {\r\n return instructions; // no Percolator instructions — leave guards intact\r\n }\r\n }\r\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\r\n}\r\n\r\n/**\r\n * Strip Lighthouse instructions from an already-built Transaction.\r\n *\r\n * Creates a new Transaction with the same recentBlockhash and feePayer\r\n * but without any Lighthouse instructions. The returned transaction is\r\n * unsigned and must be re-signed.\r\n *\r\n * @param transaction - A Transaction (signed or unsigned).\r\n * @returns A new Transaction without Lighthouse instructions, or the same\r\n * transaction if no Lighthouse instructions were found.\r\n *\r\n * @example\r\n * ```ts\r\n * const signed = await wallet.signTransaction(tx);\r\n * if (hasLighthouseInstructions(signed)) {\r\n * const clean = stripLighthouseFromTransaction(signed);\r\n * const reSigned = await wallet.signTransaction(clean);\r\n * await connection.sendRawTransaction(reSigned.serialize());\r\n * }\r\n * ```\r\n */\r\nexport function stripLighthouseFromTransaction(\r\n transaction: Transaction,\r\n percolatorProgramId?: PublicKey,\r\n): Transaction {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = transaction.instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) return transaction;\r\n }\r\n\r\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\r\n if (!hasLighthouse) return transaction;\r\n\r\n const clean = new Transaction();\r\n clean.recentBlockhash = transaction.recentBlockhash;\r\n clean.feePayer = transaction.feePayer;\r\n\r\n for (const ix of transaction.instructions) {\r\n if (!isLighthouseInstruction(ix)) {\r\n clean.add(ix);\r\n }\r\n }\r\n\r\n return clean;\r\n}\r\n\r\n/**\r\n * Count Lighthouse instructions in an instruction array or transaction.\r\n *\r\n * @param ixsOrTx - Array of instructions or a Transaction.\r\n * @returns Number of Lighthouse instructions found.\r\n */\r\nexport function countLighthouseInstructions(\r\n ixsOrTx: TransactionInstruction[] | Transaction,\r\n): number {\r\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\r\n return instructions.filter(isLighthouseInstruction).length;\r\n}\r\n\r\n// ============================================================================\r\n// User-facing error messages\r\n// ============================================================================\r\n\r\n/**\r\n * User-friendly error message for Lighthouse assertion failures.\r\n *\r\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\r\n */\r\nexport const LIGHTHOUSE_USER_MESSAGE =\r\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\r\n \"This is a known compatibility issue — the transaction itself is valid. \" +\r\n \"Try one of these workarounds:\\n\" +\r\n \"1. Disable transaction simulation in your wallet settings\\n\" +\r\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\r\n \"3. The SDK will automatically retry without the guard\";\r\n\r\n/**\r\n * Classify an error and return an appropriate user-facing message.\r\n *\r\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\r\n * Otherwise returns `null` (callers should use their own error display).\r\n *\r\n * @param error - An Error, string, or logs array.\r\n * @returns User-facing message string, or `null` if not a Lighthouse error.\r\n */\r\nexport function classifyLighthouseError(error: unknown): string | null {\r\n if (isLighthouseError(error)) {\r\n return LIGHTHOUSE_USER_MESSAGE;\r\n }\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Internal helpers\r\n// ============================================================================\r\n\r\nfunction extractErrorMessage(error: unknown): string | null {\r\n if (!error) return null;\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n if (typeof error === \"object\" && \"message\" in error) {\r\n return String((error as { message: unknown }).message);\r\n }\r\n try {\r\n return JSON.stringify(error);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Coin-margined perpetual trade math utilities.\r\n *\r\n * On-chain PnL formula:\r\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\r\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\r\n *\r\n * All prices are in e6 format (1 USD = 1_000_000).\r\n * All token amounts are in native units (e.g. lamports).\r\n */\r\n\r\n/**\r\n * Compute mark-to-market PnL for an open position.\r\n */\r\nexport function computeMarkPnl(\r\n positionSize: bigint,\r\n entryPrice: bigint,\r\n oraclePrice: bigint,\r\n): bigint {\r\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n const diff =\r\n positionSize > 0n\r\n ? oraclePrice - entryPrice\r\n : entryPrice - oraclePrice;\r\n return (diff * absPos) / oraclePrice;\r\n}\r\n\r\n/**\r\n * Compute liquidation price given entry, capital, position and maintenance margin.\r\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\r\n */\r\nexport function computeLiqPrice(\r\n entryPrice: bigint,\r\n capital: bigint,\r\n positionSize: bigint,\r\n maintenanceMarginBps: bigint,\r\n): bigint {\r\n if (positionSize === 0n || entryPrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n // capitalPerUnit scaled by 1e6 for precision\r\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\r\n\r\n if (positionSize > 0n) {\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\r\n const liq = entryPrice - adjusted;\r\n return liq > 0n ? liq : 0n;\r\n } else {\r\n // Guard: short positions liquidate when price rises above liq price.\r\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\r\n // meaning the position can never be liquidated. Return max u64 to signal this.\r\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\r\n return entryPrice + adjusted;\r\n }\r\n}\r\n\r\n/**\r\n * Compute estimated liquidation price BEFORE opening a trade.\r\n * Accounts for trading fees reducing effective capital.\r\n */\r\nexport function computePreTradeLiqPrice(\r\n oracleE6: bigint,\r\n margin: bigint,\r\n posSize: bigint,\r\n maintBps: bigint,\r\n feeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\r\n const absPos = posSize < 0n ? -posSize : posSize;\r\n const signedPos = direction === \"long\" ? absPos : -absPos;\r\n // Fee adjusts the effective entry price, not the capital.\r\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\r\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\r\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\r\n let adjustedEntry: bigint;\r\n if (direction === \"long\") {\r\n adjustedEntry = oracleE6 + feeAdjust;\r\n } else {\r\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\r\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\r\n // feeBps >= 10000, misleading the UI into showing the position is safe.\r\n const shortEntry = oracleE6 - feeAdjust;\r\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\r\n }\r\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\r\n}\r\n\r\n/**\r\n * Compute trading fee from notional value and fee rate in bps.\r\n */\r\nexport function computeTradingFee(\r\n notional: bigint,\r\n tradingFeeBps: bigint,\r\n): bigint {\r\n return (notional * tradingFeeBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Dynamic fee tier configuration.\r\n */\r\nexport interface FeeTierConfig {\r\n /** Base trading fee (Tier 1) in bps */\r\n baseBps: bigint;\r\n /** Tier 2 fee in bps (0 = disabled) */\r\n tier2Bps: bigint;\r\n /** Tier 3 fee in bps (0 = disabled) */\r\n tier3Bps: bigint;\r\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\r\n tier2Threshold: bigint;\r\n /** Notional threshold to enter Tier 3 */\r\n tier3Threshold: bigint;\r\n}\r\n\r\n/**\r\n * Compute the effective fee rate in bps using the tiered fee schedule.\r\n *\r\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\r\n * - notional < tier2Threshold → baseBps (Tier 1)\r\n * - notional < tier3Threshold → tier2Bps (Tier 2)\r\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\r\n *\r\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\r\n */\r\nexport function computeDynamicFeeBps(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n if (config.tier2Threshold === 0n) return config.baseBps;\r\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\r\n if (notional >= config.tier2Threshold) return config.tier2Bps;\r\n return config.baseBps;\r\n}\r\n\r\n/**\r\n * Compute the dynamic trading fee for a given notional and tier config.\r\n *\r\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\r\n * via micro-trades).\r\n */\r\nexport function computeDynamicTradingFee(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n const feeBps = computeDynamicFeeBps(notional, config);\r\n if (notional <= 0n || feeBps <= 0n) return 0n;\r\n return (notional * feeBps + 9999n) / 10000n;\r\n}\r\n\r\n/**\r\n * Fee split configuration.\r\n */\r\nexport interface FeeSplitConfig {\r\n /** LP vault share in bps (0–10_000) */\r\n lpBps: bigint;\r\n /** Protocol treasury share in bps */\r\n protocolBps: bigint;\r\n /** Market creator share in bps */\r\n creatorBps: bigint;\r\n}\r\n\r\n/**\r\n * Compute fee split for a total fee amount.\r\n *\r\n * Returns [lpShare, protocolShare, creatorShare].\r\n * If all split params are 0, 100% goes to LP (legacy behavior).\r\n * Creator gets the rounding remainder to ensure total is preserved.\r\n */\r\nexport function computeFeeSplit(\r\n totalFee: bigint,\r\n config: FeeSplitConfig,\r\n): [bigint, bigint, bigint] {\r\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\r\n return [totalFee, 0n, 0n];\r\n }\r\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\r\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\r\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\r\n }\r\n if (totalBps !== 10000n) {\r\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\r\n }\r\n\r\n const lp = (totalFee * config.lpBps) / 10000n;\r\n const protocol = (totalFee * config.protocolBps) / 10000n;\r\n const creator = totalFee - lp - protocol;\r\n return [lp, protocol, creator];\r\n}\r\n\r\n/**\r\n * Compute PnL as a percentage of capital.\r\n *\r\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\r\n * Number(bigint) silently truncates values above 2^53, which can produce\r\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\r\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\r\n */\r\nexport function computePnlPercent(\r\n pnlTokens: bigint,\r\n capital: bigint,\r\n): number {\r\n if (capital === 0n) return 0;\r\n const scaledPct = (pnlTokens * 10_000n) / capital;\r\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\r\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\r\n // unhandled exceptions from crashing the UI on large positions.\r\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\r\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\r\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\r\n return Number(scaledPct) / 100;\r\n}\r\n\r\n/**\r\n * Estimate entry price including fee impact (slippage approximation).\r\n */\r\nexport function computeEstimatedEntryPrice(\r\n oracleE6: bigint,\r\n tradingFeeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n) return 0n;\r\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\r\n if (direction === \"long\") return oracleE6 + feeImpact;\r\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\r\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\r\n // when fee >= 100%, misleading the UI.\r\n const shortEntry = oracleE6 - feeImpact;\r\n return shortEntry > 0n ? shortEntry : 1n;\r\n}\r\n\r\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\r\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\r\n\r\n/**\r\n * Convert per-slot funding rate (bps) to annualized percentage.\r\n */\r\nexport function computeFundingRateAnnualized(\r\n fundingRateBpsPerSlot: bigint,\r\n): number {\r\n // Clamp rather than throw: extreme funding rates are display-only values;\r\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\r\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\r\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\r\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\r\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\r\n return (bpsPerSlot * slotsPerYear) / 100;\r\n}\r\n\r\n/**\r\n * Compute margin required for a given notional and initial margin bps.\r\n */\r\nexport function computeRequiredMargin(\r\n notional: bigint,\r\n initialMarginBps: bigint,\r\n): bigint {\r\n return (notional * initialMarginBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, as an exact ratio.\r\n *\r\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\r\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\r\n * {@link computeMaxLeverageFloor} instead.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\r\n }\r\n // Use floating-point division so fractional leverage is preserved.\r\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\r\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\r\n return 10000 / Number(initialMarginBps);\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, floored to a whole\r\n * multiplier — the conservative integer form used by risk/sizing math.\r\n *\r\n * Kept separate from {@link computeMaxLeverage} because that one is a display\r\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\r\n * DOWN also keeps client-side caps at or below what the program enforces, so a\r\n * caller can never build a position the chain would reject on leverage.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\r\n }\r\n return 10000n / initialMarginBps;\r\n}\r\n","/**\r\n * Warmup leverage cap utilities.\r\n *\r\n * During the market warmup period, capital is released linearly over\r\n * `warmupPeriodSlots` slots, which constrains the effective leverage\r\n * and maximum position size available to traders.\r\n */\r\n\r\nimport { computeMaxLeverageFloor } from \"./trading.js\";\r\n\r\n// =============================================================================\r\n// Warmup leverage cap utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Compute unlocked capital during the warmup period.\r\n *\r\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\r\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\r\n * warmup period is 0, all capital is considered unlocked.\r\n *\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The amount of capital currently unlocked.\r\n */\r\nexport function computeWarmupUnlockedCapital(\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n // No warmup configured or not started → all capital available\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\r\n if (totalCapital <= 0n) return 0n;\r\n\r\n const elapsed = currentSlot > warmupStartSlot\r\n ? currentSlot - warmupStartSlot\r\n : 0n;\r\n\r\n // Warmup complete\r\n if (elapsed >= warmupPeriodSlots) return totalCapital;\r\n\r\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\r\n return (totalCapital * elapsed) / warmupPeriodSlots;\r\n}\r\n\r\n/**\r\n * Compute the effective maximum leverage during the warmup period.\r\n *\r\n * During warmup, only unlocked capital can be used as margin. The effective\r\n * leverage relative to *total* capital is therefore capped at:\r\n *\r\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\r\n *\r\n * This returns a floored integer value (leverage is always a whole number\r\n * in the UI), with a minimum of 1x if any capital is unlocked.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The effective maximum leverage (integer, ≥ 1).\r\n */\r\nexport function computeWarmupLeverageCap(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): number {\r\n // Integer form: this is risk/sizing math, and the fractional\r\n // computeMaxLeverage() is a display value that cannot be used in BigInt\r\n // arithmetic. Flooring also keeps the client cap at or below the program's.\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n\r\n // No warmup or warmup not started → full leverage\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\r\n if (totalCapital <= 0n) return 1;\r\n\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n\r\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\r\n\r\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\r\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\r\n return Math.max(1, effectiveLev);\r\n}\r\n\r\n/**\r\n * Compute the maximum position size allowed during warmup.\r\n *\r\n * This is the unlocked capital multiplied by the base max leverage.\r\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\r\n * relative to total capital), this gives the absolute notional cap.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns Maximum position size in native units.\r\n */\r\nexport function computeWarmupMaxPositionSize(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n return unlocked * maxLev;\r\n}\r\n","/**\r\n * Input validation utilities for CLI commands.\r\n * Provides descriptive error messages for invalid input.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\n// Constants for numeric limits\r\nconst U16_MAX = 65535;\r\nconst U64_MAX = BigInt(\"18446744073709551615\");\r\nconst I64_MIN = BigInt(\"-9223372036854775808\");\r\nconst I64_MAX = BigInt(\"9223372036854775807\");\r\nconst U128_MAX = (1n << 128n) - 1n;\r\nconst I128_MIN = -(1n << 127n);\r\nconst I128_MAX = (1n << 127n) - 1n;\r\n\r\nexport class ValidationError extends Error {\r\n constructor(\r\n public readonly field: string,\r\n message: string\r\n ) {\r\n super(`Invalid ${field}: ${message}`);\r\n this.name = \"ValidationError\";\r\n }\r\n}\r\n\r\n/**\r\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\r\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\r\n */\r\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\r\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n */\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\r\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n *\r\n * @param value - The string to validate.\r\n * @param field - The field name used in error messages.\r\n * @returns The trimmed, validated decimal string.\r\n */\r\nexport function requireDecimalUIntString(value: string, field: string): string {\r\n const t = value.trim();\r\n if (t === \"\") {\r\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\r\n }\r\n if (!DECIMAL_UINT_RE.test(t)) {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\r\n );\r\n }\r\n return t;\r\n}\r\n\r\n/**\r\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\r\n * (hex, scientific notation, underscores, fractions, leading zeros).\r\n *\r\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\r\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\r\n *\r\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\r\n * @param caller - The calling function name, used in the error message.\r\n * @returns The parsed BigInt value.\r\n * @throws {Error} When `val` does not match the strict decimal integer format.\r\n *\r\n * @example\r\n * safeBigInt(\"123\", \"encU64\") // 123n\r\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\r\n * safeBigInt(\"0x1\", \"encU64\") // throws\r\n * safeBigInt(\"1e5\", \"encU128\") // throws\r\n */\r\nexport function safeBigInt(val: string, caller: string): bigint {\r\n const t = val.trim();\r\n if (!DECIMAL_INT_RE.test(t)) {\r\n throw new Error(\r\n `${caller}: \"${val}\" is not a valid decimal integer ` +\r\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\r\n );\r\n }\r\n return BigInt(t);\r\n}\r\n\r\n/**\r\n * Validate a public key string.\r\n */\r\nexport function validatePublicKey(value: string, field: string): PublicKey {\r\n try {\r\n return new PublicKey(value);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid base58 public key. ` +\r\n `Example: \"11111111111111111111111111111111\"`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate a non-negative integer index (u16 range for accounts).\r\n */\r\nexport function validateIndex(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a non-negative amount (u64 range).\r\n */\r\nexport function validateAmount(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U64_MAX} (u64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a u128 value.\r\n */\r\nexport function validateU128(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U128_MAX} (u128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i64 value.\r\n */\r\nexport function validateI64(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I64_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I64_MIN} (i64 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I64_MAX} (i64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i128 value (trade sizes).\r\n */\r\nexport function validateI128(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I128_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I128_MIN} (i128 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I128_MAX} (i128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a basis points value (0-10000).\r\n */\r\nexport function validateBps(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > 10000n) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= 10000 (100%), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a u64 value.\r\n */\r\nexport function validateU64(value: string, field: string): bigint {\r\n return validateAmount(value, field);\r\n}\r\n\r\n/**\r\n * Validate a u16 value.\r\n */\r\nexport function validateU16(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n","/**\r\n * Smart Price Router — automatic oracle selection for any token.\r\n *\r\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\r\n * ranks them by liquidity/reliability, and returns the best oracle config.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\r\n\r\nexport interface PriceSource {\r\n type: PriceSourceType;\r\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\r\n address: string;\r\n /** DEX id for dex sources */\r\n dexId?: string;\r\n /** Pair label e.g. \"SOL / USDC\" */\r\n pairLabel?: string;\r\n /** USD liquidity depth — higher is better */\r\n liquidity: number;\r\n /** Latest spot price in USD */\r\n price: number;\r\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\r\n confidence: number;\r\n}\r\n\r\nexport interface PriceRouterResult {\r\n mint: string;\r\n bestSource: PriceSource | null;\r\n allSources: PriceSource[];\r\n /** ISO timestamp of resolution */\r\n resolvedAt: string;\r\n}\r\n\r\n/** Options for {@link resolvePrice}. */\r\nexport interface ResolvePriceOptions {\r\n timeoutMs?: number;\r\n}\r\n\r\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\r\n\r\nfunction isRecord(v: unknown): v is Record {\r\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\r\n const already = signals.find((s) => s.aborted);\r\n if (already) {\r\n const c = new AbortController();\r\n c.abort(already.reason);\r\n return c.signal;\r\n }\r\n const active = signals.filter((s) => !s.aborted);\r\n if (active.length === 0) {\r\n const c = new AbortController();\r\n c.abort();\r\n return c.signal;\r\n }\r\n if (active.length === 1) return active[0];\r\n const ctrl = new AbortController();\r\n for (const s of active) {\r\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\r\n }\r\n return ctrl.signal;\r\n}\r\n\r\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\r\n\r\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\r\n if (!isRecord(json)) return [];\r\n const rawPairs = json.pairs;\r\n if (!Array.isArray(rawPairs)) return [];\r\n const sources: PriceSource[] = [];\r\n\r\n for (const pair of rawPairs) {\r\n if (!isRecord(pair)) continue;\r\n if (pair.chainId !== \"solana\") continue;\r\n const dexId = String(pair.dexId || \"\").toLowerCase();\r\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\r\n\r\n let liquidity = 0;\r\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\r\n liquidity = pair.liquidity.usd;\r\n }\r\n if (liquidity < 100) continue;\r\n\r\n let confidence = 30;\r\n if (liquidity > 1_000_000) confidence = 90;\r\n else if (liquidity > 100_000) confidence = 75;\r\n else if (liquidity > 10_000) confidence = 60;\r\n else if (liquidity > 1_000) confidence = 45;\r\n\r\n const priceUsd = pair.priceUsd;\r\n const price =\r\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\r\n ? parseFloat(String(priceUsd)) || 0\r\n : 0;\r\n\r\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\r\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\r\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\r\n // any source without a usable positive price.\r\n if (!(price > 0)) continue;\r\n\r\n let baseSym = \"?\";\r\n let quoteSym = \"?\";\r\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\r\n baseSym = pair.baseToken.symbol;\r\n }\r\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\r\n quoteSym = pair.quoteToken.symbol;\r\n }\r\n\r\n const addr = pair.pairAddress;\r\n sources.push({\r\n type: \"dex\",\r\n address: typeof addr === \"string\" ? addr : \"\",\r\n dexId,\r\n pairLabel: `${baseSym} / ${quoteSym}`,\r\n liquidity,\r\n price,\r\n confidence,\r\n });\r\n }\r\n\r\n sources.sort((a, b) => b.liquidity - a.liquidity);\r\n return sources.slice(0, 10);\r\n}\r\n\r\n/**\r\n * Parse a Jupiter price row.\r\n *\r\n * Handles BOTH shapes:\r\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\r\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\r\n *\r\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\r\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\r\n * cross-validation in this module was silently inert, including the #227/#315\r\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\r\n * mock or a proxy that still speaks v2 keeps working.\r\n */\r\nfunction parseJupiterMintEntry(\r\n json: unknown,\r\n mint: string,\r\n): { price: number; mintSymbol: string; liquidity: number } | null {\r\n if (!isRecord(json)) return null;\r\n\r\n // v3: the mint is a top-level key.\r\n const v3Row = json[mint];\r\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\r\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\r\n if (price <= 0) return null;\r\n const liquidity =\r\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\r\n ? v3Row.liquidity\r\n : 0;\r\n return { price, mintSymbol: \"?\", liquidity };\r\n }\r\n\r\n // v2 (retired): rows live under `data`.\r\n const data = json.data;\r\n if (!isRecord(data)) return null;\r\n const row = data[mint];\r\n if (!isRecord(row)) return null;\r\n const rawPrice = row.price;\r\n if (rawPrice === undefined || rawPrice === null) return null;\r\n const price = parseFloat(String(rawPrice)) || 0;\r\n if (price <= 0) return null;\r\n let mintSymbol = \"?\";\r\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\r\n return { price, mintSymbol, liquidity: 0 };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const PYTH_SOLANA_FEEDS: Record = {\r\n // SOL\r\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\r\n // BTC\r\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\r\n // ETH\r\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\r\n // USDC\r\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\r\n // USDT\r\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\r\n // BONK\r\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\r\n // JTO\r\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\r\n // JUP\r\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\r\n // PYTH\r\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\r\n // RAY\r\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\r\n // ORCA\r\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\r\n // MNGO\r\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\r\n // MSOL\r\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\r\n // JITOSOL\r\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\r\n // WIF\r\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\r\n // RENDER\r\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\r\n // W\r\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\r\n // TNSR\r\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\r\n // HNT\r\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\r\n // MOBILE\r\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\r\n // IOT\r\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\r\n};\r\nObject.freeze(PYTH_SOLANA_FEEDS);\r\n\r\n// Reverse lookup: mint → feed ID\r\nconst MINT_TO_PYTH_FEED = new Map();\r\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\r\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DexScreener fetcher\r\n// ---------------------------------------------------------------------------\r\n\r\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\r\n\r\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\r\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\r\n}\r\n\r\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return [];\r\n const json: unknown = await resp.json();\r\n return parseDexScreenerPairs(json);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth lookup\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction lookupPythSource(mint: string): PriceSource | null {\r\n const entry = MINT_TO_PYTH_FEED.get(mint);\r\n if (!entry) return null;\r\n return {\r\n type: \"pyth\",\r\n address: entry.feedId,\r\n pairLabel: `${entry.symbol} / USD (Pyth)`,\r\n liquidity: Infinity, // Pyth is considered deep liquidity\r\n price: 0, // We don't fetch live price here; caller can enrich\r\n confidence: 95, // Pyth is highest reliability for supported tokens\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Jupiter price fallback\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return null;\r\n const json: unknown = await resp.json();\r\n const row = parseJupiterMintEntry(json, mint);\r\n if (!row) return null;\r\n return {\r\n type: \"jupiter\",\r\n address: mint,\r\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\r\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\r\n // Used below to decide whether Jupiter is a credible enough reference to\r\n // demote a disagreeing pool.\r\n liquidity: row.liquidity,\r\n price: row.price,\r\n confidence: 40, // Fallback — lower confidence\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main resolver\r\n// ---------------------------------------------------------------------------\r\n\r\nexport async function resolvePrice(\r\n mint: string,\r\n signal?: AbortSignal,\r\n options?: ResolvePriceOptions,\r\n): Promise {\r\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\r\n const combinedSignal = signal\r\n ? combineAbortSignals([signal, timeoutSignal])\r\n : timeoutSignal;\r\n\r\n const [dexSources, jupiterSource] = await Promise.all([\r\n fetchDexSources(mint, combinedSignal),\r\n fetchJupiterSource(mint, combinedSignal),\r\n ]);\r\n\r\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\r\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\r\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\r\n // the common case for permissionless markets — had its top DEX source ranked\r\n // purely on self-reported liquidity, with no check against an independent price\r\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\r\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\r\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\r\n // source's confidence to Jupiter's when they diverge beyond the same tightened\r\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\r\n // independent reference purely on liquidity. The source stays in allSources for\r\n // transparency; only its ranking weight is reduced.\r\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\r\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\r\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\r\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\r\n // ahead and bestSource unchanged.\r\n const DISTRUST_CONFIDENCE_MARGIN = 1;\r\n if (jupiterSource && jupiterSource.price > 0) {\r\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\r\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\r\n // itself — enrichment reads dexSources[0].price, which is untouched; only\r\n // ranking weight changes, and Pyth's own confidence (95) still outranks\r\n // everything here.\r\n //\r\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\r\n // Jupiter is an aggregate across venues, so it is normally the better\r\n // reference — but with v2 retired a malformed/empty response used to yield a\r\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\r\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\r\n // ranking alone rather than trust it.\r\n const jupiterIsCredible = jupiterSource.liquidity > 0;\r\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\r\n if (jupiterIsCredible) {\r\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\r\n // returns up to 10 pools and confidence is a step function of liquidity, so a\r\n // second pool in the same tier would otherwise keep its score and win\r\n // bestSource at the divergent price.\r\n for (const dex of dexSources) {\r\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\r\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\r\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\r\n dex.confidence = Math.min(dex.confidence, distrusted);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const pythSource = lookupPythSource(mint);\r\n\r\n const allSources: PriceSource[] = [];\r\n\r\n // Add Pyth if available (highest priority for supported tokens)\r\n if (pythSource) {\r\n // Enrich Pyth price from Jupiter or DEX if available.\r\n // Guard: only push a Pyth source when we have at least one live price\r\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\r\n // at crank time on devnet/mainnet.\r\n const dexPrice = dexSources[0]?.price ?? 0;\r\n const jupPrice = jupiterSource?.price ?? 0;\r\n // #227: cross-validate the enrichment reference so a single manipulable DEX\r\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\r\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\r\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\r\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\r\n //\r\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\r\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\r\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\r\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\r\n let enrichedPrice = 0;\r\n let singleSource = false;\r\n if (dexPrice > 0 && jupPrice > 0) {\r\n const mid = (dexPrice + jupPrice) / 2;\r\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\r\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\r\n enrichedPrice = mid;\r\n } else {\r\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\r\n // DEX and Jupiter are still added below at their own confidence levels.\r\n console.warn(\r\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\r\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\r\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\r\n );\r\n }\r\n } else if (dexPrice > 0 || jupPrice > 0) {\r\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\r\n singleSource = true;\r\n }\r\n if (enrichedPrice > 0) {\r\n pythSource.price = enrichedPrice;\r\n if (singleSource) {\r\n pythSource.confidence = Math.min(pythSource.confidence, 50);\r\n }\r\n allSources.push(pythSource);\r\n }\r\n }\r\n\r\n // Add DEX sources\r\n allSources.push(...dexSources);\r\n\r\n // Add Jupiter as fallback\r\n if (jupiterSource) {\r\n allSources.push(jupiterSource);\r\n }\r\n\r\n // Sort by confidence descending (already accounts for liquidity/reliability)\r\n allSources.sort((a, b) => b.confidence - a.confidence);\r\n\r\n return {\r\n mint,\r\n bestSource: allSources[0] || null,\r\n allSources,\r\n resolvedAt: new Date().toISOString(),\r\n };\r\n}\r\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;A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","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file +{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst U8_MAX = 0xFF;\r\nconst U16_MAX = 0xFFFF;\r\nconst U32_MAX = 0xFFFFFFFF;\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\r\n if (typeof val === \"bigint\") return val;\r\n if (typeof val !== \"string\") {\r\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\r\n }\r\n if (!DECIMAL_INT_RE.test(val)) {\r\n throw new Error(`${fnName}: value must be a decimal integer string`);\r\n }\r\n return BigInt(val);\r\n}\r\n\r\n/**\r\n * Encode u8 (1 byte)\r\n */\r\nexport function encU8(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\r\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\r\n }\r\n return new Uint8Array([val]);\r\n}\r\n\r\n/**\r\n * Encode u16 little-endian (2 bytes)\r\n */\r\nexport function encU16(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\r\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u32 little-endian (4 bytes)\r\n */\r\nexport function encU32(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\r\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\r\n }\r\n const buf = new Uint8Array(4);\r\n new DataView(buf.buffer).setUint32(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u64 little-endian (8 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU64\");\r\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\r\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i64 little-endian (8 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI64\");\r\n const min = -(1n << 63n);\r\n const max = (1n << 63n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigInt64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u128 little-endian (16 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU128\");\r\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\r\n const max = (1n << 128n) - 1n;\r\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = n & 0xffff_ffff_ffff_ffffn;\r\n const hi = n >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i128 little-endian (16 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI128\");\r\n const min = -(1n << 127n);\r\n const max = (1n << 127n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\r\n\r\n // Convert to unsigned representation (two's complement)\r\n let unsigned = n;\r\n if (n < 0n) {\r\n unsigned = (1n << 128n) + n;\r\n }\r\n\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\r\n const hi = unsigned >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\r\n *\r\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\r\n * objects are validated before their bytes are returned so JavaScript callers\r\n * cannot provide malformed `toBytes()` output.\r\n *\r\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\r\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\r\n */\r\nexport function encPubkey(val: PublicKey | string): Uint8Array {\r\n try {\r\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\r\n\r\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\r\n throw new Error(\"value must be a PublicKey or base58 string\");\r\n }\r\n\r\n const bytes = pk.toBytes();\r\n\r\n if (!(bytes instanceof Uint8Array)) {\r\n throw new Error(\"toBytes() must return a Uint8Array\");\r\n }\r\n\r\n if (bytes.length !== 32) {\r\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\r\n }\r\n\r\n return bytes;\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\r\n }\r\n}\r\n\r\n/**\r\n * Encode a boolean as u8 (0 = false, 1 = true)\r\n */\r\nexport function encBool(val: boolean): Uint8Array {\r\n return encU8(val ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\r\n */\r\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\r\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\r\n const result = new Uint8Array(totalLen);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n encU8,\r\n encU16,\r\n encU32,\r\n encU64,\r\n encI64,\r\n encU128,\r\n encI128,\r\n encPubkey,\r\n concatBytes,\r\n} from \"./encode.js\";\r\n\r\n/**\r\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\r\n * v17 converged wrapper (percolator-prog @v17-convergence, source\r\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\r\n * InvalidInstructionData.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\r\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\r\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\r\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\r\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\r\n * all callers — the program hard-rejects nonzero.\r\n * - Domain fields: u8→u16 everywhere.\r\n */\r\nexport const IX_TAG = {\r\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\r\n InitMarket: 0,\r\n InitPortfolio: 1,\r\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\r\n InitUser: 1,\r\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\r\n InitLP: 2,\r\n Deposit: 3,\r\n /** @alias DepositCollateral @since v12.x alias */\r\n DepositCollateral: 3,\r\n Withdraw: 4,\r\n /** @alias WithdrawCollateral @since v12.x alias */\r\n WithdrawCollateral: 4,\r\n /**\r\n * PermissionlessCrank (tag 5).\r\n *\r\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\r\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\r\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\r\n * construct the payload manually and omit this field — that produces a\r\n * malformed instruction (missing bytes).\r\n */\r\n PermissionlessCrank: 5,\r\n /** @alias KeeperCrank @since v12.x alias */\r\n KeeperCrank: 5,\r\n TradeNoCpi: 6,\r\n LiquidateAtOracle: 7,\r\n ClosePortfolio: 8,\r\n /** @alias CloseAccount @since v12.x alias */\r\n CloseAccount: 8,\r\n TopUpInsurance: 9,\r\n TradeCpi: 10,\r\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\r\n SetRiskThreshold: 11,\r\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\r\n UpdateAdmin: 12,\r\n CloseSlab: 13,\r\n ResolveMarket: 19,\r\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\r\n TopUpBackingBucket: 24,\r\n ConvertReleasedPnl: 28,\r\n CloseResolved: 30,\r\n /**\r\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\r\n *\r\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\r\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\r\n * rotation uses tag 65 (UpdateAssetAuthority).\r\n */\r\n UpdateAuthority: 32,\r\n ConfigureHybridOracle: 34,\r\n ConfigureEwmaMark: 35,\r\n PushEwmaMark: 36,\r\n UpdateLiquidationFeePolicy: 37,\r\n ConfigurePermissionlessResolve: 38,\r\n ResolveStalePermissionless: 39,\r\n UpdateAssetLifecycle: 40,\r\n WithdrawInsurance: 41,\r\n CureAndCancelClose: 42,\r\n ForfeitRecoveryLeg: 43,\r\n RebalanceReduce: 44,\r\n FinalizeResetSide: 45,\r\n ClaimResolvedPayoutTopup: 46,\r\n RefineResolvedUnreceiptedBound: 47,\r\n SyncMaintenanceFee: 48,\r\n UpdateMaintenanceFeePolicy: 49,\r\n WithdrawBackingBucket: 50,\r\n UpdateBackingFeePolicy: 51,\r\n WithdrawBackingBucketEarnings: 52,\r\n SyncBackingDomainLedger: 53,\r\n SyncInsuranceLedger: 54,\r\n UpdateTradeFeePolicy: 55,\r\n TopUpInsuranceDomain: 56,\r\n /**\r\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\r\n *\r\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\r\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\r\n */\r\n WithdrawInsuranceAsset: 57,\r\n UpdateFeeRedirectPolicy: 58,\r\n UpdateMarketInitFeePolicy: 59,\r\n UpdateBaseUnitMints: 60,\r\n SwapSecondaryForPrimary: 61,\r\n ConfigureAuthMark: 62,\r\n PushAuthMark: 63,\r\n ForceCloseAbandonedAsset: 64,\r\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\r\n /**\r\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\r\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\r\n * 1 = INSURANCE — insurance_authority\r\n * 2 = INSURANCE_OPERATOR — insurance_operator\r\n * 3 = BACKING_BUCKET — backing_bucket_authority\r\n * 4 = ORACLE — oracle_authority\r\n *\r\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\r\n * See stake-program docs.\r\n */\r\n UpdateAssetAuthority: 65,\r\n /**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\r\n */\r\n BatchTradeNoCpi: 66,\r\n /**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\r\n */\r\n BatchTradeCpi: 67,\r\n /**\r\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n */\r\n SetMatcherConfig: 68,\r\n /**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\r\n */\r\n RestartAssetOracle: 69,\r\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\r\n /**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n */\r\n TransferPortfolioOwnership: 72,\r\n /**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n */\r\n SetNftProgramId: 73,\r\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\r\n /**\r\n * CreateLpVault (tag 74).\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\r\n */\r\n CreateLpVault: 74,\r\n /**\r\n * DepositToLpVault (tag 75).\r\n * Wire: tag(1) + amount(u128) = 17 bytes.\r\n */\r\n DepositToLpVault: 75,\r\n /**\r\n * RequestRedeemLpShares (tag 76).\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n */\r\n RequestRedeemLpShares: 76,\r\n /**\r\n * ExecuteRedemption (tag 77).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n ExecuteRedemption: 77,\r\n /**\r\n * LpVaultCrankFees (tag 78).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n LpVaultCrankFees: 78,\r\n /**\r\n * SetLpVaultPaused (tag 79).\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n */\r\n SetLpVaultPaused: 79,\r\n /**\r\n * CloseLpVault (tag 80).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n CloseLpVault: 80,\r\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\r\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\r\n LpVaultDeposit: 75,\r\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\r\n LpVaultWithdraw: 76,\r\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\r\n /** @deprecated v12.x tag 14. Removed in v17. */\r\n UpdateConfig: 14,\r\n /** @deprecated v12.x tag 15. Removed in v17. */\r\n SetMaintenanceFee: 15,\r\n /** @deprecated v12.x tag 16. Removed in v17. */\r\n SetOraclePriceCap: 16,\r\n /** @deprecated v12.x tag 17. Removed in v17. */\r\n AdminForceClose: 17,\r\n /** @deprecated v12.x tag 18. Removed in v17. */\r\n UpdateRiskParams: 18,\r\n /** @deprecated v12.x tag 20. Removed in v17. */\r\n SetPythOracle: 20,\r\n /** @deprecated v12.x tag 21. Removed in v17. */\r\n RenounceAdmin: 21,\r\n /** @deprecated v12.x tag 22. Removed in v17. */\r\n SetInsuranceWithdrawPolicy: 22,\r\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\r\n WithdrawInsuranceLimited: 23,\r\n /** @deprecated v12.x tag 25. Removed in v17. */\r\n FundMarketInsurance: 25,\r\n /** @deprecated v12.x tag 26. Removed in v17. */\r\n SetInsuranceIsolation: 26,\r\n /** @deprecated v12.x tag 27. Removed in v17. */\r\n DepositFeeCredits: 27,\r\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\r\n ResolvePermissionless: 29,\r\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\r\n ForceCloseResolved: 30,\r\n /** @deprecated v12.x tag 33. Removed in v17. */\r\n UpdateInsurancePolicy: 33,\r\n /** @deprecated v12.x tag 36. Removed in v12.17. */\r\n UnresolveMarket: 36,\r\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\r\n ChallengeSettlement: 43,\r\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\r\n ResolveDispute: 44,\r\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\r\n DepositLpCollateral: 45,\r\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\r\n WithdrawLpCollateral: 46,\r\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\r\n SetOffsetPair: 54,\r\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\r\n AttestCrossMargin: 55,\r\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\r\n PauseMarket: 56,\r\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\r\n UnpauseMarket: 58,\r\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\r\n MintPositionNft: 64,\r\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\r\n TransferPositionOwnership: 65,\r\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\r\n BurnPositionNft: 66,\r\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\r\n SetPendingSettlement: 67,\r\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\r\n ClearPendingSettlement: 68,\r\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\r\n TransferOwnershipCpi: 69,\r\n /** @deprecated v12.x tag 70. Not in v17. */\r\n SetWalletCap: 70,\r\n /** @deprecated v12.x tag 71. Not in v17. */\r\n SetOiImbalanceHardBlock: 71,\r\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\r\n RescueOrphanVault: 72,\r\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\r\n CloseOrphanSlab: 73,\r\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\r\n SetDexPool: 74,\r\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\r\n InitMatcherCtxV12: 75,\r\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\r\n SetMaxPnlCap: 78,\r\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\r\n SetOiCapMultiplier: 79,\r\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\r\n SetDisputeParams: 80,\r\n /** @deprecated v12.x tag 81. Not in v17. */\r\n SetLpCollateralParams: 81,\r\n /** @deprecated v12.x tag 82. Not in v17. */\r\n AcceptAdmin: 82,\r\n /**\r\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\r\n *\r\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\r\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\r\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\r\n * skew_spread_mult_bps(u16) = 70 bytes total.\r\n *\r\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\r\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\r\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\r\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\r\n *\r\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\r\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\r\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\r\n * free tag 83 for this instruction rather than the reverse.\r\n */\r\n InitMatcherCtx: 83,\r\n /**\r\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\r\n *\r\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\r\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\r\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\r\n *\r\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\r\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\r\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\r\n */\r\n WithdrawProtocolFee: 84,\r\n /**\r\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\r\n * cfg.protocol_fee_authority.\r\n *\r\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\r\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\r\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\r\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\r\n *\r\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\r\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\r\n */\r\n SetProtocolFeeAuthority: 85,\r\n /**\r\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\r\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\r\n *\r\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\r\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\r\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\r\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\r\n * FeeSplitFloorViolation.\r\n *\r\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\r\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\r\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\r\n * `encodeStakeAdminUpdateFeeSplit`.\r\n */\r\n UpdateFeeSplit: 86,\r\n /**\r\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\r\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\r\n * vault and into the bound stake pool's vault, where percolator-stake's\r\n * AccrueFees measures it as surplus and distributes it to stakers.\r\n *\r\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\r\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\r\n *\r\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\r\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\r\n * id. The only thing a caller decides is *when* the push happens.\r\n *\r\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\r\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\r\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\r\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\r\n * ResolveMarket, not after.\r\n */\r\n WithdrawInsuranceReserveToStake: 87,\r\n /**\r\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\r\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\r\n * argument with no setter anywhere in the dispatch table and was therefore\r\n * frozen for the life of the market.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\r\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\r\n * (v16_program.rs tag-88 arm), matching both the storage type\r\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\r\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\r\n * rejects the whole instruction with InvalidInstructionData.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\r\n */\r\n UpdateMaintenanceFeePerSlot: 88,\r\n /**\r\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\r\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\r\n * bucket to `Expired`/`Impaired` so settlement against that domain can\r\n * proceed again.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\r\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\r\n *\r\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\r\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\r\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\r\n * horizon defers the lapse, it does not avoid it. See\r\n * {@link encodeExpireBackingBucket} for the full keeper contract.\r\n */\r\n ExpireBackingBucket: 89,\r\n /**\r\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\r\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\r\n * Pays the market creator's accrued trade-fee share out of the vault and\r\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\r\n * EXACTLY `amount`.\r\n *\r\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\r\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\r\n * tag 84).\r\n *\r\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\r\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\r\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\r\n * config and pass that to drain it.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\r\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\r\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\r\n * alone, so this deliberate divergence is what lets the creator still claim\r\n * after staking (and stops the pool PDA claiming creator revenue).\r\n *\r\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\r\n * saturated — there is no partial fill. Nothing is debited on failure.\r\n */\r\n WithdrawCreatorFee: 90,\r\n /**\r\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\r\n * between the two domains of the LP vault's asset, carrying ledger principal\r\n * in lockstep. No tokens move: `header.vault` is untouched.\r\n *\r\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\r\n * gains from the OPPOSITE domain, so without this the pot the house actually\r\n * needs can never be refilled (spec.md L410 requires refill be source-domain\r\n * local).\r\n */\r\n RebalanceLpVaultBacking: 91,\r\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\r\n ReclaimEmptyAccount: 85,\r\n /** @deprecated v12.x tag 86. Not in v17. */\r\n SettleAccount: 86,\r\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\r\n UpdateMarkPrice: 90,\r\n /** @deprecated v12.x tag 91. Not in v17. */\r\n AuditCrank: 91,\r\n /** @deprecated v12.x tag 92. Not in v17. */\r\n AdvanceOraclePhase: 92,\r\n /** @deprecated v12.x tag 93. Not in v17. */\r\n SlashCreationDeposit: 93,\r\n /** @deprecated v12.x tag 94. Not in v17. */\r\n InitSharedVault: 94,\r\n /** @deprecated v12.x tag 95. Not in v17. */\r\n AllocateMarket: 95,\r\n /** @deprecated v12.x tag 96. Not in v17. */\r\n QueueWithdrawalSV: 96,\r\n /** @deprecated v12.x tag 97. Not in v17. */\r\n ClaimEpochWithdrawal: 97,\r\n /** @deprecated v12.x tag 98. Not in v17. */\r\n AdvanceEpoch: 98,\r\n /** @deprecated v12.x tag 99. Not in v17. */\r\n ReclaimSlabRent: 99,\r\n /** @deprecated v12.x tag 100. Not in v17. */\r\n CloseStaleSlabs: 100,\r\n /** @deprecated v12.x tag 101. Not in v17. */\r\n ExecuteAdl: 101,\r\n /** @deprecated v12.x tag 102. Not in v17. */\r\n QueueWithdrawal: 102,\r\n /** @deprecated v12.x tag 103. Not in v17. */\r\n ClaimQueuedWithdrawal: 103,\r\n /** @deprecated v12.x tag 104. Not in v17. */\r\n CancelQueuedWithdrawal: 104,\r\n /** @deprecated v12.x tag 105. Not in v17. */\r\n TradeCpiV: 105,\r\n} as const;\r\nObject.freeze(IX_TAG);\r\n\r\n/**\r\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\r\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\r\n *\r\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\r\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\r\n */\r\nexport const EXPECTED_SLAB_VERSION = 16;\r\n\r\n/**\r\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\r\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\r\n throw new Error(\r\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\r\n );\r\n}\r\n\r\n/**\r\n * InitMarket instruction data — v17 wire format.\r\n *\r\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\r\n *\r\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\r\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\r\n * provided as account metas or configured separately via ConfigureHybridOracle /\r\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\r\n *\r\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\r\n * is completely rejected by the v17 program — the first field read is now\r\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\r\n * a u16 portfolio count, producing invalid config or rejection at every call.\r\n *\r\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\r\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\r\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\r\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\r\n */\r\n/**\r\n * Optional 66-byte extended tail for InitMarket (S-4).\r\n *\r\n * When present and any field is non-zero the encoder appends a 66-byte block\r\n * in the exact order that the program reads it (percolator.rs:1516-1545):\r\n * insurance_withdraw_max_bps u16 (2 bytes)\r\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\r\n * permissionless_resolve_stale_slots u64 (8 bytes)\r\n * funding_horizon_slots u64 (8 bytes)\r\n * funding_k_bps u64 (8 bytes)\r\n * funding_max_premium_bps i64 (8 bytes)\r\n * funding_max_bps_per_slot i64 (8 bytes)\r\n * mark_min_fee u64 (8 bytes)\r\n * force_close_delay_slots u64 (8 bytes)\r\n * total = 2 + 8*8 = 66 bytes\r\n *\r\n * When absent (or all fields are zero) the encoder omits the tail and the\r\n * program treats all extended fields as their default zero values. This\r\n * preserves full backward compatibility with existing 344-byte payloads.\r\n */\r\nexport interface InitMarketExtendedTail {\r\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\r\n insuranceWithdrawMaxBps: number;\r\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\r\n insuranceWithdrawCooldownSlots: bigint | string;\r\n /** Slots after which an unresolved market may be permissionlessly resolved. */\r\n permissionlessResolveStaleSlots: bigint | string;\r\n /** Funding rate horizon in slots (custom_funding_k denominator). */\r\n fundingHorizonSlots: bigint | string;\r\n /** Funding rate K parameter in bps (0 = disabled). */\r\n fundingKBps: bigint | string;\r\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\r\n fundingMaxPremiumBps: bigint | string;\r\n /** Maximum funding rate change per slot in bps (i64). */\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\r\n markMinFee: bigint | string;\r\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\r\n forceCloseDelaySlots: bigint | string;\r\n /**\r\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\r\n *\r\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\r\n * the wrapper applies its deployment default\r\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\r\n * emits a 74-byte v2 tail with this value appended after\r\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\r\n * `InvalidConfigParam`; the engine then re-validates the solvency\r\n * envelope at `init_in_place`.\r\n *\r\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\r\n */\r\n maxPriceMoveBpsPerSlot?: bigint | string;\r\n}\r\n\r\nexport interface InitMarketArgs {\r\n admin: PublicKey | string;\r\n collateralMint: PublicKey | string;\r\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\r\n maxStalenessSecs: bigint | string;\r\n confFilterBps: number;\r\n invert: number;\r\n unitScale: number;\r\n initialMarkPriceE6: bigint | string;\r\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\r\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n maxInsuranceFloor?: bigint | string;\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n minOraclePriceCap?: bigint | string;\r\n // RiskParams block (16 fields, read by read_risk_params on-chain)\r\n /**\r\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\r\n * when hMin/hMax are not provided.\r\n */\r\n warmupPeriodSlots?: bigint | string;\r\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMin?: bigint | string;\r\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMax?: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n initialMarginBps: bigint | string;\r\n tradingFeeBps: bigint | string;\r\n maxAccounts: bigint | string;\r\n newAccountFee: bigint | string;\r\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\r\n maintenanceFeePerSlot: bigint | string;\r\n maxCrankStalenessSlots: bigint | string;\r\n liquidationFeeBps: bigint | string;\r\n liquidationFeeCap: bigint | string;\r\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\r\n minLiquidationAbs: bigint | string;\r\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\r\n minInitialDeposit?: bigint | string;\r\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\r\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\r\n /**\r\n * Optional 66-byte extended tail (S-4).\r\n * When present and any field is non-zero, appended after the 344-byte base payload.\r\n * When absent (or all zeros), the base 344-byte payload is sent and the program\r\n * uses default zero values for all extended fields.\r\n * @see InitMarketExtendedTail\r\n */\r\n extendedTail?: InitMarketExtendedTail;\r\n}\r\n\r\n/**\r\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\r\n *\r\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\r\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\r\n * Retained as a utility for off-chain feed ID validation.\r\n */\r\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function encodeFeedId(feedId: string): Uint8Array {\r\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\r\n if (!HEX_RE.test(hex)) {\r\n throw new Error(\r\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\r\n );\r\n }\r\n const bytes = new Uint8Array(32);\r\n for (let i = 0; i < 64; i += 2) {\r\n const byte = parseInt(hex.substring(i, i + 2), 16);\r\n if (Number.isNaN(byte)) {\r\n throw new Error(\r\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\r\n );\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\r\n * (10_000_000_000_000_000 — effectively unlimited).\r\n *\r\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\r\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\r\n * engine returns `RecoveryRequired` and refuses further liquidation until\r\n * the insurance fund covers the residual. Production markets MUST use this\r\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\r\n * limit is intended AND the insurance fund is sized accordingly.\r\n *\r\n * @example\r\n * ```ts\r\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\r\n * const data = encodeInitMarket({\r\n * ...otherParams,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\r\n\r\n// v17 wire layout (v16_program.rs decode arm at tag 0):\r\n// tag(1) +\r\n// max_portfolio_assets(u16=2) +\r\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\r\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\r\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\r\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\r\n// liquidation_fee_bps(u64=8) +\r\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\r\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\r\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\r\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\r\n// max_bankrupt_close_lifetime_slots(u64=8) +\r\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\r\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\r\nconst INIT_MARKET_V17_LEN = 219;\r\n\r\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\r\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\r\n// with no optional tail — all parameters are required fields in the main body.\r\n\r\n/**\r\n * InitMarket v17 argument interface.\r\n *\r\n * admin and collateralMint are passed as account metas (accounts[0] and\r\n * accounts[2] respectively), NOT in instruction data.\r\n *\r\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\r\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\r\n * after the market is created.\r\n *\r\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\r\n * max_portfolio_assets, h_min, h_max, initial_price,\r\n * min_nonzero_mm_req, min_nonzero_im_req,\r\n * maintenance_margin_bps, initial_margin_bps,\r\n * max_trading_fee_bps, trade_fee_base_bps,\r\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\r\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\r\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\r\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\r\n * max_bankrupt_close_lifetime_slots,\r\n * public_b_chunk_atoms, maintenance_fee_per_slot.\r\n */\r\nexport interface InitMarketV17Args {\r\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\r\n maxPortfolioAssets: number;\r\n /** Minimum funding horizon in slots (u64). */\r\n hMin: bigint | string;\r\n /** Maximum funding horizon in slots (u64). */\r\n hMax: bigint | string;\r\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\r\n initialPrice: bigint | string;\r\n /** Minimum non-zero maintenance margin requirement (u128). */\r\n minNonzeroMmReq: bigint | string;\r\n /** Minimum non-zero initial margin requirement (u128). */\r\n minNonzeroImReq: bigint | string;\r\n /** Maintenance margin ratio in bps (u64). */\r\n maintenanceMarginBps: bigint | string;\r\n /** Initial margin ratio in bps (u64). */\r\n initialMarginBps: bigint | string;\r\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\r\n maxTradingFeeBps: bigint | string;\r\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\r\n tradeFeeBaseBps: bigint | string;\r\n /** Liquidation fee in bps (u64). */\r\n liquidationFeeBps: bigint | string;\r\n /** Liquidation fee cap in absolute units (u128). */\r\n liquidationFeeCap: bigint | string;\r\n /** Minimum liquidation size in absolute units (u128). */\r\n minLiquidationAbs: bigint | string;\r\n /** Maximum price movement per slot in bps (u64). */\r\n maxPriceMoveBpsPerSlot: bigint | string;\r\n /** Maximum accrual delta-time in slots (u64). */\r\n maxAccrualDtSlots: bigint | string;\r\n /** Maximum absolute funding rate in e9 per slot (u64). */\r\n maxAbsFundingE9PerSlot: bigint | string;\r\n /** Minimum funding lifetime in slots (u64). */\r\n minFundingLifetimeSlots: bigint | string;\r\n /** Maximum account-B settlement chunks per crank (u64). */\r\n maxAccountBSettlementChunks: bigint | string;\r\n /** Maximum bankrupt-close chunks per crank (u64). */\r\n maxBankruptCloseChunks: bigint | string;\r\n /** Maximum bankrupt-close lifetime in slots (u64). */\r\n maxBankruptCloseLifetimeSlots: bigint | string;\r\n /**\r\n * Public-B chunk size in atoms (u128).\r\n *\r\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\r\n * the engine returns `RecoveryRequired` when the bankrupt position's\r\n * liability exceeds this limit and insurance is insufficient to cover it.\r\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\r\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\r\n * and a funded insurance pool.\r\n */\r\n publicBChunkAtoms: bigint | string;\r\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\n/**\r\n * Encode InitMarket instruction data (v17 wire format).\r\n *\r\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\r\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\r\n *\r\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\r\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\r\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\r\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\r\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\r\n *\r\n * @param args v17 market parameters (InitMarketV17Args)\r\n * @returns 227-byte Uint8Array\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMarket({\r\n * maxPortfolioAssets: 256,\r\n * hMin: 1000n,\r\n * hMax: 100000n,\r\n * initialPrice: 50_000_000_000n,\r\n * minNonzeroMmReq: 1_000_000n,\r\n * minNonzeroImReq: 2_000_000n,\r\n * maintenanceMarginBps: 500n,\r\n * initialMarginBps: 1000n,\r\n * maxTradingFeeBps: 100n,\r\n * tradeFeeBaseBps: 30n,\r\n * liquidationFeeBps: 100n,\r\n * liquidationFeeCap: 10_000_000n,\r\n * minLiquidationAbs: 1_000_000n,\r\n * maxPriceMoveBpsPerSlot: 4n,\r\n * maxAccrualDtSlots: 600n,\r\n * maxAbsFundingE9PerSlot: 1000n,\r\n * minFundingLifetimeSlots: 50n,\r\n * maxAccountBSettlementChunks: 10n,\r\n * maxBankruptCloseChunks: 10n,\r\n * maxBankruptCloseLifetimeSlots: 500n,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\r\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\r\n const isV17Args = 'maxPortfolioAssets' in args;\r\n\r\n let maxPortfolioAssets: number;\r\n let hMin: bigint | string;\r\n let hMax: bigint | string;\r\n let initialPrice: bigint | string;\r\n let minNonzeroMmReq: bigint | string;\r\n let minNonzeroImReq: bigint | string;\r\n let maintenanceMarginBps: bigint | string;\r\n let initialMarginBps: bigint | string;\r\n let maxTradingFeeBps: bigint | string;\r\n let tradeFeeBaseBps: bigint | string;\r\n let liquidationFeeBps: bigint | string;\r\n let liquidationFeeCap: bigint | string;\r\n let minLiquidationAbs: bigint | string;\r\n let maxPriceMoveBpsPerSlot: bigint | string;\r\n let maxAccrualDtSlots: bigint | string;\r\n let maxAbsFundingE9PerSlot: bigint | string;\r\n let minFundingLifetimeSlots: bigint | string;\r\n let maxAccountBSettlementChunks: bigint | string;\r\n let maxBankruptCloseChunks: bigint | string;\r\n let maxBankruptCloseLifetimeSlots: bigint | string;\r\n let publicBChunkAtoms: bigint | string;\r\n let maintenanceFeePerSlot: bigint | string;\r\n\r\n if (isV17Args) {\r\n const v = args as InitMarketV17Args;\r\n maxPortfolioAssets = v.maxPortfolioAssets;\r\n hMin = v.hMin;\r\n hMax = v.hMax;\r\n initialPrice = v.initialPrice;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n maxTradingFeeBps = v.maxTradingFeeBps;\r\n tradeFeeBaseBps = v.tradeFeeBaseBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\r\n maxAccrualDtSlots = v.maxAccrualDtSlots;\r\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\r\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\r\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\r\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\r\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\r\n publicBChunkAtoms = v.publicBChunkAtoms;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n } else {\r\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\r\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\r\n // invert, unitScale, extendedTail) are silently ignored.\r\n const v = args as InitMarketArgs;\r\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\r\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\r\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\r\n hMin = resolvedHMin;\r\n hMax = resolvedHMax;\r\n initialPrice = v.initialMarkPriceE6;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\r\n maxTradingFeeBps = v.tradingFeeBps;\r\n tradeFeeBaseBps = v.tradingFeeBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\r\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\r\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\r\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\r\n minFundingLifetimeSlots = 0n;\r\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\r\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\r\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\r\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\r\n // them to functional values instead so v12-initialized markets stay recoverable; callers\r\n // wanting explicit control should migrate to InitMarketV17Args.\r\n maxAccountBSettlementChunks = 10n;\r\n maxBankruptCloseChunks = 10n;\r\n maxBankruptCloseLifetimeSlots = 500n;\r\n publicBChunkAtoms = 1_000_000n;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n }\r\n\r\n const data = concatBytes(\r\n encU8(IX_TAG.InitMarket),\r\n encU16(maxPortfolioAssets),\r\n encU64(hMin),\r\n encU64(hMax),\r\n encU64(initialPrice),\r\n encU128(minNonzeroMmReq),\r\n encU128(minNonzeroImReq),\r\n encU64(maintenanceMarginBps),\r\n encU64(initialMarginBps),\r\n encU64(maxTradingFeeBps),\r\n encU64(tradeFeeBaseBps),\r\n encU64(liquidationFeeBps),\r\n encU128(liquidationFeeCap),\r\n encU128(minLiquidationAbs),\r\n encU64(maxPriceMoveBpsPerSlot),\r\n encU64(maxAccrualDtSlots),\r\n encU64(maxAbsFundingE9PerSlot),\r\n encU64(minFundingLifetimeSlots),\r\n encU64(maxAccountBSettlementChunks),\r\n encU64(maxBankruptCloseChunks),\r\n encU64(maxBankruptCloseLifetimeSlots),\r\n encU128(publicBChunkAtoms),\r\n encU128(maintenanceFeePerSlot),\r\n );\r\n\r\n if (data.length !== INIT_MARKET_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n return data;\r\n}\r\n\r\n/**\r\n * InitPortfolio / InitUser instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\r\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\r\n * Sending extra bytes causes garbage reads in downstream decoder arms.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitUser();\r\n * ```\r\n */\r\nexport interface InitUserArgs {\r\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\r\n feePayment?: bigint | string;\r\n}\r\n\r\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.InitPortfolio]);\r\n}\r\n\r\n/**\r\n * InitLP (tag 2) — REMOVED in v17.\r\n *\r\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\r\n */\r\nexport interface InitLPArgs {\r\n matcherProgram: PublicKey | string;\r\n matcherContext: PublicKey | string;\r\n feePayment: bigint | string;\r\n}\r\n\r\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\r\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\r\n}\r\n\r\n/**\r\n * DepositCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\r\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\r\n *\r\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface DepositCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\r\n *\r\n * @param amount Collateral to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\r\n * ```\r\n */\r\nexport interface WithdrawCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) action byte values.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\r\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\r\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\r\n */\r\nexport const CrankAction = {\r\n FeeSweep: 0,\r\n Liquidate: 1,\r\n} as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) instruction args.\r\n *\r\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\r\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\r\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\r\n * and the fee rate is always read from config inside\r\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\r\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\r\n * while still making forward progress. Any client still encoding the old\r\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\r\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\r\n * side, not a runtime check.\r\n *\r\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\r\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\r\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\r\n * `read_u64`/`read_i128`/`push_*` call sequence.\r\n *\r\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\r\n * The program hard-rejects any nonzero value with InvalidInstructionData.\r\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\r\n * produces a truncated instruction (missing 16 bytes).\r\n *\r\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\r\n * @param assetIndex Asset/domain index to operate on.\r\n * @param nowSlot Current slot (for crank freshness check).\r\n * @param recoveryReason Recovery reason byte (0 for normal operations).\r\n *\r\n * @example\r\n * ```ts\r\n * // Simple fee-sweep crank\r\n * const data = encodePermissionlessCrank({\r\n * action: CrankAction.FeeSweep,\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * recoveryReason: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface PermissionlessCrankArgs {\r\n action: number;\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n recoveryReason: number;\r\n}\r\n\r\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.PermissionlessCrank),\r\n encU8(args.action),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\r\n encU8(args.recoveryReason),\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\r\n * Use encodePermissionlessCrank() instead.\r\n *\r\n * Retained for source-compat only. Will throw to prevent silent misuse.\r\n */\r\nexport interface KeeperCrankArgs {\r\n callerIdx: number;\r\n candidates?: unknown[];\r\n}\r\n\r\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\r\n throw new Error(\r\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\r\n \"Use encodePermissionlessCrank() instead.\"\r\n );\r\n}\r\n\r\n/**\r\n * TradeNoCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\r\n * v17 has asset_index+size_q+exec_price+fee_bps.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\r\n * @param execPrice Execution price in e6 units.\r\n * @param feeBps Fee in basis points.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeNoCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * execPrice: 50_000_000_000n,\r\n * feeBps: 30n,\r\n * });\r\n * ```\r\n */\r\nexport interface TradeNoCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeNoCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.execPrice),\r\n encU64(args.feeBps),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\r\n *\r\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\r\n */\r\nexport interface LiquidateAtOracleArgs {\r\n targetIdx: number;\r\n}\r\n\r\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LiquidateAtOracle\",\r\n IX_TAG.LiquidateAtOracle,\r\n \"PermissionlessCrank (tag 5)\",\r\n );\r\n}\r\n\r\n/**\r\n * ClosePortfolio / CloseAccount instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\r\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\r\n * bytes from the old userIdx field cause InvalidInstructionData.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseAccount();\r\n * ```\r\n */\r\nexport interface CloseAccountArgs {\r\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\r\n userIdx?: number;\r\n}\r\n\r\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.ClosePortfolio]);\r\n}\r\n\r\n/**\r\n * TopUpInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\r\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\r\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\r\n *\r\n * @param amount Amount to top up the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\r\n * ```\r\n */\r\nexport interface TopUpInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * TopUpBackingBucket instruction data (tag 24).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\r\n * = 27 bytes.\r\n *\r\n * Deposits `amount` quote atoms of external collateral into a source domain's\r\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\r\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\r\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\r\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\r\n *\r\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\r\n * SHORT domain is `2*i + 1`.\r\n *\r\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\r\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\r\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\r\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\r\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\r\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\r\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\r\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\r\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\r\n * every later automatic loss-reserve requests the SAME existing expiry and\r\n * hits the harmless no-op arm instead of the LockActive trap.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\r\n * nonzero \"dust\" amount is sufficient — there is no\r\n * minimum floor enforced by the engine.\r\n * @param expirySlot Requested fresh-expiry slot (u64). Use\r\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\r\n *\r\n * @example\r\n * ```ts\r\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\r\n * const data = encodeTopUpBackingBucket({\r\n * domain: 0,\r\n * amount: 10_000n, // 0.01 Sim-USDC dust\r\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\r\n * });\r\n * ```\r\n */\r\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\r\n\r\nexport interface TopUpBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n expirySlot: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TopUpBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n encU64(args.expirySlot),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucket instruction data (tag 50).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\r\n * back to the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\r\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\r\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\r\n *\r\n * Together with TopUpBackingBucket (24, deposit) and\r\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\r\n * LP-provider backing-bucket loop.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateBackingFeePolicy instruction data (tag 51).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * THE switch that turns on LP-vault yield for a domain: sets the\r\n * backing-trade fee charged on that domain's fills, of which\r\n * `insurance_share_bps` is diverted to the insurance budget and the\r\n * remainder accrues to the domain's backing-bucket providers as\r\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\r\n * currently has this at 0 — which is why LP APY is 0%.\r\n *\r\n * Gated by the asset's `insurance_authority` (v16_program.rs\r\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\r\n * the market creator can call it even after the launch flow rotates\r\n * marketauth to the stake-pool PDA. Market must be Live.\r\n *\r\n * Handler-side validation (reverts InvalidInstruction otherwise):\r\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\r\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\r\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\r\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\r\n * of the fee (the rest goes to backing providers).\r\n */\r\nexport interface UpdateBackingFeePolicyArgs {\r\n domain: number;\r\n feeBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateBackingFeePolicy),\r\n encU16(args.domain),\r\n encU16(args.feeBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings instruction data (tag 52).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\r\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\r\n * the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket_earnings` → same\r\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\r\n * per-domain ledger account is REQUIRED (account [2]).\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketEarningsArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucketEarnings(\r\n args: WithdrawBackingBucketEarningsArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * TradeCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\r\n * v17 has asset_index+size_q+fee_bps+limit_price.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed).\r\n * @param feeBps Fee in basis points.\r\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\r\n * Buys: reject if exec_price > limit_price.\r\n * Sells: reject if exec_price < limit_price.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * feeBps: 30n,\r\n * limitPrice: 51_000_000_000n, // max price for a buy\r\n * });\r\n * ```\r\n */\r\nexport interface TradeCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n /** Limit price in e6 units. 0 = no limit. */\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.feeBps),\r\n encU64(args.limitPrice),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\r\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\r\n */\r\nexport interface TradeCpiV2Args {\r\n lpIdx: number;\r\n userIdx: number;\r\n size: bigint | string;\r\n bump: number;\r\n}\r\n\r\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\r\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\r\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\r\n */\r\nexport interface UnresolveMarketArgs {\r\n confirmation: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\r\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\r\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetRiskThresholdArgs {\r\n newThreshold: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\r\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * UpdateAdmin (tag 12) — REMOVED in v17.\r\n *\r\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\r\n */\r\nexport interface UpdateAdminArgs {\r\n newAdmin: PublicKey | string;\r\n}\r\n\r\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\r\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateAdmin\",\r\n IX_TAG.UpdateAdmin,\r\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\r\n );\r\n}\r\n\r\n/**\r\n * CloseSlab instruction data (1 byte)\r\n */\r\nexport function encodeCloseSlab(): Uint8Array {\r\n return encU8(IX_TAG.CloseSlab);\r\n}\r\n\r\n/**\r\n * UpdateConfig instruction data.\r\n *\r\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\r\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\r\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\r\n * src/percolator.rs:2027-2041 (handle_update_config decode).\r\n */\r\nexport interface UpdateConfigArgs {\r\n fundingHorizonSlots: bigint | string;\r\n fundingKBps: bigint | string;\r\n fundingMaxPremiumBps: bigint | string;\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /**\r\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\r\n * Wrapper field added at src/percolator.rs:2031.\r\n */\r\n tvlInsuranceCapMult?: number;\r\n}\r\n\r\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\r\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\r\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetMaintenanceFeeArgs {\r\n newFee: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\r\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * SetOraclePriceCap instruction data (9 bytes)\r\n * Set oracle price circuit breaker cap (admin only).\r\n *\r\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\r\n * 1_000_000 = 100% max move per slot.\r\n *\r\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\r\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\r\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\r\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\r\n *\r\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\r\n */\r\nexport interface SetOraclePriceCapArgs {\r\n maxChangeE2bps: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\r\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\r\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\r\n}\r\n\r\n/**\r\n * ResolveMode constants — retained for source compatibility with v12.x callers.\r\n *\r\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\r\n * no longer encoded into the instruction data. They may be used in logging or\r\n * off-chain logic but must not be passed to encodeResolveMarket.\r\n */\r\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\r\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\r\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\r\n\r\n/**\r\n * ResolveMarket instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\r\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\r\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\r\n * next read in a subsequent call, corrupting the instruction stream.\r\n *\r\n * The `mode` argument is accepted for source compatibility but is silently ignored.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeResolveMarket();\r\n * ```\r\n */\r\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\r\n return new Uint8Array([IX_TAG.ResolveMarket]);\r\n}\r\n\r\n/**\r\n * WithdrawInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\r\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\r\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\r\n * 1-byte payload fails on devnet/mainnet.\r\n *\r\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\r\n *\r\n * @param amount Amount to withdraw from the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * AdminForceClose instruction data (3 bytes)\r\n * Force-close any position at oracle price (admin only, skips margin checks).\r\n */\r\nexport interface AdminForceCloseArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\r\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\r\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\r\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\r\n * Use encodeSetInsuranceWithdrawPolicy instead.\r\n */\r\nexport interface UpdateRiskParamsArgs {\r\n initialMarginBps: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n tradingFeeBps?: bigint | string;\r\n}\r\n\r\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\r\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateRiskParams\",\r\n IX_TAG.UpdateRiskParams,\r\n \"encodeSetInsuranceWithdrawPolicy()\",\r\n );\r\n}\r\n\r\n/**\r\n * On-chain confirmation code for RenounceAdmin (must match program constant).\r\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\r\n */\r\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\r\n\r\n/**\r\n * On-chain confirmation code for UnresolveMarket (must match program constant).\r\n */\r\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\r\n\r\n/**\r\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\r\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\r\n * Use encodeWithdrawInsuranceLimited instead.\r\n */\r\nexport function encodeRenounceAdmin(): Uint8Array {\r\n return removedInstruction(\r\n \"RenounceAdmin\",\r\n IX_TAG.RenounceAdmin,\r\n \"encodeWithdrawInsuranceLimited()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\r\n * withdraw proportional collateral.\r\n *\r\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\r\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\r\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\r\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\r\n *\r\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\r\n *\r\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\r\n * [0] withdrawer signer\r\n * [1] slab writable\r\n * [2] withdrawerAta writable\r\n * [3] vault writable\r\n * [4] tokenProgram\r\n * [5] lpVaultMint writable\r\n * [6] withdrawerLpAta writable\r\n * [7] vaultAuthority\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\r\n *\r\n * @param lpAmount - Amount of LP vault tokens to burn.\r\n *\r\n * @example\r\n * ```ts\r\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\r\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\r\n *\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\r\n *\r\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\r\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\r\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\r\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\r\n * });\r\n * ```\r\n */\r\nexport interface LpVaultWithdrawArgs {\r\n /** Amount of LP vault tokens to burn. */\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\r\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\r\n */\r\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\r\n IX_TAG.LpVaultWithdraw,\r\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\r\n */\r\nexport function encodePauseMarket(): Uint8Array {\r\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\r\n */\r\nexport function encodeUnpauseMarket(): Uint8Array {\r\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-117: Pyth Oracle CPI Instructions\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetPythOracleArgs {\r\n feedId: Uint8Array;\r\n maxStalenessSecs: bigint;\r\n confFilterBps: number;\r\n}\r\n\r\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\r\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\r\n void args;\r\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\r\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\r\n *\r\n * @param feedId 32-byte Pyth feed ID\r\n * @param shardId Shard index (default 0 for mainnet/devnet)\r\n */\r\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\r\n\r\nexport async function derivePythPriceUpdateAccount(\r\n feedId: Uint8Array,\r\n shardId = 0,\r\n): Promise {\r\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\r\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\r\n }\r\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\r\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\r\n }\r\n const { PublicKey } = await import('@solana/web3.js');\r\n const shardBuf = new Uint8Array(2);\r\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\r\n const [pda] = PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\r\n );\r\n return pda.toBase58();\r\n}\r\n\r\n// SetPythOracle tag (32) is already defined in IX_TAG above.\r\n\r\n// PERC-118: Mark Price EMA Instructions\r\n// ============================================================================\r\n\r\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\r\n\r\n/**\r\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport function encodeUpdateMarkPrice(): Uint8Array {\r\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\r\n}\r\n\r\n/**\r\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\r\n */\r\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\r\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\r\n\r\n/**\r\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\r\n */\r\nexport function computeEmaMarkPrice(\r\n markPrevE6: bigint,\r\n oracleE6: bigint,\r\n dtSlots: bigint,\r\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\r\n capE2bps = 0n,\r\n): bigint {\r\n if (oracleE6 === 0n) return markPrevE6;\r\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\r\n\r\n let oracleClamped = oracleE6;\r\n if (capE2bps > 0n) {\r\n // Avoid overflow: divide early to reduce intermediate product\r\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\r\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\r\n const hi = markPrevE6 + maxDelta;\r\n if (oracleClamped < lo) oracleClamped = lo;\r\n if (oracleClamped > hi) oracleClamped = hi;\r\n }\r\n\r\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\r\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\r\n\r\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\r\n}\r\n\r\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\r\n// ============================================================================\r\n\r\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\r\n\r\n/**\r\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\r\n *\r\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\r\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\r\n * to authority_price_e6 on the slab.\r\n *\r\n * This is the core mechanism for permissionless token markets — no Pyth or\r\n * Chainlink feed is needed. The DEX AMM IS the oracle.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\r\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\r\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\r\n */\r\nexport function encodeUpdateHyperpMark(): Uint8Array {\r\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\r\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\r\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\r\n return removedInstruction(\r\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\r\n 34,\r\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-306: Per-Market Insurance Isolation\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\r\n */\r\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\r\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\r\n}\r\n\r\n/**\r\n * Set insurance isolation BPS for a market.\r\n * Accounts: [admin(signer), slab(writable)]\r\n */\r\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\r\n void args;\r\n return removedInstruction(\r\n \"SetInsuranceIsolation\",\r\n IX_TAG.SetInsuranceIsolation,\r\n \"encodeFundMarketInsurance()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\r\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\r\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\r\n// ============================================================================\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\r\n *\r\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\r\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\r\n *\r\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\r\n * ```\r\n */\r\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\r\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n/**\r\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\r\n *\r\n * Burns LP tokens and releases one tranche of SOL to the user.\r\n * Call once per epoch until epochs_remaining == 0.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\r\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\r\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\r\n */\r\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\r\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\r\n *\r\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\r\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\r\n * Use only to abandon a partial withdrawal.\r\n *\r\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\r\n */\r\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\r\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\r\n *\r\n * Permissionless. Surgically closes or reduces `targetIdx` position when\r\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\r\n * the incentive is unblocking the market for normal trading.\r\n *\r\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\r\n *\r\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\r\n *\r\n * @param targetIdx - Account index of the position to deleverage.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteAdl({ targetIdx: 5 });\r\n * ```\r\n */\r\nexport interface ExecuteAdlArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\r\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\r\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\r\n *\r\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\r\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\r\n * whose size does not match any current valid tier.\r\n *\r\n * Accounts: [dest(signer,writable), slab(writable)]\r\n */\r\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\r\nexport function encodeCloseStaleSlabs(): Uint8Array {\r\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\r\n}\r\n\r\n/**\r\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\r\n *\r\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\r\n * The slab account must sign (proves the caller holds the slab keypair).\r\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\r\n *\r\n * Accounts: [dest(signer,writable), slab(signer,writable)]\r\n */\r\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\r\nexport function encodeReclaimSlabRent(): Uint8Array {\r\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\r\n *\r\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\r\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\r\n * prevent DoS from transient failures).\r\n *\r\n * Accounts: [slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeAuditCrank();\r\n * ```\r\n */\r\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\r\nexport function encodeAuditCrank(): Uint8Array {\r\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// SMART PRICE ROUTER — quote computation for LP selection\r\n// ============================================================================\r\n\r\n/**\r\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\r\n */\r\nexport interface VammMatcherParams {\r\n mode: number; // 0 = Passive, 1 = vAMM\r\n tradingFeeBps: number;\r\n baseSpreadBps: number;\r\n maxTotalBps: number;\r\n impactKBps: number;\r\n liquidityNotionalE6: bigint;\r\n}\r\n\r\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\r\nexport const VAMM_MAGIC = 0x504552434d415443n;\r\n/** Alias matching the Rust constant name for parity tests */\r\nexport const MATCHER_MAGIC = VAMM_MAGIC;\r\n\r\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\r\nexport const CTX_RETURN_OFFSET = 0;\r\n/** Byte length of the MatcherReturn section of the context account */\r\nexport const MATCHER_RETURN_LEN = 64;\r\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\r\nexport const CTX_VAMM_OFFSET = 64;\r\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\r\nexport const CTX_VAMM_LEN = 256;\r\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\r\nexport const MATCHER_CONTEXT_LEN = 320;\r\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\r\nexport const MATCHER_CALL_LEN = 67;\r\n/**\r\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\r\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\r\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\r\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\r\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\r\n */\r\nexport const INIT_CTX_LEN = 78;\r\n\r\nconst BPS_DENOM = 10_000n;\r\n\r\n/**\r\n * Compute execution price for a given LP quote.\r\n * For buys (isLong=true): price above oracle.\r\n * For sells (isLong=false): price below oracle.\r\n */\r\nexport function computeVammQuote(\r\n params: VammMatcherParams,\r\n oraclePriceE6: bigint,\r\n tradeSize: bigint,\r\n isLong: boolean,\r\n): bigint {\r\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\r\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\r\n\r\n // Impact for vAMM mode\r\n let impactBps = 0n;\r\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\r\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\r\n }\r\n\r\n // Total = base_spread + trading_fee + impact, capped at max_total\r\n const maxTotal = BigInt(params.maxTotalBps);\r\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\r\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\r\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\r\n let totalBps = baseFee + clampedImpact;\r\n if (totalBps > maxTotal) totalBps = maxTotal;\r\n\r\n if (isLong) {\r\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\r\n } else {\r\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\r\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\r\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless crank)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\r\n *\r\n * Checks if a market should transition from Phase 0→1→2 based on\r\n * time elapsed and cumulative volume. Anyone can call this.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n */\r\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\r\nexport function encodeAdvanceOraclePhase(): Uint8Array {\r\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\r\n}\r\n\r\n/** Oracle phase constants matching on-chain values */\r\nexport const ORACLE_PHASE_NASCENT = 0;\r\nexport const ORACLE_PHASE_GROWING = 1;\r\nexport const ORACLE_PHASE_MATURE = 2;\r\n\r\n/** Phase transition thresholds (must match program constants) */\r\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\r\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\r\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\r\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\r\n\r\n/**\r\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\r\n *\r\n * @returns [newPhase, shouldTransition]\r\n */\r\nexport function checkPhaseTransition(\r\n currentSlot: bigint,\r\n marketCreatedSlot: bigint,\r\n oraclePhase: number,\r\n cumulativeVolumeE6: bigint,\r\n phase2DeltaSlots: number,\r\n hasMatureOracle: boolean,\r\n): [number, boolean] {\r\n switch (oraclePhase) {\r\n case 0: {\r\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\r\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\r\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\r\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\r\n if (timeReady || volumeReady) {\r\n return [ORACLE_PHASE_GROWING, true];\r\n }\r\n return [ORACLE_PHASE_NASCENT, false];\r\n }\r\n case 1: {\r\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\r\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\r\n const elapsedSincePhase2 = currentSlot - phase2Start;\r\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\r\n return [ORACLE_PHASE_MATURE, true];\r\n }\r\n return [ORACLE_PHASE_GROWING, false];\r\n }\r\n default:\r\n return [ORACLE_PHASE_MATURE, false];\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-629: Dynamic Creation Deposit\r\n// ============================================================================\r\n\r\n/**\r\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\r\n * after the spam grace period has elapsed (PERC-629).\r\n *\r\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\r\n * handler in the on-chain program. Sending this instruction will fail with\r\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [] Slab\r\n * 2. [writable] Creator history PDA\r\n * 3. [writable] Insurance vault\r\n * 4. [writable] Treasury\r\n * 5. [] System program\r\n *\r\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\r\n */\r\nexport function encodeSlashCreationDeposit(): Uint8Array {\r\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\r\n// ============================================================================\r\n\r\n/**\r\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\r\n *\r\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [writable] Shared vault PDA\r\n * 2. [] System program\r\n */\r\nexport interface InitSharedVaultArgs {\r\n epochDurationSlots: bigint | string;\r\n maxMarketExposureBps: number;\r\n}\r\n\r\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\r\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\r\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\r\n}\r\n\r\n/**\r\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\r\n * to a market (PERC-628).\r\n *\r\n * Instruction data: tag(1) + amount(16) = 17 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [] Slab\r\n * 2. [writable] Shared vault PDA\r\n * 3. [writable] Market alloc PDA\r\n * 4. [] System program\r\n */\r\nexport interface AllocateMarketArgs {\r\n amount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\r\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\r\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\r\n}\r\n\r\n/**\r\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\r\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\r\n *\r\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] System program\r\n */\r\nexport interface QueueWithdrawalSVArgs {\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\r\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\r\n}\r\n\r\n/**\r\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\r\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] Slab\r\n * 4. [writable] Vault\r\n * 5. [writable] User ATA\r\n * 6. [] Vault authority\r\n * 7. [] Token program\r\n */\r\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\r\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\r\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [writable] Shared vault PDA\r\n */\r\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\r\nexport function encodeAdvanceEpoch(): Uint8Array {\r\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\r\n}\r\n\r\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\r\n\r\n// PERC-8110 ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\r\n *\r\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\r\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\r\n *\r\n * - `threshold_bps = 0`: hard block disabled.\r\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\r\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\r\n *\r\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\r\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\r\n * });\r\n * ```\r\n */\r\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\r\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-608 — Position NFT instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\r\n *\r\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\r\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\r\n *\r\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\r\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\r\n * program creates it, so the ATA can't be created in a preceding instruction.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts (11):\r\n * 0. [signer, writable] payer\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\r\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\r\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\r\n * 5. [signer] owner (must match engine account owner)\r\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\r\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\r\n * 8. [] system_program\r\n * 9. [] rent sysvar\r\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\r\n */\r\nexport interface MintPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\r\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\r\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\r\n */\r\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\r\n IX_TAG.MintPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\r\n *\r\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\r\n * engine account's owner field. Requires `pending_settlement == 0`.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] current_owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA\r\n * 3. [writable] nft_mint PDA\r\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\r\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\r\n * 6. [] new_owner\r\n * 7. [] token_2022_program\r\n */\r\nexport interface TransferPositionOwnershipArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\r\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\r\n */\r\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\r\n IX_TAG.TransferPositionOwnership,\r\n \"encodeTransferPortfolioOwnership() (tag 72)\",\r\n );\r\n}\r\n\r\n/**\r\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\r\n *\r\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\r\n * Can only be called after the position is fully closed (size == 0).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (closed — rent to owner)\r\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\r\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\r\n * 5. [] vault_authority PDA\r\n * 6. [] token_2022_program\r\n */\r\nexport interface BurnPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\r\n * NFT burn is handled by the standalone percolator-nft program in v17.\r\n */\r\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\r\n IX_TAG.BurnPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin before performing a funding settlement transfer.\r\n * Blocks NFT transfers until ClearPendingSettlement is called.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface SetPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\r\n */\r\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\r\n IX_TAG.SetPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface ClearPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\r\n */\r\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\r\n IX_TAG.ClearPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\r\n *\r\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\r\n * Updates the engine account's owner field to the new_owner public key.\r\n * NOT intended for direct external use — always called via Token-2022 CPI.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] nft TransferHook program (CPI caller)\r\n * 1. [writable] slab\r\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\r\n */\r\nexport interface TransferOwnershipCpiArgs {\r\n userIdx: number;\r\n newOwner: PublicKey | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\r\n */\r\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\r\n IX_TAG.TransferOwnershipCpi,\r\n \"percolator-nft transfer hook\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-8111 — SetWalletCap (tag 70)\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\r\n *\r\n * Limits the maximum absolute position size any single wallet may hold on this market.\r\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\r\n *\r\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\r\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\r\n * Phase 1 launch value: 1_000_000_000n ($1,000).\r\n *\r\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\r\n * (error code 58) is returned.\r\n *\r\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * // Set $1K per-wallet cap\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\r\n * });\r\n *\r\n * // Disable cap\r\n * const disableIx = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\r\n * });\r\n * ```\r\n */\r\nexport interface SetWalletCapArgs {\r\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\r\n capE6: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\r\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\r\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\r\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\r\n *\r\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\r\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\r\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\r\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\r\n * handler reads the LP portfolio's stored matcher config and verifies that:\r\n * cfg.matcher_program == matcherProg\r\n * cfg.matcher_context == matcherCtx\r\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\r\n *\r\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\r\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\r\n * check on the deployed binary. No client-side signer of the delegate is needed.\r\n *\r\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\r\n * [0] lp_owner signer (LP portfolio owner)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\r\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\r\n * [4] matcher_prog read-only, executable (the matcher program)\r\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\r\n *\r\n * @param args.kind 0=Passive, 1=vAMM\r\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\r\n * @param args.baseSpreadBps Base spread in bps (u32)\r\n * @param args.maxTotalBps Max total spread in bps (u32)\r\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\r\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\r\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\r\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\r\n *\r\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\r\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\r\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\r\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\r\n * this tag free.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMatcherCtx({\r\n * kind: 0, // Passive\r\n * tradingFeeBps: 30,\r\n * baseSpreadBps: 50,\r\n * maxTotalBps: 200,\r\n * impactKBps: 0,\r\n * liquidityNotionalE6: 0n,\r\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\r\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\r\n * feeToInsuranceBps: 0,\r\n * skewSpreadMultBps: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface InitMatcherCtxArgs {\r\n /**\r\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\r\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\r\n */\r\n lpIdx?: number;\r\n /** Matcher kind: 0=Passive, 1=vAMM. */\r\n kind: number;\r\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\r\n tradingFeeBps: number;\r\n /** Base spread in bps (u32). */\r\n baseSpreadBps: number;\r\n /** Max total spread in bps (u32). */\r\n maxTotalBps: number;\r\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\r\n impactKBps: number;\r\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\r\n liquidityNotionalE6: bigint | string;\r\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\r\n maxFillAbs: bigint | string;\r\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\r\n maxInventoryAbs: bigint | string;\r\n /** Fraction of fees routed to insurance fund in bps (u16). */\r\n feeToInsuranceBps: number;\r\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\r\n skewSpreadMultBps: number;\r\n}\r\n\r\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\r\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\r\n\r\n/**\r\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\r\n *\r\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\r\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\r\n *\r\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\r\n * @returns 70-byte Uint8Array\r\n */\r\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(83), // IX_TAG.InitMatcherCtx = 83\r\n encU8(args.kind),\r\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\r\n encU128(args.liquidityNotionalE6), // u128 LE\r\n encU128(args.maxFillAbs), // u128 LE\r\n encU128(args.maxInventoryAbs), // u128 LE\r\n encU16(args.feeToInsuranceBps), // u16 LE\r\n encU16(args.skewSpreadMultBps), // u16 LE\r\n );\r\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n// ============================================================================\r\n// Missing encoders — corrected tag mappings (tags 22-74)\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\r\n */\r\nexport interface SetInsuranceWithdrawPolicyArgs {\r\n authority: PublicKey | string;\r\n minWithdrawBase: bigint | string;\r\n maxWithdrawBps: number;\r\n cooldownSlots: bigint | string;\r\n}\r\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\r\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\r\n */\r\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\r\n */\r\nexport function encodeResolvePermissionless(): Uint8Array {\r\n return removedInstruction(\r\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\r\n IX_TAG.ResolvePermissionless,\r\n \"encodeResolveStalePermissionless()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\r\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\r\n return removedInstruction(\r\n \"ForceCloseResolved\",\r\n IX_TAG.ForceCloseResolved,\r\n \"encodeCloseResolved() for v17\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeCreateLpVault (v12 format)\",\r\n IX_TAG.CreateLpVault,\r\n \"encodeCreateLpVaultV17()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeLpVaultDeposit (v12 format)\",\r\n IX_TAG.LpVaultDeposit,\r\n \"encodeDepositToLpVault()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\r\n */\r\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"ChallengeSettlement\",\r\n IX_TAG.ChallengeSettlement,\r\n undefined,\r\n );\r\n}\r\n\r\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\r\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\r\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\r\n}\r\n\r\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\r\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\r\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\r\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\r\n}\r\n\r\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\r\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\r\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\r\n}\r\n\r\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\r\nexport function encodeRescueOrphanVault(): Uint8Array {\r\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\r\n}\r\n\r\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\r\nexport function encodeCloseOrphanSlab(): Uint8Array {\r\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\r\n}\r\n\r\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\r\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\r\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeCreateInsuranceMint(): Uint8Array {\r\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n// ============================================================================\r\n// Phase B admin setters (tags 78-81) — added 2026-04-17\r\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\r\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport interface SetMaxPnlCapArgs {\r\n cap: bigint | string;\r\n}\r\n\r\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\r\n IX_TAG.SetMaxPnlCap,\r\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\r\n */\r\nexport interface SetOiCapMultiplierArgs {\r\n packed: bigint | string;\r\n}\r\n\r\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\r\n IX_TAG.SetOiCapMultiplier,\r\n \"encodeSetLpVaultPaused() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\r\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\r\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\r\n }\r\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\r\n }\r\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\r\n */\r\nexport interface SetDisputeParamsArgs {\r\n windowSlots: bigint | string;\r\n bondAmount: bigint | string;\r\n}\r\n\r\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\r\n IX_TAG.SetDisputeParams,\r\n \"encodeCloseLpVault() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\r\n */\r\nexport interface SetLpCollateralParamsArgs {\r\n enabled: number;\r\n ltvBps: number;\r\n}\r\n\r\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\r\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\r\n */\r\nexport function encodeAcceptAdmin(): Uint8Array {\r\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\r\n}\r\n\r\n// ============================================================================\r\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\r\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\r\n */\r\nexport interface ReclaimEmptyAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\r\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\r\n */\r\nexport interface SettleAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\r\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\r\n */\r\nexport interface DepositFeeCreditsArgs {\r\n userIdx: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\r\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\r\n}\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\r\n * Owner only.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\r\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\r\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\r\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\r\n * are identified by account key alone.\r\n *\r\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\r\n *\r\n * @param amount Amount of released PnL to convert (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface ConvertReleasedPnlArgs {\r\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ConvertReleasedPnl),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\r\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\r\n *\r\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\r\n *\r\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\r\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\r\n * Burning marketauth to zero is rejected on-chain.\r\n *\r\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\r\n * ```\r\n */\r\nexport interface UpdateAuthorityArgs {\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAuthority),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — UpdateAssetAuthority (tag 65)\r\n// ============================================================================\r\n\r\n/**\r\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\r\n *\r\n * Exact mapping from v16_program.rs lines 5246-5250:\r\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\r\n * ASSET_AUTH_INSURANCE = 1 → Insurance\r\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\r\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\r\n * ASSET_AUTH_ORACLE = 4 → Oracle\r\n *\r\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\r\n * slot. Wrong values silently corrupt authority state:\r\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\r\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\r\n * corrupting the market-level admin key instead.\r\n *\r\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\r\n * the stake vault PDA into the asset_admin authority slot.\r\n */\r\nexport const ASSET_AUTH_KIND = {\r\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\r\n AssetAdmin: 0,\r\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\r\n Insurance: 1,\r\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\r\n InsuranceOperator: 2,\r\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\r\n BackingBucket: 3,\r\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\r\n Oracle: 4,\r\n} as const;\r\nObject.freeze(ASSET_AUTH_KIND);\r\n\r\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\r\n\r\n/**\r\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * Gated by the asset's own asset_admin (can rotate any) or by the current\r\n * holder of that authority (self-rotation). Isolated to the given asset_index.\r\n *\r\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\r\n * @param kind ASSET_AUTH_KIND.* constant.\r\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\r\n *\r\n * @example\r\n * ```ts\r\n * // Rotate insurance authority for asset 0\r\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\r\n * const data = encodeUpdateAssetAuthority({\r\n * assetIndex: 0,\r\n * kind: ASSET_AUTH_KIND.Insurance,\r\n * newPubkey: newInsuranceKey,\r\n * });\r\n * ```\r\n */\r\nexport interface UpdateAssetAuthorityArgs {\r\n assetIndex: number;\r\n kind: AssetAuthKind;\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAssetAuthority),\r\n encU16(args.assetIndex),\r\n encU8(args.kind),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\r\n// ============================================================================\r\n\r\n/**\r\n * One leg of a BatchTradeNoCpi instruction.\r\n */\r\nexport interface BatchTradeNoCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\n/**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\r\n *\r\n * @param legs Array of up to 255 trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeNoCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\r\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\r\n * ]});\r\n * ```\r\n */\r\nexport interface BatchTradeNoCpiArgs {\r\n legs: BatchTradeNoCpiLeg[];\r\n}\r\n\r\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\r\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\r\n if (feeBps > 10_000n) {\r\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\r\n }\r\n}\r\n\r\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeNoCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.execPrice));\r\n parts.push(encU64(leg.feeBps));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n/**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\r\n *\r\n * @param legs Array of up to 255 CPI trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\r\n * ]});\r\n * ```\r\n */\r\n\r\nexport interface BatchTradeCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport interface BatchTradeCpiArgs {\r\n legs: BatchTradeCpiLeg[];\r\n}\r\n\r\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.feeBps));\r\n parts.push(encU64(leg.limitPrice));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — SetMatcherConfig (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n *\r\n * @param enabled 1 = enabled, 0 = disabled.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetMatcherConfig({ enabled: 1 });\r\n * ```\r\n */\r\nexport interface SetMatcherConfigArgs {\r\n enabled: number;\r\n}\r\n\r\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\r\n if (args.enabled !== 0 && args.enabled !== 1) {\r\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\r\n }\r\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — RestartAssetOracle (tag 69)\r\n// ============================================================================\r\n\r\n/**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\r\n *\r\n * Used to un-stick a stale or hung oracle. Anyone can call this.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param nowSlot Current slot.\r\n * @param initialPrice Initial mark price in e6 units.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRestartAssetOracle({\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * initialPrice: 50_000_000_000n,\r\n * });\r\n * ```\r\n */\r\nexport interface RestartAssetOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialPrice: bigint | string;\r\n}\r\n\r\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RestartAssetOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialPrice),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\r\n *\r\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\r\n * asset_index is u16 (domain u8→u16 migration in v17).\r\n *\r\n * @param assetIndex Asset/domain index (u16, not u8).\r\n * @param amount Amount to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceAssetArgs {\r\n assetIndex: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawInsuranceAsset),\r\n encU16(args.assetIndex),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — LP-vault renumbered tags (74-80)\r\n// ============================================================================\r\n\r\n/**\r\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\r\n *\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\r\n *\r\n * @param feeShareBps LP vault fee share in bps (0-10000).\r\n * @param redemptionCooldownSlots Slots between redemption requests.\r\n * @param oiReservationThresholdBps OI reservation threshold in bps.\r\n * @param domain Asset/domain index (u16 in v17).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCreateLpVault({\r\n * feeShareBps: 5000,\r\n * redemptionCooldownSlots: 21600n,\r\n * oiReservationThresholdBps: 8000,\r\n * domain: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface CreateLpVaultArgs {\r\n feeShareBps: number;\r\n redemptionCooldownSlots: bigint | string;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n}\r\n\r\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.CreateLpVault),\r\n encU16(args.feeShareBps),\r\n encU64(args.redemptionCooldownSlots),\r\n encU16(args.oiReservationThresholdBps),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\r\n *\r\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\r\n *\r\n * `domain` selects which pot of the vault's asset receives the backing and MUST\r\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\r\n * NAV across both pots, so the depositor is indifferent to the choice; routing\r\n * exists so new money can reach whichever pot the house is drawing on.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\r\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\r\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\r\n * and mint the depositor free shares at existing holders' expense.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\r\n * ```\r\n */\r\nexport function encodeDepositToLpVault(args: {\r\n amount: bigint | string;\r\n domain: number;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositToLpVault),\r\n encU128(args.amount),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\r\n *\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\r\n * v17 uses shares u128 and a two-step request/execute redemption flow.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\r\n * ```\r\n */\r\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\r\n}\r\n\r\n/**\r\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\r\n * available-principal stay COMBINED across both pots, so this does not change\r\n * what the redeemer is owed — only where the atoms come from. A redemption draws\r\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\r\n * cover it; rebalance (tag 91) first.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteRedemption({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\r\n * choice cannot dilute; routing exists so fees can become backing in the pot\r\n * that needs it. The target ledger is created on first use.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\r\n * index 5 is the system program (needed to create a missing target ledger).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeLpVaultCrankFees({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\r\n * the LP vault's asset.\r\n *\r\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\r\n *\r\n * Permissionless: both pots belong to the same vault, so the move cannot extract\r\n * value, and the source-side gate refuses anything that would leave the source\r\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\r\n * open interest, already consumed, or impaired stays put.\r\n *\r\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\r\n * systemProgram]. The destination ledger is created on first arrival.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRebalanceLpVaultBacking({\r\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeRebalanceLpVaultBacking(args: {\r\n fromDomain: number;\r\n toDomain: number;\r\n amount: bigint | string;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RebalanceLpVaultBacking),\r\n encU16(args.fromDomain),\r\n encU16(args.toDomain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\r\n *\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n *\r\n * @param paused 1 = paused, 0 = active.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetLpVaultPaused({ paused: 1 });\r\n * ```\r\n */\r\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\r\n}\r\n\r\n/**\r\n * CloseLpVault (tag 80) — close an empty LP vault.\r\n *\r\n * Wire: tag(1) = 1 byte.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseLpVault();\r\n * ```\r\n */\r\nexport function encodeCloseLpVault(): Uint8Array {\r\n return encU8(IX_TAG.CloseLpVault);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NFT / B-3 (tags 72/73) — kept from v16\r\n// ============================================================================\r\n\r\n/**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n *\r\n * @param newOwner New owner pubkey.\r\n * @param assetIndex Asset/domain index.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTransferPortfolioOwnership({\r\n * newOwner: newOwnerKey,\r\n * assetIndex: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface TransferPortfolioOwnershipArgs {\r\n newOwner: PublicKey | string;\r\n assetIndex: number;\r\n}\r\n\r\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TransferPortfolioOwnership),\r\n encPubkey(args.newOwner),\r\n encU16(args.assetIndex),\r\n );\r\n}\r\n\r\n/**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n *\r\n * @param nftProgramId Pubkey of the percolator-nft program.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\r\n * ```\r\n */\r\nexport interface SetNftProgramIdArgs {\r\n nftProgramId: PublicKey | string;\r\n}\r\n\r\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetNftProgramId),\r\n encPubkey(args.nftProgramId),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\r\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\r\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\r\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\r\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\r\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\r\n *\r\n * Constraints (from v16_program.rs:10419-10435):\r\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\r\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\r\n * - hybrid_soft_stale_slots > 0\r\n * - invert ∈ {0, 1}\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\r\n * @param oracleLegCount Number of active oracle legs (1–3).\r\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\r\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\r\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\r\n * @param markMinFee Minimum fee charged per mark-price update.\r\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\r\n * @param unitScale Unit scaling factor (u32).\r\n * @param confFilterBps Confidence filter in basis points (u16).\r\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureHybridOracle({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * nowUnixTs: 1700000000n,\r\n * oracleLegCount: 1,\r\n * oracleLegFlags: 0,\r\n * maxStalenessSecs: 60n,\r\n * hybridSoftStaleSlots: 100n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * invert: 0,\r\n * unitScale: 1000000,\r\n * confFilterBps: 200,\r\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\r\n * });\r\n * assert(data.length === 156);\r\n * ```\r\n */\r\nexport interface ConfigureHybridOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n nowUnixTs: bigint | string;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n maxStalenessSecs: bigint | string;\r\n hybridSoftStaleSlots: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\r\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\r\n}\r\n\r\nconst ORACLE_LEG_CAP = 3;\r\n\r\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\r\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\r\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\r\n }\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureHybridOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI64(args.nowUnixTs),\r\n encU8(args.oracleLegCount),\r\n encU8(args.oracleLegFlags),\r\n encU64(args.maxStalenessSecs),\r\n encU64(args.hybridSoftStaleSlots),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n encU8(args.invert),\r\n encU32(args.unitScale),\r\n encU16(args.confFilterBps),\r\n encPubkey(args.oracleLegFeeds[0]),\r\n encPubkey(args.oracleLegFeeds[1]),\r\n encPubkey(args.oracleLegFeeds[2]),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\r\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10558-10563):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - mark_ewma_halflife_slots > 0\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\r\n * @param markMinFee Minimum fee charged per mark-price update (u64).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureEwmaMark({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * initialMarkE6: 50000000000n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * });\r\n * assert(data.length === 35);\r\n * ```\r\n */\r\nexport interface ConfigureEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n}\r\n\r\nfunction requirePositiveU64(value: bigint | string, field: string): void {\r\n const n = typeof value === \"string\" ? BigInt(value) : value;\r\n if (n <= 0n) {\r\n throw new Error(`${field} must be > 0`);\r\n }\r\n}\r\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n );\r\n}\r\n\r\n/**\r\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10771):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10665):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface ConfigureAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n}\r\n\r\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n );\r\n}\r\n\r\n/**\r\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10847):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\r\n// ============================================================================\r\n\r\n/**\r\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\r\n * to initialize a passive LP matcher context.\r\n *\r\n * This is NOT a wrapper instruction. Program = matcher program address.\r\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\r\n *\r\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\r\n * [0] = 2 (opcode: passive-LP init)\r\n * [1] = 0 (reserved)\r\n * [2..10] = 0 (8 bytes reserved)\r\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\r\n * [14..34] = 0 (20 bytes reserved)\r\n * [34..50] = max_fill_abs (u128 LE)\r\n * [50..66] = 0 (16 bytes reserved)\r\n * Total = 66 bytes\r\n *\r\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\r\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\r\n *\r\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\r\n * assert(data.length === 66);\r\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\r\n * ```\r\n */\r\nexport interface MatcherInitPassiveArgs {\r\n maxFillAbs: bigint | string;\r\n}\r\n\r\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\r\n const buf = new Uint8Array(66);\r\n buf[0] = 2;\r\n buf[1] = 0;\r\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\r\n const u32Bytes = encU32(100);\r\n buf.set(u32Bytes, 10);\r\n // [34..50] = max_fill_abs u128 LE\r\n const u128Bytes = encU128(args.maxFillAbs);\r\n buf.set(u128Bytes, 34);\r\n return buf;\r\n}\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\r\n// handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\r\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\r\n//\r\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\r\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\r\n// all — sending this encoded data to it would be rejected or misinterpreted.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee instruction data (tag 84).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\r\n * WrapperConfigV17) to an external token account. Signer-gated on\r\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\r\n * clamped to what's actually available on-chain (engine surplus, vault\r\n * balance) and only the actually-transferred amount is marked withdrawn —\r\n * this never errors solely because the ledger raced ahead of availability.\r\n *\r\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\r\n * currently-available capacity.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\r\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawProtocolFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawProtocolFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetProtocolFeeAuthority instruction data (tag 85).\r\n *\r\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\r\n *\r\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\r\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\r\n * marketauth/insurance_authority/any creator-facing gate) — see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\r\n * a keeper script iterates markets for a mass rotation.\r\n *\r\n * @param newAuthority New protocol-fee-authority pubkey.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\r\n * ```\r\n */\r\nexport interface SetProtocolFeeAuthorityArgs {\r\n newAuthority: PublicKey;\r\n}\r\n\r\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetProtocolFeeAuthority),\r\n encPubkey(args.newAuthority),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\r\n *\r\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\r\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\r\n * three stored shares below, which are bps *of T* and must sum to exactly\r\n * `FEE_SHARE_TOTAL_BPS`.\r\n *\r\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\r\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\r\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\r\n * above its ceiling necessarily drags another leg under its floor.\r\n *\r\n * Defaults are written unconditionally at InitMarket and are never instruction\r\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\r\n * legs correctly from its first trade.\r\n */\r\nexport const FEE_SPLIT = {\r\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\r\n PROTOCOL_FEE_BPS: 2000,\r\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\r\n FEE_SHARE_TOTAL_BPS: 8000,\r\n DEFAULT_CREATOR_SHARE_BPS: 1600,\r\n DEFAULT_LP_SHARE_BPS: 4800,\r\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\r\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\r\n MAX_CREATOR_SHARE_BPS: 3600,\r\n /** LP floor, bps of T (40% of the post-protocol remainder). */\r\n MIN_LP_SHARE_BPS: 3200,\r\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\r\n MIN_INSURANCE_SHARE_BPS: 1200,\r\n} as const;\r\nObject.freeze(FEE_SPLIT);\r\n\r\n/**\r\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\r\n * the split would be accepted on-chain, otherwise a human-readable reason.\r\n *\r\n * Provided so a wizard/UI can reject a bad split before paying for a\r\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\r\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\r\n * floors), so this is a convenience, never the security boundary.\r\n *\r\n * @param args The three candidate shares, in bps of T.\r\n * @returns `null` if valid, else a string describing the first violation.\r\n *\r\n * @example\r\n * ```ts\r\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\r\n * // => null (these are the on-chain defaults)\r\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\r\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\r\n * ```\r\n */\r\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\r\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\r\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\r\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\r\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\r\n }\r\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\r\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\r\n }\r\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\r\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\r\n }\r\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\r\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * UpdateFeeSplit instruction data (tag 86).\r\n *\r\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\r\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\r\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\r\n * {@link validateFeeSplit} to check before sending.\r\n *\r\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\r\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\r\n * top-level transaction and this tag is reachable only via the stake program's\r\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\r\n *\r\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\r\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\r\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Restore the on-chain defaults explicitly.\r\n * const data = encodeUpdateFeeSplit({\r\n * creatorShareBps: 1600,\r\n * lpShareBps: 4800,\r\n * insuranceShareBps: 1600,\r\n * });\r\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateFeeSplitArgs {\r\n creatorShareBps: number;\r\n lpShareBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateFeeSplit),\r\n encU16(args.creatorShareBps),\r\n encU16(args.lpShareBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\r\n *\r\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\r\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\r\n * clamped on-chain to engine-available surplus, and the destination is derived\r\n * rather than passed.\r\n *\r\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\r\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\r\n * PINNED stake program id, so there is nothing for a caller to redirect.\r\n *\r\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\r\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\r\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\r\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\r\n * resolution.\r\n *\r\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\r\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\r\n * stake deployment.\r\n *\r\n * @returns 1-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceReserveToStake();\r\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\r\n * ```\r\n */\r\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\r\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\r\n}\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\r\n *\r\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\r\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\r\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\r\n * wrapper rejects the instruction outright.\r\n *\r\n * Gated on `cfg.marketauth`. The wrapper range-checks against\r\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\r\n * exceeded — the same bound InitMarket applies.\r\n *\r\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\r\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\r\n * (maintenance fee disabled).\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\r\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateMaintenanceFeePerSlotArgs {\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateMaintenanceFeePerSlot(\r\n args: UpdateMaintenanceFeePerSlotArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\r\n encU128(args.maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateTradeFeePolicy instruction data (tag 55).\r\n *\r\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\r\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\r\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\r\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\r\n * (stake tag 28).\r\n *\r\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\r\n * with `read_u128`.\r\n *\r\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\r\n * which left stake tag 28's CPI target unrepresentable from the SDK.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\r\n * ```\r\n */\r\nexport interface UpdateTradeFeePolicyArgs {\r\n tradeFeeBaseBps: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateTradeFeePolicy),\r\n encU64(args.tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * ExpireBackingBucket instruction data (tag 89).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\r\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\r\n * domain: read_u16(&mut rest)? }`) followed by the shared\r\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\r\n *\r\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\r\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\r\n * authority to hold.\r\n *\r\n * ## Why this exists\r\n *\r\n * A realized loss reserves capital as counterparty backing, which opens the\r\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\r\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\r\n * END in all three directions, permanently:\r\n *\r\n * - settling a GAIN against it -> Custom(19) EngineStale\r\n * - reserving a further LOSS -> Custom(21) EngineLockActive\r\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\r\n *\r\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\r\n * no call site that reached the engine's own escape hatch\r\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\r\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\r\n * good. Tag 89 IS that missing call site.\r\n *\r\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\r\n *\r\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\r\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\r\n * once when the bucket opens and is never extended. Seeding a long horizon\r\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\r\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\r\n * incident-response tool: a keeper should scan live markets for domains whose\r\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\r\n * nobody cranks it, the first lapse silently bricks the domain and the failure\r\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\r\n * settlement.\r\n *\r\n * ## Safety\r\n *\r\n * Permissionless is not an authority hole. The engine refuses the transition\r\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\r\n * is read from the runtime `Clock` (via\r\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\r\n * — so no caller can force an early forfeiture. Moves no tokens.\r\n *\r\n * Expiry forfeits the lapsed principal to the junior pool. That is the\r\n * engine's documented expiry semantics, not a haircut invented by this\r\n * instruction; the alternative is the account never settling at all.\r\n *\r\n * ## Failure modes\r\n *\r\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\r\n * resolved/wound-down path reaches the transition through the engine's own\r\n * resolved-close sweep, so re-entering it from outside is refused.\r\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\r\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\r\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\r\n * speculatively on a healthy domain is safe (it just reverts).\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short), u16. Must be\r\n * `< 2 * max_market_slots`.\r\n * @returns 3-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\r\n * const data = encodeExpireBackingBucket({ domain: 0 });\r\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\r\n * // beyond the fee payer.\r\n * ```\r\n */\r\nexport interface ExpireBackingBucketArgs {\r\n domain: number;\r\n}\r\n\r\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ExpireBackingBucket),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n//\r\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\r\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\r\n// 576-byte config — see solana/slab.ts).\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee instruction data (tag 90).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\r\n * percolator-prog `src/v16_program.rs`:\r\n *\r\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\r\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\r\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\r\n * -> total length is EXACTLY 17; any trailing byte is rejected\r\n * encode arm: out.push(90); push_u128(&mut out, amount)\r\n *\r\n * Pays the market creator's accrued trade-fee share out of the market vault to\r\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\r\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\r\n * backstop): before this change the creator leg was credited INTO the backstop,\r\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\r\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\r\n * counter.\r\n *\r\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\r\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\r\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\r\n * `parseWrapperConfigV17` and pass that exact value.\r\n *\r\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\r\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\r\n * the whole instruction fails closed (EngineLockActive); retry with less.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\r\n * `cfg.marketauth`), so claiming still works on a staked market where\r\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\r\n *\r\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\r\n * u64, so anything above u64::MAX is an over-claim).\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketAccount.data);\r\n * // Drain the full claimable balance:\r\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\r\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawCreatorFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCreatorFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n","import {\r\n PublicKey,\r\n AccountMeta,\r\n SYSVAR_CLOCK_PUBKEY,\r\n SYSVAR_RENT_PUBKEY,\r\n SystemProgram,\r\n} from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Account spec for building instruction account metas.\r\n * Each instruction has a fixed ordering that matches the Rust processor.\r\n */\r\nexport interface AccountSpec {\r\n name: string;\r\n signer: boolean;\r\n writable: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// ACCOUNT ORDERINGS - Single source of truth\r\n// ============================================================================\r\n\r\n/**\r\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\r\n */\r\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"mint\", signer: false, writable: false },\r\n { name: \"vault\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"dummyAta\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * InitPortfolio (tag 2): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\r\n * [0] owner signer, writable (portfolio owner; pays for alloc)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n *\r\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\r\n * InitPortfolio does not transfer collateral and does not read the clock.\r\n */\r\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * InitLP: 6 accounts\r\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\r\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\r\n * [0] user signer, writable (LP owner; pays fee)\r\n * [1] slab writable\r\n * [2] userAta writable (collateral source for fee)\r\n * [3] vault writable (collateral destination)\r\n * [4] tokenProgram read-only\r\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\r\n */\r\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Deposit (tag 3): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] sourceToken writable (owner's collateral ATA)\r\n * [4] vaultToken writable (program vault token account)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\r\n */\r\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Withdraw (tag 4): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] destToken writable (owner's collateral ATA — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs token CPI)\r\n * [6] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\r\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\r\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\r\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\r\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\r\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\r\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\r\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\r\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\r\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\r\n */\r\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\r\n { name: \"nftRegistry\", signer: false, writable: false },\r\n { name: \"positionNft\", signer: false, writable: false },\r\n { name: \"signerNftAta\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\r\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\r\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\r\n */\r\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\r\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\r\n}\r\n\r\n/**\r\n * KeeperCrank: 4 accounts\r\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\r\n */\r\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\r\n * [0] owner signer, writable (keeper key; receives liquidation reward)\r\n * [1] market writable (the market-group slab)\r\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\r\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\r\n *\r\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\r\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\r\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\r\n * the same program and have a different key from accounts[2].\r\n *\r\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\r\n * including oracle tail and optional keeper portfolio.\r\n */\r\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * RestartAssetOracle (tag 69): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\r\n * [0] authority signer (asset_admin for the target asset_index)\r\n * [1] market writable (the market-group slab)\r\n *\r\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\r\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\r\n * Permissionless in the sense that any holder of asset_admin can call it.\r\n */\r\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n\r\n/**\r\n * TradeNoCpi (tag 9): 5 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\r\n * [0] signerA signer, writable (party A — portfolio owner)\r\n * [1] signerB signer, writable (party B — portfolio owner)\r\n * [2] market writable (market-group slab; program-owned)\r\n * [3] accountA writable (portfolio A; program-owned)\r\n * [4] accountB writable (portfolio B; program-owned)\r\n *\r\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\r\n * signerB replaces lp (both portfolios must have live owner signers).\r\n */\r\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: true },\r\n { name: \"signerB\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LiquidateAtOracle: 4 accounts\r\n * Note: account[0] is unused but must be present\r\n */\r\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\r\n { name: \"unused\", signer: false, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClosePortfolio (tag 8): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\r\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\r\n *\r\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\r\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\r\n * portfolio and closes the account back to the market slab.\r\n */\r\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\r\n * [0] signer signer, writable (insurance authority for asset 0)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\r\n *\r\n * v12 stale accounts removed: clock sysvar (was at [5]).\r\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\r\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\r\n * per-authority deposit principals; omit for simple vault top-ups.\r\n */\r\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\r\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\r\n * omit for a simple top-up with no ledger tracking)\r\n *\r\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\r\n */\r\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority-OWNED token account — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\r\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\r\n * so it stays callable by the creator wallet after the\r\n * launch flow rotates marketauth to the stake-pool PDA)\r\n * [1] market writable (market-group slab; program-owned)\r\n */\r\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\r\n * unlike tag 50 where it is an optional tail)\r\n * [3] destToken writable (authority-OWNED token account — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [6] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\r\n * [0] signerA signer (party A — portfolio owner)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] accountA writable (portfolio A; program-owned)\r\n * [3] accountB writable (portfolio B; program-owned)\r\n * [4] matcherProg read-only, executable (matcher program)\r\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\r\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\r\n * [7+] tail additional accounts forwarded to matcher CPI\r\n *\r\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\r\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\r\n * market replaces slab name.\r\n */\r\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetRiskThreshold: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAdmin: 2 accounts\r\n */\r\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * AcceptAdmin: 2 accounts (tag 82)\r\n * Second half of two-step admin transfer. The proposed new admin must sign to\r\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\r\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\r\n * [1] slab writable\r\n */\r\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\r\n { name: \"pendingAdmin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CloseSlab: 6 accounts\r\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\r\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\r\n * [0] dest signer, writable (receives rent + drained vault tokens)\r\n * [1] slab writable\r\n * [2] vault writable (token account — drained)\r\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\r\n * [4] destAta writable (dest's token ATA receiving drained tokens)\r\n * [5] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"destAta\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\r\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\r\n * 3-account form: [admin(s+w), slab(w), clock].\r\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\r\n * needs to re-read price during config commit). Default to the 3-account form;\r\n * callers that need oracle re-reads should append the oracle account themselves.\r\n */\r\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetMaintenanceFee: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetOraclePriceCap: 3 accounts.\r\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\r\n * Layout: [admin(s+w), slab(w), clock].\r\n */\r\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ResolveMarket (tag 19): 2 accounts.\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\r\n * `handle_resolve_market` at src/v16_program.rs:12269:\r\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\r\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\r\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\r\n * clock account, and never touches an oracle account at all.\r\n *\r\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\r\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\r\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\r\n * also admin-gated, market-level, no token movement — which is\r\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\r\n * when the program does not require it only widens the account's write lock.\r\n */\r\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\r\n * [0] authority signer, writable (insurance authority)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority's collateral ATA — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\r\n *\r\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\r\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\r\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\r\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\r\n * the handler does a same-instruction accrue_market_to against the fresh\r\n * oracle price to prevent withdrawals against overstated insurance.\r\n * On resolved markets the oracle is frozen — 7 accounts suffice.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"authorityAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\r\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UnpauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\r\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\r\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\r\n// (set_insurance_withdraw_policy), 6876 (update_authority).\r\n// ============================================================================\r\n\r\n/**\r\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10470.\r\n */\r\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SettleAccount (tag 26): 3 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10503.\r\n */\r\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\r\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\r\n * Owner only. No token movement (internal PnL-bucket conversion within the\r\n * same portfolio).\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\r\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\r\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\r\n * at src/v16_program.rs:17469, which reads:\r\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\r\n * [1] market writable — `expect_writable` + `expect_owner`\r\n * [2] portfolio writable — `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\r\n * is no clock account (the handler needs no slot) and no oracle account.\r\n *\r\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\r\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\r\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\r\n * portfolio rent — this instruction moves no lamports at all.\r\n *\r\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\r\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\r\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\r\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\r\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\r\n */\r\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\r\n * Wrapper: src/percolator.rs:9990.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\r\n * Wrapper: src/percolator.rs:6876.\r\n *\r\n * Both the current authority and the new authority must sign. For burn\r\n * (`new_pubkey == default()`) the new account is still passed but does\r\n * not need to sign per wrapper L7036 region.\r\n */\r\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"currentAuthority\", signer: true, writable: false },\r\n { name: \"newAuthority\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// ACCOUNT META BUILDERS\r\n// ============================================================================\r\n\r\n/**\r\n * Build AccountMeta array from spec and provided pubkeys.\r\n *\r\n * Accepts either:\r\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\r\n * - `Record` — named map keyed by account `name` (preferred form)\r\n *\r\n * Named-map form resolves accounts by spec name so callers don't have to\r\n * remember the positional order, and errors clearly on missing names.\r\n */\r\nexport function buildAccountMetas(\r\n spec: readonly AccountSpec[],\r\n keys: PublicKey[] | Record\r\n): AccountMeta[] {\r\n let keysArray: PublicKey[];\r\n\r\n if (Array.isArray(keys)) {\r\n keysArray = keys;\r\n } else {\r\n // Named map: resolve by spec name\r\n keysArray = spec.map((s) => {\r\n const key = (keys as Record)[s.name];\r\n if (!key) {\r\n throw new Error(\r\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\r\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\r\n );\r\n }\r\n return key;\r\n });\r\n }\r\n\r\n if (keysArray.length !== spec.length) {\r\n throw new Error(\r\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\r\n );\r\n }\r\n return spec.map((s, i) => ({\r\n pubkey: keysArray[i],\r\n isSigner: s.signer,\r\n isWritable: s.writable,\r\n }));\r\n}\r\n\r\n/**\r\n * CreateInsuranceMint: 9 accounts\r\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\r\n */\r\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"collateralMint\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"payer\", signer: true, writable: true },\r\n] as const;\r\n\r\n/**\r\n * DepositInsuranceLP: 8 accounts\r\n * Deposit collateral into insurance fund, receive LP tokens.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"depositorAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLP: 8 accounts\r\n * Burn LP tokens and withdraw proportional share of insurance fund.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\r\n *\r\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\r\n *\r\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\r\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\r\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\r\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\r\n *\r\n * Accounts:\r\n * [0] withdrawer signer, read-only\r\n * [1] slab writable\r\n * [2] withdrawerAta writable (collateral destination)\r\n * [3] vault writable (collateral source)\r\n * [4] tokenProgram read-only\r\n * [5] lpVaultMint writable (LP tokens burned from here)\r\n * [6] withdrawerLpAta writable (LP tokens source)\r\n * [7] vaultAuthority read-only (PDA that signs token transfers)\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\r\n */\r\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"creatorLockPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * FundMarketInsurance: 5 accounts (PERC-306)\r\n * Fund per-market isolated insurance balance.\r\n */\r\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceIsolation: 2 accounts (PERC-306)\r\n * Set max % of global fund this market can access.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal: 5 accounts (PERC-309)\r\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\r\n */\r\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"lpVaultState\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\r\n * Burns LP tokens and releases one epoch tranche of SOL.\r\n */\r\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\r\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\r\n */\r\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\r\n * Permissionless — surgically close/reduce the most profitable position\r\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\r\n * pass additional oracle accounts at accounts[4..].\r\n */\r\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs: 2 accounts (tag 51)\r\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\r\n */\r\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ReclaimSlabRent: 2 accounts (tag 52)\r\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\r\n */\r\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: true, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// AuditCrank (tag 53) — Permissionless invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank: 1 account (tag 53)\r\n * Permissionless. Verifies conservation invariants; pauses market on violation.\r\n */\r\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase: 1 account\r\n * Permissionless — no signer required beyond fee payer.\r\n */\r\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dexPool\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * CreateLpVault (tag 74): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\r\n * [0] admin signer, writable (marketauth — pays for PDA creation)\r\n * [1] market read-only (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\r\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\r\n * [4] systemProgram read-only (required for create_account CPI)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\r\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\r\n */\r\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositToLpVault (tag 75): 10 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\r\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] lpMint writable (LP share mint PDA)\r\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\r\n * [5] sourceToken writable (depositor's collateral ATA — source)\r\n * [6] vaultToken writable (program vault token account — destination)\r\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\r\n * [8] tokenProgram read-only\r\n * [9] systemProgram read-only (required for ledger create_account CPI)\r\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n *\r\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\r\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\r\n * and mints the depositor free shares at existing holders' expense. `ledger` at\r\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\r\n * which of the two actually receives the backing.\r\n *\r\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\r\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\r\n * ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\r\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n * [5] systemProgram read-only (required to create a missing target ledger)\r\n *\r\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\r\n * land in, and that pot's ledger is created on first use. Once deposits can be\r\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\r\n * so cranker had to become writable and the system program is now required.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\r\n *\r\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\r\n * carrying ledger principal in lockstep. No tokens move.\r\n *\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\r\n * destination ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry read-only (LpVaultRegistry PDA)\r\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\r\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\r\n * [5] systemProgram read-only\r\n */\r\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: false },\r\n { name: \"fromLedger\", signer: false, writable: true },\r\n { name: \"toLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"challenger\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"attestation\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8110: SetOiImbalanceHardBlock\r\n// ============================================================================\r\n\r\n/**\r\n * SetOiImbalanceHardBlock: 2 accounts\r\n * Sets the OI imbalance hard-block threshold (admin only)\r\n */\r\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-608: Position NFT Instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft: 10 accounts\r\n * Creates a Token-2022 position NFT for an open position.\r\n */\r\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TransferPositionOwnership: 8 accounts\r\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\r\n */\r\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\r\n { name: \"currentOwner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"currentOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwner\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * BurnPositionNft: 7 accounts\r\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\r\n */\r\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetPendingSettlement: 3 accounts\r\n * Keeper/admin sets pending_settlement flag before funding transfer.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ClearPendingSettlement: 3 accounts\r\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"nftProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8111: SetWalletCap\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap: 2 accounts\r\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\r\n */\r\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-SetDexPool: SetDexPool (tag 74)\r\n// ============================================================================\r\n\r\n/**\r\n * SetDexPool: 3 accounts\r\n * Admin pins the approved DEX pool address for a HYPERP market.\r\n * After this call, UpdateHyperpMark rejects any pool that does not match.\r\n */\r\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"poolAccount\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// InitMatcherCtx (tag 83) — v17 wire\r\n//\r\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\r\n// 83. The protocol-fee instructions below were renumbered to 84/85\r\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\r\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\r\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\r\n * [0] lpOwner signer (LP portfolio owner wallet)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\r\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\r\n * [4] matcherProg read-only, executable (the external matcher program)\r\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\r\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\r\n * calling the matcher CPI.\r\n *\r\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\r\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\r\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\r\n */\r\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\r\n *\r\n * Fixed accounts:\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned market account)\r\n *\r\n * Dynamic accounts [2..2+oracle_leg_count]:\r\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\r\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\r\n *\r\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\r\n] as const;\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\r\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushEwmaMark (tag 36): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\r\n */\r\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushAuthMark (tag 63): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\r\n */\r\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK B — SetMatcherConfig account spec (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\r\n * 6 accounts when enabling (enabled=1).\r\n *\r\n * [0] lpOwner signer (portfolio owner)\r\n * [1] market read-only (program-owned; owner-check only)\r\n * [2] lpPortfolio writable (program-owned portfolio)\r\n * [3] matcherProg read-only, executable (required when enabled=1 only)\r\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\r\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\r\n *\r\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\r\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\r\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\r\n */\r\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: true },\r\n // When enabled=1, also pass:\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee (tag 84): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\r\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\r\n * in the instruction data means \"withdraw all currently-available capacity\".\r\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\r\n * domain budgets; the protocol's claim is a separate, non-domain balance).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\r\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\r\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\r\n * seeds [program_id])\r\n * [2] market writable (program-owned market-group slab)\r\n *\r\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\r\n * authority — NOT marketauth, NOT insurance_authority, NOT any\r\n * creator-facing gate. No global fan-out: call once per market.\r\n */\r\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"upgradeAuthority\", signer: true, writable: false },\r\n { name: \"programData\", signer: false, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateFeeSplit (tag 86): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\r\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors the neighbouring marketauth-gated single-field setters\r\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\r\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\r\n *\r\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\r\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\r\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\r\n */\r\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_withdraw_insurance_reserve_to_stake):\r\n * [0] cranker signer (permissionless — any signer, pays fees only)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\r\n * wrapper's PINNED stake program id; its owner is\r\n * asserted BEFORE any byte is read — the forgery gate)\r\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\r\n * [4] vaultToken writable (this market's collateral vault token acct)\r\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\r\n * [6] tokenProgram read-only\r\n *\r\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\r\n * destination; percolator-stake's own AccrueFees is what later credits it.\r\n *\r\n * Failure codes are deliberately distinct so a keeper can tell the cases\r\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\r\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\r\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\r\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"stakePool\", signer: false, writable: false },\r\n { name: \"stakeVault\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\r\n * [0] admin signer (must match cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * ⚠ The instruction payload is a u128, not a u64. See\r\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\r\n */\r\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\r\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\r\n * cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\r\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\r\n * than by StakeInitPool; proxy is stake tag 28.\r\n *\r\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\r\n * the authority normally also being the fee payer. The program itself only\r\n * calls `expect_signer(authority)` — it never writes to this account.\r\n */\r\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\r\n * [0] market writable (program-owned market-group slab)\r\n *\r\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\r\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\r\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\r\n * instruction moves no tokens. The transaction still needs a fee payer, but\r\n * that signer is not an account of this instruction and is not checked against\r\n * anything.\r\n *\r\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\r\n * only by an authority that may be a cold key or a stake-pool PDA. The\r\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\r\n * against the runtime `Clock`), not an authority check. See\r\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\r\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\r\n * Custom(19) bucket not `Fresh`-and-lapsed.\r\n */\r\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee (tag 90): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\r\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\r\n * only the authority the program checks [0] against differs:\r\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account, owned by [0])\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\r\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\r\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\r\n * reflects the authority normally also being the transaction fee payer; the\r\n * program itself only calls expect_signer on it.\r\n *\r\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\r\n * does NOT accept marketauth as an alternate the way\r\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\r\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\r\n * pool claim the creator's revenue. It also means claiming keeps working after\r\n * StakeInitPool, since staking never rotates insurance_operator.\r\n *\r\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\r\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\r\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\r\n * from the loss backstop, so backstop gating does not apply).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\r\n// ============================================================================\r\n\r\nexport const WELL_KNOWN = {\r\n tokenProgram: TOKEN_PROGRAM_ID,\r\n clock: SYSVAR_CLOCK_PUBKEY,\r\n rent: SYSVAR_RENT_PUBKEY,\r\n systemProgram: SystemProgram.programId,\r\n} as const;\r\n","/**\r\n * Percolator v17 program error definitions.\r\n *\r\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\r\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\r\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\r\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\r\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\r\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\r\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\r\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\r\n *\r\n * Ordinals 0-61 read directly off the PercolatorError enum in\r\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\r\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\r\n * tentative\" TODO here is resolved.\r\n *\r\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\r\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Errors 0-29 have completely different names and semantics from v12.\r\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\r\n * - Errors 42-46 are NFT/B-3 (new in v17).\r\n * - v12.x errors 28-65 are entirely removed.\r\n */\r\nexport interface ErrorInfo {\r\n name: string;\r\n hint: string;\r\n}\r\n\r\nexport const PERCOLATOR_ERRORS: Record = {\r\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\r\n 0: {\r\n name: \"InvalidMagic\",\r\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\r\n },\r\n 1: {\r\n name: \"InvalidVersion\",\r\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\r\n },\r\n 2: {\r\n name: \"AlreadyInitialized\",\r\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\r\n },\r\n 3: {\r\n name: \"NotInitialized\",\r\n hint: \"Account is not initialized. Run InitMarket first.\",\r\n },\r\n 4: {\r\n name: \"InvalidAccountKind\",\r\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\r\n },\r\n 5: {\r\n name: \"InvalidAccountLen\",\r\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\r\n },\r\n 6: {\r\n name: \"ExpectedSigner\",\r\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\r\n },\r\n 7: {\r\n name: \"ExpectedWritable\",\r\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\r\n },\r\n 8: {\r\n name: \"Unauthorized\",\r\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\r\n },\r\n 9: {\r\n name: \"InvalidInstruction\",\r\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\r\n },\r\n 10: {\r\n name: \"InvalidMint\",\r\n hint: \"Token mint does not match the market's collateral mint.\",\r\n },\r\n 11: {\r\n name: \"InvalidTokenAccount\",\r\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\r\n },\r\n 12: {\r\n name: \"InvalidVaultAccount\",\r\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\r\n },\r\n 13: {\r\n name: \"InvalidTokenProgram\",\r\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\r\n },\r\n 14: {\r\n name: \"EngineInvalidConfig\",\r\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\r\n },\r\n 15: {\r\n name: \"EngineArithmeticOverflow\",\r\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\r\n },\r\n 16: {\r\n name: \"EngineProvenanceMismatch\",\r\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\r\n },\r\n 17: {\r\n name: \"EngineHiddenLeg\",\r\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\r\n },\r\n 18: {\r\n name: \"EngineInvalidLeg\",\r\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\r\n },\r\n 19: {\r\n name: \"EngineStale\",\r\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\r\n },\r\n 20: {\r\n name: \"EngineBStale\",\r\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\r\n },\r\n 21: {\r\n name: \"EngineLockActive\",\r\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\r\n },\r\n 22: {\r\n name: \"EngineNonProgress\",\r\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\r\n },\r\n 23: {\r\n name: \"EngineRecoveryRequired\",\r\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\r\n },\r\n 24: {\r\n name: \"EngineCounterOverflow\",\r\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\r\n },\r\n 25: {\r\n name: \"EngineCounterUnderflow\",\r\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\r\n },\r\n 26: {\r\n name: \"OracleInvalid\",\r\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\r\n },\r\n 27: {\r\n name: \"OracleStale\",\r\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\r\n },\r\n 28: {\r\n name: \"OracleConfTooWide\",\r\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\r\n },\r\n 29: {\r\n name: \"InvalidOracleKey\",\r\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\r\n },\r\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\r\n 30: {\r\n name: \"LpVaultAlreadyExists\",\r\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\r\n },\r\n 31: {\r\n name: \"LpVaultNotFound\",\r\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\r\n },\r\n 32: {\r\n name: \"LpVaultPaused\",\r\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\r\n },\r\n 33: {\r\n name: \"LpVaultSharesOutstanding\",\r\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\r\n },\r\n 34: {\r\n name: \"LpVaultZeroAmount\",\r\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\r\n },\r\n 35: {\r\n name: \"LpVaultInsufficientShares\",\r\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\r\n },\r\n 36: {\r\n name: \"LpVaultCooldownActive\",\r\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\r\n },\r\n 37: {\r\n name: \"LpVaultOiReservationViolated\",\r\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\r\n },\r\n 38: {\r\n name: \"LpVaultNoFeesToCrank\",\r\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\r\n },\r\n 39: {\r\n name: \"LpVaultSupplyMismatch\",\r\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\r\n },\r\n 40: {\r\n name: \"LpVaultAuthorityMismatch\",\r\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\r\n },\r\n 41: {\r\n name: \"LpVaultZeroSharesMinted\",\r\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\r\n },\r\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\r\n 42: {\r\n name: \"NftRegistryNotFound\",\r\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\r\n },\r\n 43: {\r\n name: \"NftPortfolioNotTransferable\",\r\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\r\n },\r\n 44: {\r\n name: \"NftTransferSelfOrZero\",\r\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\r\n },\r\n 45: {\r\n name: \"NftInvalidMintAuthority\",\r\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\r\n },\r\n 46: {\r\n name: \"NftPortfolioProvenance\",\r\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\r\n },\r\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\r\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\r\n 47: {\r\n name: \"InsuranceWithdrawCooldownActive\",\r\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\r\n },\r\n 48: {\r\n name: \"InsuranceWithdrawCeilingExceeded\",\r\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\r\n },\r\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\r\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\r\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\r\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\r\n // initial-margin failure, previously collapsed into the opaque\r\n // EngineInvalidConfig=14.\r\n 49: {\r\n name: \"EngineInsufficientInitialMargin\",\r\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\r\n },\r\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\r\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\r\n 50: {\r\n name: \"LpVaultDepositBelowMinimumLiquidity\",\r\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\r\n },\r\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\r\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\r\n // a3cb4390).\r\n //\r\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\r\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\r\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\r\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\r\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\r\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\r\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\r\n // EXACTLY and with no tolerance, against the bps floors below.\r\n 51: {\r\n name: \"FeeSplitFloorViolation\",\r\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\r\n },\r\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variants appended after\r\n // FeeSplitFloorViolation=51 on percolator-prog\r\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\r\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\r\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\r\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\r\n 52: {\r\n name: \"FeeSplitSumInvalid\",\r\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\r\n },\r\n 53: {\r\n name: \"NoInsuranceReserveToClaim\",\r\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\r\n },\r\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\r\n // Source: v16_program.rs, same branch. These seven previously ALL returned\r\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\r\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\r\n // destination-resolution now has its own code.\r\n //\r\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\r\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\r\n // removed. That variant existed only on an unmerged branch and was NEVER\r\n // deployed, so no on-chain consumer has ever observed the old meaning.\r\n 54: {\r\n name: \"StakePoolNotBound\",\r\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\r\n },\r\n 55: {\r\n name: \"StakePoolOwnerMismatch\",\r\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\r\n },\r\n 56: {\r\n name: \"StakePoolAuthorityMismatch\",\r\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\r\n },\r\n 57: {\r\n name: \"StakePoolMarketMismatch\",\r\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\r\n },\r\n 58: {\r\n name: \"StakePoolWrapperMismatch\",\r\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\r\n },\r\n 59: {\r\n name: \"StakePoolModeMismatch\",\r\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\r\n },\r\n 60: {\r\n name: \"StakeProgramNotPinned\",\r\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\r\n },\r\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\r\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n 61: {\r\n name: \"AssetSlotAlreadyConfigured\",\r\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\r\n },\r\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\r\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\r\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\r\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\r\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\r\n // wrapper this code is unreachable.\r\n 62: {\r\n name: \"CreatorFeeOverClaim\",\r\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\r\n },\r\n\r\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\r\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\r\n // slot 490057417, verified byte-identical.\r\n 63: {\r\n name: \"LpVaultBackingBucketNotEmpty\",\r\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\r\n },\r\n};\r\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\r\nObject.freeze(PERCOLATOR_ERRORS);\r\n\r\n/**\r\n * Decode a custom program error code to its info.\r\n *\r\n * @param code Custom error code from `custom program error: 0x`.\r\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\r\n */\r\nexport function decodeError(code: number): ErrorInfo | undefined {\r\n return PERCOLATOR_ERRORS[code];\r\n}\r\n\r\n/**\r\n * Get error name from code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\r\n */\r\nexport function getErrorName(code: number): string {\r\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\r\n}\r\n\r\n/**\r\n * Get actionable hint for error code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Actionable hint string, or undefined if not recognized.\r\n */\r\nexport function getErrorHint(code: number): string | undefined {\r\n return PERCOLATOR_ERRORS[code]?.hint;\r\n}\r\n\r\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\r\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\r\n\r\n/**\r\n * Parse a custom program error from transaction logs.\r\n *\r\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\r\n * Returns null if no custom error is found.\r\n *\r\n * @param logs Array of transaction log strings from the RPC response.\r\n * @returns Parsed error with code, name, and hint — or null if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\r\n * if (err) console.error(`${err.name}: ${err.hint}`);\r\n * ```\r\n */\r\nexport function parseErrorFromLogs(logs: string[]): {\r\n code: number;\r\n name: string;\r\n hint?: string;\r\n} | null {\r\n if (!Array.isArray(logs)) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\r\n \"i\",\r\n );\r\n for (const log of logs) {\r\n if (typeof log !== \"string\") {\r\n continue;\r\n }\r\n const match = log.match(re);\r\n if (match) {\r\n const code = parseInt(match[1], 16);\r\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\r\n continue;\r\n }\r\n const info = decodeError(code);\r\n return {\r\n code,\r\n name: info?.name ?? `Unknown(${code})`,\r\n hint: info?.hint,\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Standalone percolator-nft program SDK module.\r\n *\r\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\r\n * separate from the main Percolator program. It handles:\r\n * - MintPositionNft (tag 0)\r\n * - BurnPositionNft (tag 1)\r\n * - SettleFunding (tag 2)\r\n * - GetPositionValue (tag 3)\r\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\r\n * - EmergencyBurn (tag 5)\r\n * - RepairExtraMetas (tag 6)\r\n * - ReconcileBurnedNft (tag 7)\r\n *\r\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\r\n * PositionNft state : [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n * Mint authority : [\"mint_authority\"]\r\n *\r\n * NOTE: the PositionNft seed is keyed on `market_id`, NOT `asset_index` — see\r\n * #108 and `deriveNftPda` below. This header claimed `asset_index_u16_LE` until\r\n * 2026-08-31; the code was always correct.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\r\nimport { safeEnv } from \"../config/program-ids.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Program ID\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Allowlist of known NFT program addresses. */\r\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\r\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\r\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\r\n]);\r\n\r\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\r\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\r\n throw new Error(\r\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\r\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\r\n `Pass the programId argument explicitly to bypass env resolution.`,\r\n );\r\n}\r\n\r\n/**\r\n * The standalone percolator-nft program (TransferHook + mint authority).\r\n *\r\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\r\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\r\n * address while every other id in the SDK is devnet, so any consumer importing it built\r\n * transactions against a program that does not exist on devnet and failed late with\r\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\r\n * constant to work around it.\r\n */\r\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\r\n\r\nexport function getNftProgramId(): PublicKey {\r\n return NFT_PROGRAM_ID;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const NFT_IX_TAG = {\r\n MintPositionNft: 0,\r\n BurnPositionNft: 1,\r\n SettleFunding: 2,\r\n GetPositionValue: 3,\r\n ExecuteTransferHook: 4,\r\n EmergencyBurn: 5,\r\n RepairExtraMetas: 6,\r\n ReconcileBurnedNft: 7,\r\n} as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction encoders\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\r\nexport function encodeNftMint(assetIndex: number): Uint8Array {\r\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\r\n const buf = new Uint8Array(3);\r\n buf[0] = NFT_IX_TAG.MintPositionNft;\r\n buf.set(assetIndexBuf, 1);\r\n return buf;\r\n}\r\n\r\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\r\nexport function encodeNftBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\r\n}\r\n\r\n/** Encode SettleFunding (tag 2). Data: tag(1). */\r\nexport function encodeNftSettleFunding(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\r\n}\r\n\r\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\r\nexport function encodeNftEmergencyBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\r\n}\r\n\r\n/**\r\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\r\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\r\n * released) back to the recorded last holder, then closes the PositionNft PDA.\r\n */\r\nexport function encodeNftReconcile(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account meta templates\r\n// ---------------------------------------------------------------------------\r\n\r\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\r\n\r\n/**\r\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\r\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\r\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\r\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\r\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\r\n * `isSigner: undefined` and `isWritable: undefined` for every account\r\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\r\n * both to falsy, so EVERY account in the built instruction ends up\r\n * non-signer/read-only. The NFT program's own writable/signer checks then\r\n * reject the transaction (confirmed live against the deployed NFT program:\r\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\r\n * CPI — matching its `if !nft_pda.is_writable { return\r\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\r\n *\r\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\r\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\r\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\r\n * these arrays and working — the only prior working reference\r\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\r\n * bypassing the mismatch entirely.\r\n */\r\nexport function buildNftAccountMetas(\r\n spec: readonly AccountMeta[],\r\n keys: readonly PublicKey[],\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n if (keys.length !== spec.length) {\r\n throw new Error(\r\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\r\n );\r\n }\r\n return spec.map((code, i) => ({\r\n pubkey: keys[i],\r\n isSigner: code === \"s\" || code === \"sw\",\r\n isWritable: code === \"w\" || code === \"sw\",\r\n }));\r\n}\r\n\r\n/**\r\n * Account metas for MintPositionNft (tag 0). 12 accounts.\r\n *\r\n * 0. [signer, writable] payer / position owner\r\n * 1. [writable] PositionNft PDA (created)\r\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\r\n * 3. [writable] Owner's NFT ATA (created)\r\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [] Associated token account program\r\n * 8. [] System program\r\n * 9. [writable] ExtraAccountMetaList PDA\r\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\r\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\r\n *\r\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\r\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\r\n * writable and #10/#11 are required.\r\n */\r\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\r\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint,\r\n * PositionNft PDA and ExtraAccountMetaList rent)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint (supply → 0)\r\n * 3. [writable] Holder's NFT ATA (closed)\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n *\r\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\r\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\r\n */\r\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint\r\n * 3. [writable] Holder's NFT ATA\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n */\r\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for ReconcileBurnedNft (tag 7, #138). 9 accounts. Permissionless.\r\n *\r\n * 0. [writable] PositionNft PDA (closed)\r\n * 1. [writable] NFT mint (Token-2022 — supply must be 0; closed, #182)\r\n * 2. [writable] Portfolio account (escrow released to the last holder)\r\n * 3. [] Mint authority PDA (unwrap + mint-close CPI signer)\r\n * 4. [] Per-market NftRegistry PDA\r\n * 5. [] Percolator wrapper program (unwrap CPI target)\r\n * 6. [writable] Recorded last-holder wallet (escrow + all rent recipient)\r\n * 7. [writable] ExtraAccountMetaList PDA (closed, #182)\r\n * 8. [] Token-2022 program (mint-close CPI target, #182)\r\n *\r\n * dcccrypto/percolator-nft#182: Reconcile previously abandoned the NFT mint and\r\n * the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable,\r\n * because it closes the PositionNft PDA and every path that could later reclaim\r\n * those two requires it to still be live. Accounts 7 and 8 are REQUIRED rather\r\n * than optional: Reconcile is permissionless, irreversible and runs at most\r\n * once, so an opt-in could be defeated permanently by whoever called first.\r\n *\r\n * Forward-compatible with the currently deployed programs: their handler pulls\r\n * seven accounts off an iterator and never checks `accounts.len()`, so the two\r\n * extra metas are simply unread, and it never checks `nft_mint.is_writable`.\r\n * A nine-account call therefore behaves identically on both, which is why this\r\n * can ship ahead of the program change rather than behind it.\r\n */\r\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\r\n \"w\", \"w\", \"w\", \"r\", \"r\", \"r\", \"w\", \"w\", \"r\",\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// PDA derivation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\nfunction u16Buf(value: number, label: string): Uint8Array {\r\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\r\n throw new Error(`${label} must be a u16`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, true);\r\n return buf;\r\n}\r\n\r\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\r\n const v = typeof value === \"bigint\" ? value : BigInt(value);\r\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\r\n throw new Error(`${label} must be a u64`);\r\n }\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, v, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive the PositionNft state PDA.\r\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n *\r\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\r\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\r\n * engine reuses across close/re-open of the same asset and which therefore\r\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\r\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\r\n * NFT's stored `marketIdAtMint` for any later op.\r\n */\r\nexport function deriveNftPda(\r\n portfolioAccount: PublicKey,\r\n marketId: bigint | number,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\r\n programId,\r\n );\r\n}\r\n\r\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\r\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\r\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\r\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\r\n\r\n/**\r\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\r\n */\r\nexport function deriveNftMint(\r\n _portfolioAccount: PublicKey,\r\n _assetIndex: number,\r\n _programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\r\n}\r\n\r\n/**\r\n * Derive the program-wide mint authority PDA.\r\n * Seeds: [\"mint_authority\"]\r\n */\r\nexport function deriveMintAuthority(\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"mint_authority\")],\r\n programId,\r\n );\r\n}\r\n\r\n/**\r\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\r\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\r\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\r\n * close it and refund its rent to the holder.\r\n */\r\nexport function deriveExtraAccountMetas(\r\n nftMint: PublicKey,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\r\n programId,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account parser\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\r\n *\r\n * [0..8] magic u64 (\"PERCNFT\\0\")\r\n * [8] version u8\r\n * [9] bump u8\r\n * [10..42] portfolio_account [u8; 32]\r\n * [42..74] nft_mint [u8; 32]\r\n * [74..78] asset_index u32 LE\r\n * [78] side_at_mint u8\r\n * [79..95] basis_pos_q_at_mint i128\r\n * [95..111] f_snap_at_mint i128\r\n * [111..119] market_id_at_mint u64\r\n * [119..127] epoch_snap_at_mint u64\r\n * [127..159] position_owner_at_mint [u8; 32]\r\n * [159..167] minted_at i64\r\n * [167..199] _reserved\r\n */\r\nexport const POSITION_NFT_STATE_LEN = 199;\r\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\r\nconst POSITION_NFT_VERSION = 2;\r\n\r\nexport interface PositionNftState {\r\n version: number;\r\n bump: number;\r\n portfolioAccount: PublicKey;\r\n nftMint: PublicKey;\r\n assetIndex: number;\r\n sideAtMint: number;\r\n basisPosQAtMint: bigint;\r\n fSnapAtMint: bigint;\r\n marketIdAtMint: bigint;\r\n epochSnapAtMint: bigint;\r\n positionOwnerAtMint: PublicKey;\r\n /** Backward-compatible alias for positionOwnerAtMint. */\r\n positionOwner: PublicKey;\r\n mintedAt: bigint;\r\n}\r\n\r\n/**\r\n * Read a little-endian signed i128 from a DataView at `offset`.\r\n *\r\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\r\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\r\n * value is set the result is negative and two's-complement sign extension is\r\n * applied explicitly.\r\n *\r\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\r\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\r\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\r\n * shifted high half collapses the sign bit into all high bits and corrupts the\r\n * result.\r\n *\r\n * @param view DataView wrapping the raw account bytes\r\n * @param offset Byte offset of the i128 field (little-endian)\r\n * @returns Signed BigInt in the range [-2^127, 2^127)\r\n */\r\nfunction readI128FromView(view: DataView, offset: number): bigint {\r\n const lo = view.getBigUint64(offset, true);\r\n const hi = view.getBigUint64(offset + 8, true);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Parse a PositionNft account from raw bytes.\r\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\r\n */\r\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\r\n if (data.length < POSITION_NFT_STATE_LEN) {\r\n throw new Error(\r\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\r\n );\r\n }\r\n\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n const magic = view.getBigUint64(0, true);\r\n if (magic !== POSITION_NFT_MAGIC) {\r\n throw new Error(\"PositionNft account has invalid magic\");\r\n }\r\n if (data[8] !== POSITION_NFT_VERSION) {\r\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\r\n }\r\n\r\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\r\n\r\n return {\r\n version: data[8],\r\n bump: data[9],\r\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\r\n nftMint: new PublicKey(data.subarray(42, 74)),\r\n assetIndex: view.getUint32(74, true),\r\n sideAtMint: data[78],\r\n basisPosQAtMint: readI128FromView(view, 79),\r\n fSnapAtMint: readI128FromView(view, 95),\r\n marketIdAtMint: view.getBigUint64(111, true),\r\n epochSnapAtMint: view.getBigUint64(119, true),\r\n positionOwnerAtMint,\r\n positionOwner: positionOwnerAtMint,\r\n mintedAt: view.getBigInt64(159, true),\r\n };\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\n/**\r\n * Read an environment variable safely. Returns `undefined` in browser\r\n * environments where `process` is not defined, avoiding a\r\n * `ReferenceError` crash at import time.\r\n */\r\nexport function safeEnv(key: string): string | undefined {\r\n try {\r\n return typeof process !== \"undefined\" && process?.env\r\n ? process.env[key]\r\n : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Centralized PROGRAM_ID configuration\r\n * \r\n * Default to environment variable, then fall back to network-specific defaults.\r\n * This prevents hard-coded program IDs scattered across the codebase.\r\n */\r\n\r\nexport const PROGRAM_IDS = {\r\n devnet: {\r\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\r\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\r\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n },\r\n mainnet: {\r\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\r\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\r\n },\r\n} as const;\r\nObject.freeze(PROGRAM_IDS.devnet);\r\nObject.freeze(PROGRAM_IDS.mainnet);\r\nObject.freeze(PROGRAM_IDS);\r\n\r\n/**\r\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\r\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\r\n * and upgraded in place at the same address).\r\n *\r\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\r\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\r\n * markets — they were not migrated in place, so anything still pointed at them\r\n * (e.g. the percolator-launch playground config, which hardcodes its own program\r\n * ID rather than reading this module) keeps working against the old markets until\r\n * it is explicitly cut over to this fresh triple. That playground cutover is a\r\n * separate, later step — NOT performed by this change.\r\n */\r\nexport const PROGRAM_IDS_V17 = {\r\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\r\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\r\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\r\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\r\n} as const;\r\nObject.freeze(PROGRAM_IDS_V17);\r\n\r\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\r\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\r\n\r\nexport type Network = \"devnet\" | \"mainnet\";\r\n\r\n/** Allowlist of legitimate percolator program addresses (all networks). */\r\nconst KNOWN_PROGRAM_IDS = new Set([\r\n PROGRAM_IDS.devnet.percolator,\r\n PROGRAM_IDS.mainnet.percolator,\r\n PROGRAM_IDS_V17.percolator,\r\n]);\r\n\r\n/** Allowlist of legitimate matcher program addresses (all networks). */\r\nconst KNOWN_MATCHER_IDS = new Set([\r\n PROGRAM_IDS.devnet.matcher,\r\n PROGRAM_IDS.mainnet.matcher,\r\n]);\r\n\r\n/**\r\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\r\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\r\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\r\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\r\n * during pre-deploy / devnet testing — which the allowlist alone would break.\r\n */\r\nfunction programOverrideOptIn(): boolean {\r\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\r\n}\r\n\r\n/**\r\n * Get the Percolator program ID for the current network\r\n * \r\n * Priority:\r\n * 1. PROGRAM_ID env var (explicit override)\r\n * 2. Network-specific default (NETWORK env var)\r\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\r\n */\r\nexport function getProgramId(network?: Network): PublicKey {\r\n // #249: an explicit `network` argument is authoritative and must NOT be silently\r\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\r\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\r\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\r\n if (network === undefined) {\r\n const override = safeEnv(\"PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\r\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].percolator;\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the Matcher program ID for the current network\r\n */\r\nexport function getMatcherProgramId(network?: Network): PublicKey {\r\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\r\n if (network === undefined) {\r\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\r\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].matcher;\r\n\r\n if (!programId) {\r\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\r\n }\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the current network from environment.\r\n *\r\n * SECURITY (PERC-697): Removed silent mainnet default.\r\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\r\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\r\n *\r\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\r\n * Production deployments always set NETWORK explicitly via Railway/env.\r\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\r\n * enforces FORCE_MAINNET=1.\r\n */\r\nexport function getCurrentNetwork(): Network {\r\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\r\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\r\n return \"mainnet\";\r\n }\r\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\r\n return \"devnet\";\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\n\r\n// =============================================================================\r\n// Browser-compatible read helpers using DataView\r\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\r\n// =============================================================================\r\n\r\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\n/** Read a single unsigned byte at `off`. */\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n if (off >= data.length) {\r\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\r\n }\r\n return data[off];\r\n}\r\n/** Read a little-endian u16 at `off`. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\n/** Read a little-endian u32 at `off`. */\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint32(off, true);\r\n}\r\n/** Read a little-endian u64 at `off` as a BigInt. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\n/** Read a little-endian signed i64 at `off` as a BigInt. */\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\n\r\n// =============================================================================\r\n// Helper: read signed/unsigned i128 from buffer\r\n// =============================================================================\r\n\r\n/**\r\n * Read a little-endian signed i128 at `offset`.\r\n * Composed from two u64 halves; sign-extends if the high bit is set.\r\n */\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// =============================================================================\r\n// Slab Layout Version Detection\r\n// =============================================================================\r\n// The deployed devnet program uses a different struct layout (V0) than the SDK\r\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\r\n// struct changes that have NOT been deployed to devnet yet.\r\n//\r\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\r\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\r\n// - RiskParams: 56 bytes (basic fields only)\r\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\r\n// - No partial liquidation field in Account (240 bytes)\r\n//\r\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\r\n// - InsuranceFund: expanded with isolation fields (72 bytes)\r\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\r\n// - Has mark_price, long_oi/short_oi, emergency fields\r\n// - Account has last_partial_liquidation_slot (248 bytes)\r\n// =============================================================================\r\n\r\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\r\n\r\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\r\nexport const SLAB_MAGIC = MAGIC;\r\n\r\n// Flag bits in header._padding[0] at offset 13\r\nconst FLAG_RESOLVED = 1 << 0;\r\n\r\n/**\r\n * Full slab layout descriptor. Returned by detectSlabLayout().\r\n * All engine field offsets are relative to engineOff.\r\n */\r\nexport interface SlabLayout {\r\n version: 0 | 1 | 2;\r\n headerLen: number;\r\n configOffset: number;\r\n configLen: number;\r\n reservedOff: number; // offset of _reserved in header\r\n engineOff: number;\r\n accountSize: number;\r\n maxAccounts: number;\r\n bitmapWords: number;\r\n accountsOff: number; // absolute offset of accounts array in slab\r\n\r\n // Engine field offsets (relative to engineOff)\r\n engineInsuranceOff: number;\r\n engineParamsOff: number;\r\n paramsSize: number;\r\n engineCurrentSlotOff: number;\r\n engineFundingIndexOff: number;\r\n engineLastFundingSlotOff: number;\r\n engineFundingRateBpsOff: number;\r\n engineMarkPriceOff: number; // -1 if not present (V0)\r\n engineLastCrankSlotOff: number;\r\n engineMaxCrankStalenessOff: number;\r\n engineTotalOiOff: number;\r\n engineLongOiOff: number; // -1 if not present (V0)\r\n engineShortOiOff: number; // -1 if not present (V0)\r\n engineCTotOff: number;\r\n enginePnlPosTotOff: number;\r\n engineLiqCursorOff: number;\r\n engineGcCursorOff: number;\r\n engineLastSweepStartOff: number;\r\n engineLastSweepCompleteOff: number;\r\n engineCrankCursorOff: number;\r\n engineSweepStartIdxOff: number;\r\n engineLifetimeLiquidationsOff: number;\r\n engineLifetimeForceClosesOff: number;\r\n engineNetLpPosOff: number;\r\n engineLpSumAbsOff: number;\r\n engineLpMaxAbsOff: number;\r\n engineLpMaxAbsSweepOff: number;\r\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\r\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\r\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\r\n engineBitmapOff: number; // relative to engineOff\r\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\r\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\r\n\r\n // Insurance fund layout\r\n hasInsuranceIsolation: boolean;\r\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\r\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\r\n\r\n // Optional fallback for engines without a stored mark_price field (v12.17+):\r\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\r\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\r\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\r\n // predate v12.17 and already expose a real engine.mark_price.\r\n configMarkEwmaOff?: number;\r\n}\r\n\r\n// ---- V0 layout constants (deployed devnet program) ----\r\nconst V0_HEADER_LEN = 72;\r\nconst V0_CONFIG_LEN = 408;\r\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\r\nconst V0_ACCOUNT_SIZE = 240;\r\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\r\n\r\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\r\n// V0 RiskParams: 56 bytes → runtime state at 104\r\nconst V0_ENGINE_PARAMS_OFF = 48;\r\nconst V0_PARAMS_SIZE = 56;\r\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\r\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\r\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\r\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\r\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\r\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\r\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\r\nconst V0_ENGINE_C_TOT_OFF = 176;\r\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\r\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\r\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\r\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\r\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\r\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\r\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\r\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\r\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\r\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\r\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\r\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\r\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\r\nconst V0_ENGINE_BITMAP_OFF = 320;\r\n\r\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\r\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\r\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\r\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\r\nconst V1_HEADER_LEN = 104;\r\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\r\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\r\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\r\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\r\nconst V1_ENGINE_OFF_LEGACY = 640;\r\nconst V1_ACCOUNT_SIZE = 248;\r\nconst V1_RESERVED_OFF = 80;\r\n\r\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\r\n// V1 RiskParams: 288 bytes → runtime state at 360\r\nconst V1_ENGINE_PARAMS_OFF = 72;\r\nconst V1_PARAMS_SIZE = 288;\r\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\r\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\r\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\r\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\r\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\r\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\r\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\r\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\r\nconst V1_ENGINE_LONG_OI_OFF = 456;\r\nconst V1_ENGINE_SHORT_OI_OFF = 472;\r\nconst V1_ENGINE_C_TOT_OFF = 488;\r\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\r\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\r\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\r\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\r\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\r\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\r\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\r\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\r\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\r\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\r\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\r\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\r\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\r\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\r\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\r\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\r\nconst V1_ENGINE_BITMAP_OFF = 656;\r\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\r\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\r\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\r\n// These corrected values must be used for actual byte-level parsing.\r\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\r\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\r\n\r\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\r\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\r\n// Key differences:\r\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\r\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\r\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\r\n// - Bitmap at engine+624 (not 656)\r\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\r\nconst V1D_CONFIG_LEN = 320;\r\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\r\nconst V1D_ACCOUNT_SIZE = 248;\r\n\r\n// V1D engine field offsets (relative to engineOff):\r\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\r\nconst V1D_ENGINE_INSURANCE_OFF = 16;\r\nconst V1D_ENGINE_PARAMS_OFF = 96;\r\nconst V1D_PARAMS_SIZE = 288;\r\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\r\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\r\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\r\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\r\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\r\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\r\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\r\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\r\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\r\nconst V1D_ENGINE_LONG_OI_OFF = 480;\r\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\r\nconst V1D_ENGINE_C_TOT_OFF = 512;\r\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\r\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\r\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\r\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\r\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\r\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\r\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\r\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\r\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\r\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\r\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\r\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\r\nconst V1D_ENGINE_BITMAP_OFF = 624;\r\n\r\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\r\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\r\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\r\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\r\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\r\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\r\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\r\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\r\nconst V2_HEADER_LEN = 104;\r\nconst V2_CONFIG_LEN = 496;\r\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\r\nconst V2_ACCOUNT_SIZE = 248;\r\nconst V2_ENGINE_BITMAP_OFF = 432;\r\n\r\n// V2 engine field offsets (relative to engineOff)\r\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\r\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\r\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\r\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\r\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\r\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\r\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\r\nconst V2_ENGINE_C_TOT_OFF = 424;\r\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\r\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\r\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\r\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\r\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\r\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\r\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\r\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\r\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\r\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\r\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\r\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\r\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\r\n\r\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\r\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\r\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\r\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\r\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\r\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\r\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\r\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\r\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\r\n//\r\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\r\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\r\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\r\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\r\n// Prior value of 1006 was an arithmetic transcription error.\r\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\r\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\r\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\r\n\r\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\r\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\r\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\r\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\r\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\r\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\r\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\r\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\r\n\r\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\r\nconst V_ADL_PARAMS_SIZE = 336;\r\n\r\n// V_ADL engine field offsets (relative to engineOff=624):\r\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\r\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\r\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\r\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\r\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\r\n// PERC-8270 new fields at 472-504:\r\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\r\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\r\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\r\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\r\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\r\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\r\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\r\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\r\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\r\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\r\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\r\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\r\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\r\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\r\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\r\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\r\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\r\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\r\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\r\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\r\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\r\n// ADL side state (PERC-8268, 224 bytes):\r\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\r\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\r\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\r\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\r\n// Then LP aggregates:\r\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\r\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\r\n// emergency fields:\r\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\r\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\r\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\r\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\r\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\r\n\r\n// V_ADL account field offsets (relative to account slot start):\r\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\r\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\r\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\r\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\r\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\r\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\r\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\r\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\r\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\r\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\r\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\r\n\r\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\r\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\r\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\r\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\r\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\r\n// dynamic fee tiers, fee splits).\r\n// Engine field ordering completely reorganized from V_ADL.\r\n// All values verified by cargo build-sbf compile-time assertions.\r\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\r\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\r\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\r\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\r\n// Those fields exist in percolator-core but NOT in the deployed binary.\r\n//\r\n// HOST constants below are for aarch64 test builds (percolator-core).\r\n// SBF constants are for the actual deployed program.\r\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\r\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\r\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\r\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\r\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\r\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\r\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\r\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\r\nconst V12_1_ENGINE_PARAMS_OFF = 96;\r\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\r\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\r\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\r\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\r\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\r\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\r\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\r\nconst V12_1_SBF_OFF_C_TOT = 248;\r\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\r\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\r\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\r\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\r\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\r\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\r\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\r\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\r\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\r\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\r\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\r\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\r\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\r\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\r\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\r\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\r\n// Bitmap (used field): 584\r\n// Fields NOT present in deployed program (return -1):\r\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\r\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\r\n//\r\n// HOST engine field offsets (percolator-core, for test builds):\r\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\r\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\r\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\r\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\r\nconst V12_1_ENGINE_C_TOT_OFF = 480;\r\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\r\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\r\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\r\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\r\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\r\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\r\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\r\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\r\n// HOST-only fields (percolator-core has these, deployed percolator does not):\r\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\r\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\r\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\r\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\r\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\r\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\r\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\r\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\r\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\r\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\r\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\r\n// V12_1 account field offsets (relative to account slot start):\r\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\r\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\r\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\r\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\r\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\r\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\r\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\r\n\r\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\r\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\r\n// SBF layout (u128 align=8):\r\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\r\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\r\n// → fees_earned_total(@272) = 288 bytes\r\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\r\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\r\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\r\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\r\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\r\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\r\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\r\n\r\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\r\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\r\n// explicitly sized, no pointer-derived alignment differences).\r\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\r\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\r\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\r\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\r\n// overflow_newest_present(u8@4384).\r\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\r\n// Field max_accounts moved to offset 24, insurance_floor at 144.\r\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\r\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\r\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\r\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\r\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\r\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\r\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\r\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\r\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\r\n\r\n// V12_15 account field offsets (relative to account slot start):\r\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\r\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\r\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\r\nconst V12_15_ACCT_PNL_OFF = 32; // i128\r\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\r\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\r\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\r\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\r\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\r\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\r\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\r\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\r\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\r\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\r\n\r\n// V12_15 RiskParams offsets (relative to params base):\r\n// sizeof(RiskParams) = 192\r\nconst V12_15_PARAMS_SIZE = 192;\r\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\r\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\r\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\r\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\r\n\r\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\r\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\r\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\r\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\r\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\r\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\r\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\r\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\r\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\r\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\r\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\r\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\r\nconst V12_15_ENGINE_BITMAP_OFF = 862;\r\n\r\n// V12_15 size map for layout detection\r\nconst V12_15_SIZES = new Map();\r\n\r\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\r\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\r\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\r\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\r\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\r\n// pending_present/remaining_q/horizon/created_slot.\r\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\r\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\r\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\r\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\r\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\r\n\r\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\r\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\r\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\r\n// _new_fields_pad, pending_admin[32]).\r\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\r\n// size_of::() = 512 (both native and SBF — u128 fields happen\r\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\r\n\r\n// Native (i128 align=16)\r\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\r\nconst V12_17_ACCOUNT_SIZE = 368;\r\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\r\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\r\nconst V12_17_RISK_BUF_LEN = 160;\r\n// Per-account generation table appended after RISK_BUF in percolator-prog.\r\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\r\nconst V12_17_GEN_TABLE_ENTRY = 8;\r\n\r\n// SBF (i128 align=8)\r\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\r\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\r\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\r\n\r\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\r\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\r\nconst V12_17_ACCT_KIND_OFF = 16; // u8\r\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\r\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\r\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\r\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\r\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\r\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\r\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\r\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\r\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\r\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\r\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\r\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\r\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\r\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\r\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\r\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\r\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\r\n\r\n// V12_17 RiskEngine field offsets (native, relative to engine start)\r\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\r\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\r\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\r\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\r\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\r\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\r\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\r\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\r\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\r\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\r\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\r\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\r\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\r\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\r\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\r\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\r\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\r\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\r\n\r\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\r\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\r\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\r\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\r\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\r\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\r\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\r\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\r\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\r\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\r\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\r\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\r\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\r\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_17 size map for layout detection\r\nconst V12_17_SIZES = new Map();\r\n\r\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\r\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\r\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\r\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\r\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\r\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\r\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\r\nconst V1M_ACCOUNT_SIZE = 248;\r\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\r\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\r\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\r\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\r\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\r\n\r\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\r\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\r\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\r\n// min_nonzero_im_req(u128=16) = +48 total\r\nconst V1M_PARAMS_SIZE = 336;\r\n\r\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\r\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\r\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\r\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\r\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\r\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\r\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\r\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\r\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\r\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\r\nconst V1M_ENGINE_LONG_OI_OFF = 504;\r\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\r\nconst V1M_ENGINE_C_TOT_OFF = 536;\r\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\r\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\r\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\r\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\r\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\r\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\r\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\r\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\r\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\r\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\r\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\r\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\r\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\r\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\r\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\r\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\r\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\r\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\r\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\r\n// which is invalid for a [u64; N] array under #[repr(C)].\r\nconst V1M_ENGINE_BITMAP_OFF = 720;\r\n\r\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\r\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\r\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\r\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\r\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\r\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\r\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\r\n// New runtime fields inserted between fundingRateBps and markPrice:\r\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\r\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\r\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\r\n// +504: lastCrankSlot, +512: maxCrankStaleness\r\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\r\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\r\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\r\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\r\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\r\n\r\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\r\n// (used by reinit-slab and other scripts). These refer to V1 layout.\r\nexport const ENGINE_OFF = V1_ENGINE_OFF;\r\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\r\n\r\n// ---- Known slab sizes per version and tier ----\r\n\r\n/**\r\n * Compute the total byte size of a slab given its layout parameters.\r\n * Used to pre-populate the known-size lookup maps at module load time.\r\n */\r\nfunction computeSlabSize(\r\n engineOff: number,\r\n bitmapOff: number,\r\n accountSize: number,\r\n maxAccounts: number,\r\n // postBitmap bytes immediately after the free-slot bitmap:\r\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\r\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\r\n postBitmap = 18,\r\n): number {\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return engineOff + accountsOff + maxAccounts * accountSize;\r\n}\r\n\r\nconst TIERS = [64, 256, 1024, 4096] as const;\r\n\r\n// Pre-compute known slab sizes for fast lookup\r\nconst V0_SIZES = new Map();\r\nconst V1_SIZES = new Map();\r\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\r\nconst V1_SIZES_LEGACY = new Map();\r\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\r\nconst V1D_SIZES = new Map();\r\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\r\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\r\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\r\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\r\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\r\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\r\nconst V2_SIZES = new Map();\r\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\r\nconst V1M_SIZES = new Map();\r\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\nconst V_ADL_SIZES = new Map();\r\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\r\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n// No disambiguation probe required — size-based detection works correctly.\r\nconst V1M2_SIZES = new Map();\r\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\r\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\r\nconst V_SETDEXPOOL_SIZES = new Map();\r\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\r\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\r\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\r\nconst V12_1_SIZES = new Map();\r\nconst V1D_SIZES_LEGACY = new Map();\r\nfor (const n of TIERS) {\r\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\r\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\r\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\r\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\r\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\r\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\r\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\r\n // Disambiguation requires peeking at the version field in the slab header.\r\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\r\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\r\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\r\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\r\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\r\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\r\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\r\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\r\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\r\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\r\n // e.g. n=4096 → 1288336 bytes.\r\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\r\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\r\n // Register BOTH host-computed and SBF-empirical sizes for detection.\r\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\r\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\r\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\r\n}\r\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\r\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\r\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\r\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\r\n\r\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\r\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\r\n// SBF: Account align=8 → accountsOff alignment is 8.\r\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\r\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\r\nconst V12_17_TIERS = [256, 1024, 4096] as const;\r\nfor (const n of V12_17_TIERS) {\r\n const bitmapWords = Math.ceil(n / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = n * 2;\r\n\r\n // Native (i128 align=16, Account align=16)\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(nativeSize, n);\r\n\r\n // SBF (i128 align=8, Account align=8)\r\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\r\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(sbfSize, n);\r\n}\r\n\r\n// ---- V12_19 layout constants ----\r\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\r\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\r\n// below comes from a Rust compile-error message that revealed the real SBF\r\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\r\n//\r\n// V12_19 vs V12_17 SBF differences:\r\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\r\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\r\n// - ENGINE_OFF: 584 -> 616\r\n// - ACCOUNT_SIZE: 352 -> 360\r\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\r\n// - RiskEngine grew substantially; accounts now inline within engine struct.\r\nconst V12_19_HEADER_LEN_SBF = 136;\r\nconst V12_19_CONFIG_LEN = 480;\r\nconst V12_19_ENGINE_OFF_SBF = 616;\r\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\r\nconst V12_19_SBF_RISK_BUF_LEN = 160;\r\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\r\n\r\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\r\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\r\n// MAX_ACCOUNTS; small (256) shown here.\r\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\r\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\r\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\r\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\r\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\r\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\r\n\r\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\r\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\r\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\r\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\r\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\r\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\r\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\r\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\r\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\r\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\r\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\r\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\r\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\r\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\r\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\r\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\r\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\r\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\r\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\r\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\r\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\r\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\r\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\r\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\r\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\r\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\r\n\r\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\r\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\r\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\r\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\r\n// + (8-byte align pad) + N*360 (accounts).\r\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\r\n// (mainnet probe-confirmed), medium=376432, large=1495024.\r\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\r\nconst V12_19_SIZES = new Map([\r\n [26872, 64], // --features micro (derived)\r\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\r\n [376432, 1024], // --features medium (derived)\r\n [1495024, 4096], // default features / large (derived)\r\n]);\r\n\r\n/**\r\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\r\n *\r\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\r\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\r\n * 736 area to same offset but the post-bitmap region now contains both\r\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\r\n * before the inline accounts.\r\n *\r\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\r\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\r\n * linearly with MAX_ACCOUNTS.\r\n */\r\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\r\n // Compute layout-dependent offsets for this tier.\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\r\n const freeHeadOff = numUsedOff + 2; // after num_used u16\r\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\r\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\r\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\r\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\r\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\r\n\r\n // Inherit Account-internal field offsets from V12_17 (they're the same since\r\n // the Account struct definition is identical between v12.17 and v12.19;\r\n // the +8 byte size diff is from trailing padding, not field reordering).\r\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\r\n\r\n return {\r\n ...base,\r\n headerLen: V12_19_HEADER_LEN_SBF,\r\n configLen: V12_19_CONFIG_LEN,\r\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\r\n engineOff: V12_19_ENGINE_OFF_SBF,\r\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\r\n accountsOff,\r\n bitmapWords,\r\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\r\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\r\n // V12_19-specific engine field offsets (probe-confirmed):\r\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\r\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\r\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\r\n // last_market_slot replaces V12_17 last_crank_slot semantics.\r\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\r\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\r\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\r\n };\r\n}\r\n\r\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\r\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\r\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\r\n// Bitmap at engine+584 (used field in RiskEngine).\r\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\r\nconst V12_1_SBF_ENGINE_OFF = 616;\r\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\r\n V12_1_SIZES.set(total, n);\r\n}\r\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\r\nconst V12_1_EP_SIZES = new Map();\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\r\n V12_1_EP_SIZES.set(total, n);\r\n}\r\n\r\n/**\r\n * V2 slab tier sizes (small and large) for discovery.\r\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\r\n */\r\nexport const SLAB_TIERS_V2 = Object.freeze({\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\r\n} as const);\r\n\r\n/**\r\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\r\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\r\n */\r\nexport const SLAB_TIERS_V1M: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M);\r\n\r\n/**\r\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\r\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\r\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\r\n */\r\nexport const SLAB_TIERS_V1M2: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M2);\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\r\n */\r\nexport const SLAB_TIERS_V_ADL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_ADL);\r\n\r\n/**\r\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\r\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\r\n */\r\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\r\n const isV0 = version === 0;\r\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\r\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\r\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\r\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\r\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\r\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\r\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\r\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\r\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\r\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\r\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version,\r\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\r\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\r\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\r\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: actualBitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: !isV0,\r\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\r\n * Uses correct field offsets derived from on-chain probing.\r\n *\r\n * @param maxAccounts - Number of account slots in the slab\r\n * @param postBitmap - Bytes after the bitmap before next_free array.\r\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\r\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\r\n */\r\n/**\r\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\r\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\r\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\r\n */\r\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\r\n const engineOff = V1D_ENGINE_OFF;\r\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\r\n const accountSize = V1D_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1D_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\r\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\r\n paramsSize: V1D_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: -1, // not present in deployed V1\r\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\r\n engineEmergencyOiModeOff: -1, // not present in deployed V1\r\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\r\n engineLastBreakerSlotOff: -1, // not present in deployed V1\r\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\r\n postBitmap,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\r\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V2 (BPF intermediate layout).\r\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\r\n */\r\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\r\n const engineOff = V2_ENGINE_OFF;\r\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\r\n const accountSize = V2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V2_HEADER_LEN,\r\n configOffset: V2_HEADER_LEN,\r\n configLen: V2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\r\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\r\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: -1, // V2 has no mark_price\r\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: -1, // V2 has no long_oi\r\n engineShortOiOff: -1, // V2 has no short_oi\r\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\r\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\r\n * and trade_twap runtime fields push the bitmap to offset 726.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\r\n */\r\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M_ENGINE_OFF;\r\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\r\n paramsSize: V1M_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\r\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\r\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\r\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\r\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\r\n */\r\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M2_ENGINE_OFF;\r\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\r\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n *\r\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\r\n * large (4096 accounts): 1288320 bytes\r\n * medium (1024 accounts): 323320 bytes\r\n * small (256 accounts): 82064 bytes\r\n */\r\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\r\n const engineOff = V_ADL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_ADL_CONFIG_LEN, // 520\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\r\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\r\n * e.g. large (4096 accts) = 1288336 bytes.\r\n */\r\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\r\n\r\n/**\r\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\r\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\r\n * Verified by cargo build-sbf compile-time assertions.\r\n */\r\nexport const SLAB_TIERS_V12_1: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_1);\r\n\r\n/**\r\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\r\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\r\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\r\n * Account layout completely redesigned with reserve cohort arrays.\r\n */\r\nexport const SLAB_TIERS_V12_15: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_15);\r\n\r\n/**\r\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\r\n * Uses SBF sizes (on-chain layout) for the dataSize values.\r\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\r\n * RISK_BUF_LEN=160 appended after engine.\r\n * Supported tiers: small(256), medium(1024), large(4096).\r\n */\r\nexport const SLAB_TIERS_V12_17: Record = {};\r\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\r\n const accountsOff = Math.ceil(preAcc / 8) * 8;\r\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_17);\r\n\r\n/**\r\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\r\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\r\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\r\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\r\n * fall through to the memcmp fallback path with no layout hint.\r\n *\r\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\r\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\r\n * exports consumed by discovery.ts.\r\n */\r\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\r\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\r\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\r\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\r\n});\r\n\r\n/**\r\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\r\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\r\n * All engine and account field offsets are identical to V_ADL.\r\n */\r\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\r\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\r\n paramsSize: V_ADL_PARAMS_SIZE,\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF vs host detection via size comparison.\r\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\r\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\r\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\r\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\r\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\r\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\r\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: isSbf ? 544 : 576,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\r\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\r\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\r\n // Fields that don't exist in the deployed program are set to -1 on SBF.\r\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\r\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\r\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\r\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\r\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\r\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\r\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\r\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\r\n\r\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\r\n // No isolated_balance or insurance_isolation_bps fields.\r\n hasInsuranceIsolation: !isSbf,\r\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\r\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\r\n */\r\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\r\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\r\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\r\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: 72,\r\n configOffset: 72,\r\n configLen: 544,\r\n reservedOff: 80, // V1_RESERVED_OFF\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\r\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\r\n // Engine offsets identical to V12_1 SBF\r\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\r\n engineFundingIndexOff: -1,\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\r\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\r\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\r\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\r\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\r\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\r\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\r\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\r\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\r\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\r\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\r\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\r\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\r\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\r\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\r\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\r\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\r\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\r\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\r\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\r\n *\r\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\r\n */\r\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\r\n const isSbf = dataLen === 237512;\r\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\r\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\r\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\r\n // SBF small has different bitmap/accounts offsets due to u128 align=8\r\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: 552, // SBF CONFIG_LEN for v12.15\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\r\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\r\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\r\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\r\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\r\n engineMarkPriceOff: -1, // not present in v12.15\r\n engineLastCrankSlotOff: -1, // not yet mapped\r\n engineMaxCrankStalenessOff: -1, // not yet mapped\r\n engineTotalOiOff: -1, // not present in v12.15 engine\r\n engineLongOiOff: -1, // not present in v12.15 engine\r\n engineShortOiOff: -1, // not present in v12.15 engine\r\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\r\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\r\n engineLiqCursorOff: -1, // not yet mapped\r\n engineGcCursorOff: -1, // not yet mapped\r\n engineLastSweepStartOff: -1, // not yet mapped\r\n engineLastSweepCompleteOff: -1, // not yet mapped\r\n engineCrankCursorOff: -1, // not yet mapped\r\n engineSweepStartIdxOff: -1, // not yet mapped\r\n engineLifetimeLiquidationsOff: -1, // not yet mapped\r\n engineLifetimeForceClosesOff: -1, // not present in v12.15\r\n engineNetLpPosOff: -1, // not present in v12.15\r\n engineLpSumAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\r\n engineEmergencyOiModeOff: -1, // not present in v12.15\r\n engineEmergencyStartSlotOff: -1, // not present in v12.15\r\n engineLastBreakerSlotOff: -1, // not present in v12.15\r\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\r\n postBitmap,\r\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\r\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\r\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\r\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\r\n * RISK_BUF_LEN=160 appended after engine.\r\n */\r\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\r\n // Detect SBF vs native from account size and engine offset.\r\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\r\n const isSbf = (() => {\r\n // Compute expected native size for this tier\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\r\n return dataLen !== nativeSize;\r\n })();\r\n\r\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\r\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\r\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const acctAlign = isSbf ? 8 : 16;\r\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\r\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\r\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\r\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\r\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\r\n configLen: 512,\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : 192,\r\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\r\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\r\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: -1,\r\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\r\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\r\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: -1, // removed in v12.17\r\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: -1,\r\n engineLastSweepCompleteOff: -1,\r\n engineCrankCursorOff: -1,\r\n engineSweepStartIdxOff: -1,\r\n engineLifetimeLiquidationsOff: -1,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap,\r\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n\r\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\r\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\r\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\r\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\r\n // so absolute offset in the slab is 72 + 304 = 376.\r\n configMarkEwmaOff: V0_HEADER_LEN + 304,\r\n };\r\n}\r\n\r\n/**\r\n * Detect the slab layout version from the raw account data length.\r\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\r\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\r\n *\r\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\r\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\r\n * V2 slabs have version===2 at offset 8 (u32 LE).\r\n *\r\n * @param dataLen - The slab account data length in bytes\r\n * @param data - Optional raw slab data for version-field disambiguation\r\n */\r\n/**\r\n * Assert that a built SlabLayout is internally consistent.\r\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\r\n * Used by layout builders to catch offset arithmetic bugs early.\r\n *\r\n * @param layout - Layout descriptor to validate.\r\n * @param dataLen - Actual byte length of the slab data buffer.\r\n * @returns The validated layout (identity function for chaining).\r\n */\r\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\r\n if (layout.accountsOff > dataLen) {\r\n throw new Error(\r\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\r\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\r\n );\r\n }\r\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\r\n if (bitmapEnd > dataLen) {\r\n throw new Error(\r\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\r\n );\r\n }\r\n return layout;\r\n}\r\n\r\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\r\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\r\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\r\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\r\n // deployed program only emits v12.19 going forward, so this priority\r\n // is correct for live mainnet reads.\r\n const v1219n = V12_19_SIZES.get(dataLen);\r\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\r\n\r\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\r\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\r\n const v1217n = V12_17_SIZES.get(dataLen);\r\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\r\n\r\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\r\n // Vastly larger account size — no collision with any earlier layout possible.\r\n const v1215n = V12_15_SIZES.get(dataLen);\r\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\r\n\r\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\r\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\r\n const v121epn = V12_1_EP_SIZES.get(dataLen);\r\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\r\n\r\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\r\n const v121n = V12_1_SIZES.get(dataLen);\r\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\r\n\r\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\r\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\r\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\r\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\r\n\r\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\r\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\r\n // works directly — no data-probe disambiguation required.\r\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n const v1m2n = V1M2_SIZES.get(dataLen);\r\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\r\n\r\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\r\n const vadln = V_ADL_SIZES.get(dataLen);\r\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\r\n\r\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\r\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\r\n const v1mn = V1M_SIZES.get(dataLen);\r\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\r\n\r\n // Check V0 sizes (deployed devnet V0 program)\r\n const v0n = V0_SIZES.get(dataLen);\r\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\r\n\r\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\r\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\r\n // When data is available, peek at the version field to disambiguate.\r\n const v1dn = V1D_SIZES.get(dataLen);\r\n if (v1dn !== undefined) {\r\n if (data && data.length >= 12) {\r\n const version = readU32LE(data, 8);\r\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\r\n }\r\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\r\n }\r\n\r\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\r\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\r\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\r\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\r\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\r\n\r\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\r\n const v1n = V1_SIZES.get(dataLen);\r\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\r\n\r\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\r\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\r\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\r\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\r\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\r\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Legacy detectLayout for backward compat.\r\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\r\n *\r\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\r\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\r\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\r\n */\r\nexport function detectLayout(dataLen: number) {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return null;\r\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\r\n}\r\n\r\n// =============================================================================\r\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\r\n// =============================================================================\r\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\r\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\r\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\r\nconst PARAMS_TRADING_FEE_OFF = 24;\r\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\r\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\r\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\r\n// riskReductionThreshold and liquidationBufferBps fields).\r\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\r\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\r\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\r\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\r\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\r\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\r\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\r\n\r\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\r\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\r\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\r\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\r\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\r\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\r\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\r\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\r\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\r\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\r\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\r\n\r\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\r\n// InitMarket wire payload for policy fields such as new_account_fee and\r\n// insurance_floor, but those fields are not stored inside engine RiskParams.\r\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\r\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\r\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\r\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\r\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\r\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\r\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\r\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\r\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\r\nconst V12_19_PARAMS_H_MIN_OFF = 104;\r\nconst V12_19_PARAMS_H_MAX_OFF = 112;\r\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\r\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\r\n\r\n// =============================================================================\r\n// Account Layout (240/248 bytes)\r\n// The first 240 bytes are identical in V0 and V1.\r\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\r\n// =============================================================================\r\nconst ACCT_ACCOUNT_ID_OFF = 0;\r\nconst ACCT_CAPITAL_OFF = 8;\r\nconst ACCT_KIND_OFF = 24;\r\nconst ACCT_PNL_OFF = 32;\r\nconst ACCT_RESERVED_PNL_OFF = 48;\r\nconst ACCT_WARMUP_STARTED_OFF = 56;\r\nconst ACCT_WARMUP_SLOPE_OFF = 64;\r\nconst ACCT_POSITION_SIZE_OFF = 80;\r\nconst ACCT_ENTRY_PRICE_OFF = 96;\r\nconst ACCT_FUNDING_INDEX_OFF = 104;\r\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\r\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\r\nconst ACCT_OWNER_OFF = 184;\r\nconst ACCT_FEE_CREDITS_OFF = 216;\r\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\r\n\r\n// =============================================================================\r\n// Interfaces\r\n// =============================================================================\r\n\r\nexport interface SlabHeader {\r\n magic: bigint;\r\n version: number;\r\n bump: number;\r\n flags: number;\r\n resolved: boolean;\r\n paused: boolean;\r\n admin: PublicKey;\r\n nonce: bigint;\r\n lastThrUpdateSlot: bigint;\r\n}\r\n\r\nexport interface MarketConfig {\r\n collateralMint: PublicKey;\r\n vaultPubkey: PublicKey;\r\n indexFeedId: PublicKey;\r\n maxStalenessSlots: bigint;\r\n confFilterBps: number;\r\n vaultAuthorityBump: number;\r\n invert: number;\r\n unitScale: number;\r\n fundingHorizonSlots: bigint;\r\n fundingKBps: bigint;\r\n fundingInvScaleNotionalE6: bigint;\r\n fundingMaxPremiumBps: bigint;\r\n fundingMaxBpsPerSlot: bigint;\r\n threshFloor: bigint;\r\n threshRiskBps: bigint;\r\n threshUpdateIntervalSlots: bigint;\r\n threshStepBps: bigint;\r\n threshAlphaBps: bigint;\r\n threshMin: bigint;\r\n threshMax: bigint;\r\n threshMinStep: bigint;\r\n oracleAuthority: PublicKey;\r\n authorityPriceE6: bigint;\r\n authorityTimestamp: bigint;\r\n oraclePriceCapE2bps: bigint;\r\n lastEffectivePriceE6: bigint;\r\n oiCapMultiplierBps: bigint;\r\n maxPnlCap: bigint;\r\n adaptiveFundingEnabled: boolean;\r\n adaptiveScaleBps: number;\r\n adaptiveMaxFundingBps: bigint;\r\n marketCreatedSlot: bigint;\r\n oiRampSlots: bigint;\r\n /**\r\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\r\n * Do not use for market-resolution logic until a parser is wired.\r\n */\r\n resolvedSlot: bigint;\r\n insuranceIsolationBps: number;\r\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\r\n oraclePhase: number;\r\n /** PERC-622: Cumulative trade volume in e6 format */\r\n cumulativeVolumeE6: bigint;\r\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\r\n phase2DeltaSlots: number;\r\n /**\r\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\r\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\r\n * SetDexPool has never been called (all-zero pubkey).\r\n * Non-null means the program will reject any UpdateHyperpMark that passes\r\n * a different pool account.\r\n */\r\n dexPool: PublicKey | null;\r\n}\r\n\r\nexport interface InsuranceFund {\r\n balance: bigint;\r\n feeRevenue: bigint;\r\n isolatedBalance: bigint;\r\n isolationBps: number;\r\n}\r\n\r\nexport interface RiskParams {\r\n /**\r\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\r\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\r\n */\r\n warmupPeriodSlots: bigint;\r\n maintenanceMarginBps: bigint;\r\n initialMarginBps: bigint;\r\n tradingFeeBps: bigint;\r\n maxAccounts: bigint;\r\n newAccountFee: bigint;\r\n riskReductionThreshold: bigint;\r\n maintenanceFeePerSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n liquidationFeeBps: bigint;\r\n liquidationFeeCap: bigint;\r\n liquidationBufferBps: bigint;\r\n minLiquidationAbs: bigint;\r\n /** Minimum initial deposit to open an account (V12_1+ only) */\r\n minInitialDeposit: bigint;\r\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\r\n minNonzeroMmReq: bigint;\r\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\r\n minNonzeroImReq: bigint;\r\n /** Insurance fund floor (V12_1+ only) */\r\n insuranceFloor: bigint;\r\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\r\n hMin: bigint;\r\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\r\n hMax: bigint;\r\n}\r\n\r\nexport interface EngineState {\r\n vault: bigint;\r\n insuranceFund: InsuranceFund;\r\n currentSlot: bigint;\r\n fundingIndexQpbE6: bigint;\r\n lastFundingSlot: bigint;\r\n /**\r\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\r\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\r\n */\r\n fundingRateBpsPerSlotLast: bigint;\r\n /**\r\n * Funding rate in e9 units (i128). v12.15+ only.\r\n * 0n on pre-v12.15 slabs.\r\n */\r\n fundingRateE9: bigint;\r\n /**\r\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\r\n */\r\n marketMode: 0 | 1 | null;\r\n lastCrankSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n totalOpenInterest: bigint;\r\n longOi: bigint;\r\n shortOi: bigint;\r\n cTot: bigint;\r\n pnlPosTot: bigint;\r\n /**\r\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\r\n */\r\n pnlMaturedPosTot: bigint;\r\n liqCursor: number;\r\n gcCursor: number;\r\n lastSweepStartSlot: bigint;\r\n lastSweepCompleteSlot: bigint;\r\n crankCursor: number;\r\n sweepStartIdx: number;\r\n lifetimeLiquidations: bigint;\r\n lifetimeForceCloses: bigint;\r\n netLpPos: bigint;\r\n lpSumAbs: bigint;\r\n lpMaxAbs: bigint;\r\n lpMaxAbsSweep: bigint;\r\n emergencyOiMode: boolean;\r\n emergencyStartSlot: bigint;\r\n lastBreakerSlot: bigint;\r\n numUsedAccounts: number;\r\n nextAccountId: bigint;\r\n markPriceE6: bigint;\r\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\r\n oraclePriceE6: bigint;\r\n\r\n // ---- V12_17 engine fields ----\r\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\r\n fLongNum: bigint;\r\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\r\n fShortNum: bigint;\r\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\r\n negPnlAccountCount: bigint;\r\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\r\n fundPxLast: bigint;\r\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\r\n resolvedKLongTerminalDelta: bigint;\r\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\r\n resolvedKShortTerminalDelta: bigint;\r\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\r\n resolvedLivePrice: bigint;\r\n}\r\n\r\nexport enum AccountKind {\r\n User = 0,\r\n LP = 1,\r\n}\r\n\r\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\r\nexport type ReserveCohortBytes = Uint8Array;\r\n\r\nexport interface Account {\r\n kind: AccountKind;\r\n accountId: bigint;\r\n capital: bigint;\r\n pnl: bigint;\r\n reservedPnl: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupStartedAtSlot: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupSlopePerStep: bigint;\r\n positionSize: bigint;\r\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\r\n entryPrice: bigint;\r\n fundingIndex: bigint;\r\n matcherProgram: PublicKey;\r\n matcherContext: PublicKey;\r\n owner: PublicKey;\r\n feeCredits: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n lastFeeSlot: bigint;\r\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\r\n feesEarnedTotal: bigint;\r\n /**\r\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\r\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\r\n */\r\n exactReserveCohorts: ReserveCohortBytes[] | null;\r\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\r\n exactCohortCount: number | null;\r\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowOlder: ReserveCohortBytes | null;\r\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\r\n overflowOlderPresent: boolean | null;\r\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowNewest: ReserveCohortBytes | null;\r\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\r\n overflowNewestPresent: boolean | null;\r\n\r\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\r\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\r\n fSnap: bigint;\r\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\r\n adlABasis: bigint;\r\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\r\n adlKSnap: bigint;\r\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\r\n adlEpochSnap: bigint;\r\n\r\n // Scheduled reserve bucket (older, matures linearly)\r\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\r\n schedPresent: boolean | null;\r\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\r\n schedRemainingQ: bigint | null;\r\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\r\n schedAnchorQ: bigint | null;\r\n /** Start slot for scheduled bucket. null on pre-v12.17. */\r\n schedStartSlot: bigint | null;\r\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\r\n schedHorizon: bigint | null;\r\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\r\n schedReleaseQ: bigint | null;\r\n\r\n // Pending reserve bucket (newest, does not mature while pending)\r\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\r\n pendingPresent: boolean | null;\r\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\r\n pendingRemainingQ: bigint | null;\r\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\r\n pendingHorizon: bigint | null;\r\n /** Creation slot for pending bucket. null on pre-v12.17. */\r\n pendingCreatedSlot: bigint | null;\r\n}\r\n\r\n// =============================================================================\r\n// Fetch\r\n// =============================================================================\r\n\r\nexport async function fetchSlab(\r\n connection: Connection,\r\n slabPubkey: PublicKey,\r\n expectedOwner?: PublicKey\r\n): Promise {\r\n const info = await connection.getAccountInfo(slabPubkey);\r\n if (!info) {\r\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\r\n }\r\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\r\n throw new Error(\r\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\r\n );\r\n }\r\n return new Uint8Array(info.data);\r\n}\r\n\r\n// =============================================================================\r\n// PERC-302: Market Maturity OI Ramp\r\n// =============================================================================\r\n\r\nexport const RAMP_START_BPS = 1000n;\r\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\r\n\r\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\r\n const target = config.oiCapMultiplierBps;\r\n if (target === 0n) return 0n;\r\n if (config.oiRampSlots === 0n) return target;\r\n if (target <= RAMP_START_BPS) return target;\r\n const elapsed = currentSlot > config.marketCreatedSlot\r\n ? currentSlot - config.marketCreatedSlot\r\n : 0n;\r\n if (elapsed >= config.oiRampSlots) return target;\r\n const range = target - RAMP_START_BPS;\r\n const rampAdd = (range * elapsed) / config.oiRampSlots;\r\n const result = RAMP_START_BPS + rampAdd;\r\n return result < target ? result : target;\r\n}\r\n\r\n// =============================================================================\r\n// Header helpers\r\n// =============================================================================\r\n\r\nexport function readNonce(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\r\n return readU64LE(data, roff);\r\n}\r\n\r\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\r\n return readU64LE(data, roff + 8);\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Parse slab header (first 72 bytes — layout-independent).\r\n */\r\nexport function parseHeader(data: Uint8Array): SlabHeader {\r\n if (data.length < V0_HEADER_LEN) {\r\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\r\n }\r\n\r\n const magic = readU64LE(data, 0);\r\n if (magic !== MAGIC) {\r\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\r\n }\r\n\r\n const version = readU32LE(data, 8);\r\n const bump = readU8(data, 12);\r\n const flags = readU8(data, 13);\r\n const admin = new PublicKey(data.subarray(16, 48));\r\n\r\n // Reserved field location depends on layout\r\n const layout = detectSlabLayout(data.length, data);\r\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\r\n const nonce = readU64LE(data, roff);\r\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\r\n\r\n return {\r\n magic,\r\n version,\r\n bump,\r\n flags,\r\n resolved: (flags & FLAG_RESOLVED) !== 0,\r\n paused: (flags & 0x02) !== 0,\r\n admin,\r\n nonce,\r\n lastThrUpdateSlot,\r\n };\r\n}\r\n\r\n/**\r\n * Parse market config. Layout-version aware.\r\n * For V0 slabs, fields beyond the basic config are read if present in the data,\r\n * otherwise defaults are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\n/**\r\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\r\n * SBF layout (u128 align=8, total size 512 bytes):\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_bps_per_slot i64\r\n * 144 oracle_authority [32]\r\n * 176 authority_price_e6 u64\r\n * 184 authority_timestamp i64\r\n * 192 oracle_price_cap_e2bps u64\r\n * 200 last_effective_price_e6 u64\r\n * 208 max_insurance_floor u128\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\r\n * 240 insurance_withdraw_cooldown_slots u64\r\n * 248 _iw_padding2 [u64;2]\r\n * 264 last_hyperp_index_slot u64\r\n * 272 last_mark_push_slot u128\r\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\r\n * 304 mark_ewma_e6 u64\r\n * 312 mark_ewma_last_slot u64\r\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\r\n * 336 permissionless_resolve_stale_slots u64\r\n * 344 last_good_oracle_slot u64\r\n * 352 maintenance_fee_per_slot u128\r\n * 368 last_fee_charge_slot u64 (+ 8 pad)\r\n * 384 mark_min_fee u64\r\n * 392 force_close_delay_slots u64\r\n * 400 dex_pool [32]\r\n * 432 max_pnl_cap u64\r\n * 440 last_audit_pause_slot u64\r\n * 448 oi_cap_multiplier_bps u64\r\n * 456 dispute_window_slots u64\r\n * 464 dispute_bond_amount u64\r\n * 472 lp_collateral_enabled u8\r\n * 473 _pad u8\r\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\r\n * 480 pending_admin [32]\r\n * 512 end\r\n */\r\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_17_BYTES = 512;\r\n if (data.length < configOff + MIN_V12_17_BYTES) {\r\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\r\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\r\n // currently surfaced by the MarketConfig type; read them when/if callers\r\n // need them. Only dex_pool is consumed downstream.\r\n\r\n const dexPoolBytes = data.subarray(b + 400, b + 432);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n, // removed in v12.17\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 448),\r\n maxPnlCap: readU64LE(data, b + 432),\r\n adaptiveFundingEnabled: false, // removed in v12.17\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\r\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\r\n * --features small) on 2026-04-28.\r\n *\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_e9_per_slot i64\r\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\r\n * 176 hyperp_mark_e6 u64 ← v12.19 only\r\n * 184 last_oracle_publish_time i64\r\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\r\n * 200 insurance_withdraw_max_bps u16\r\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\r\n * 204 _iw_padding [u8;4]\r\n * 208 insurance_withdraw_cooldown_slots u64\r\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 last_hyperp_index_slot u64\r\n * 240 last_mark_push_slot u128\r\n * 256 last_insurance_withdraw_slot u64\r\n * 264 _pad u64\r\n * 272 mark_ewma_e6 u64\r\n * 280 mark_ewma_last_slot u64\r\n * 288 mark_ewma_halflife_slots u64\r\n * 296 init_restart_slot u64\r\n * 304 permissionless_resolve_stale_slots u64\r\n * 312 last_good_oracle_slot u64\r\n * 320 maintenance_fee_per_slot u128\r\n * 336 fee_sweep_cursor_word u64\r\n * 344 fee_sweep_cursor_bit u64\r\n * 352 mark_min_fee u64\r\n * 360 force_close_delay_slots u64\r\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\r\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\r\n * 408 last_audit_pause_slot u64\r\n * 416 oi_cap_multiplier_bps u64\r\n * 424 dispute_window_slots u64\r\n * 432 dispute_bond_amount u64\r\n * 440 lp_collateral_enabled u8\r\n * 441 _pad u8\r\n * 442 lp_collateral_ltv_bps u16\r\n * 444 _pad [u8;4]\r\n * 448 pending_admin [32]\r\n * 480 end\r\n */\r\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_19_BYTES = 480;\r\n if (data.length < configOff + MIN_V12_19_BYTES) {\r\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\r\n\r\n const dexPoolBytes = data.subarray(b + 368, b + 400);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n,\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 416),\r\n maxPnlCap: readU64LE(data, b + 400),\r\n adaptiveFundingEnabled: false,\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseConfig: invalid slab magic');\r\n }\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\r\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\r\n\r\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\r\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\r\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_19) {\r\n return parseConfigV12_19(data, configOff);\r\n }\r\n\r\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\r\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\r\n // sequential code below covers pre-v12.17 layouts.\r\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\r\n if (isV12_17) {\r\n return parseConfigV12_17(data, configOff);\r\n }\r\n\r\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\r\n // V1 extended fields are optional and guarded by their own `remaining` checks.\r\n const MIN_CONFIG_BYTES = 376;\r\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\r\n }\r\n\r\n let off = configOff;\r\n\r\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const maxStalenessSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const confFilterBps = readU16LE(data, off);\r\n off += 2;\r\n\r\n const vaultAuthorityBump = readU8(data, off);\r\n off += 1;\r\n\r\n const invert = readU8(data, off);\r\n off += 1;\r\n\r\n const unitScale = readU32LE(data, off);\r\n off += 4;\r\n\r\n // Funding rate parameters\r\n const fundingHorizonSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingKBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\r\n off += 16;\r\n\r\n const fundingMaxPremiumBps = readI64LE(data, off);\r\n off += 8;\r\n\r\n const fundingMaxBpsPerSlot = readI64LE(data, off);\r\n off += 8;\r\n\r\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\r\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\r\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\r\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\r\n\r\n // Threshold parameters\r\n const threshFloor = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshRiskBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshUpdateIntervalSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshStepBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshAlphaBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshMin = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMax = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMinStep = readU128LE(data, off);\r\n off += 16;\r\n\r\n // Oracle authority fields\r\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const authorityPriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n const authorityTimestamp = readI64LE(data, off);\r\n off += 8;\r\n\r\n // Oracle price circuit breaker\r\n const oraclePriceCapE2bps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const lastEffectivePriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n // OI cap\r\n const oiCapMultiplierBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const maxPnlCap = readU64LE(data, off);\r\n off += 8;\r\n\r\n // Check if we have enough data for V1-only fields\r\n const remaining = configOff + configLen - off;\r\n\r\n let adaptiveFundingEnabled = false;\r\n let adaptiveScaleBps = 0;\r\n let adaptiveMaxFundingBps = 0n;\r\n let marketCreatedSlot = 0n;\r\n let oiRampSlots = 0n;\r\n let resolvedSlot = 0n;\r\n let insuranceIsolationBps = 0;\r\n let oraclePhase = 0;\r\n let cumulativeVolumeE6 = 0n;\r\n let phase2DeltaSlots = 0;\r\n\r\n if (remaining >= 40) {\r\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\r\n // market_created_slot(u64), oi_ramp_slots(u64),\r\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\r\n // _pad2(u32), adaptive_max_funding_bps(u64),\r\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\r\n marketCreatedSlot = readU64LE(data, off);\r\n off += 8;\r\n\r\n oiRampSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n adaptiveFundingEnabled = readU8(data, off) !== 0;\r\n off += 1;\r\n off += 1; // _adaptive_pad\r\n adaptiveScaleBps = readU16LE(data, off);\r\n off += 2;\r\n off += 4; // _adaptive_pad2\r\n adaptiveMaxFundingBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n if (remaining >= 42) {\r\n insuranceIsolationBps = readU16LE(data, off);\r\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\r\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\r\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\r\n if (remaining >= 56) { // 42 + 14 bytes padding\r\n const padOff = off + 2;\r\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\r\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\r\n // phase2_delta_slots is u24 LE (3 bytes)\r\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\r\n }\r\n }\r\n }\r\n\r\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\r\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\r\n // All-zero pubkey means SetDexPool was never called.\r\n let dexPool: PublicKey | null = null;\r\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\r\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\r\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\r\n // Return null if all-zero (SetDexPool never called)\r\n if (dexPoolBytes.some(b => b !== 0)) {\r\n dexPool = new PublicKey(dexPoolBytes);\r\n }\r\n }\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor,\r\n threshRiskBps,\r\n threshUpdateIntervalSlots,\r\n threshStepBps,\r\n threshAlphaBps,\r\n threshMin,\r\n threshMax,\r\n threshMinStep,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps,\r\n maxPnlCap,\r\n adaptiveFundingEnabled,\r\n adaptiveScaleBps,\r\n adaptiveMaxFundingBps,\r\n marketCreatedSlot,\r\n oiRampSlots,\r\n resolvedSlot,\r\n insuranceIsolationBps,\r\n oraclePhase,\r\n cumulativeVolumeE6,\r\n phase2DeltaSlots,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * Parse RiskParams from engine data. Layout-version aware.\r\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\r\n * not present on-chain, so defaults (0) are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\r\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\r\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\r\n const base = engineOff + paramsOff;\r\n\r\n // Validate we have enough data for the fields we'll actually read.\r\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\r\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\r\n if (data.length < base + MIN_PARAMS_BYTES) {\r\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\r\n }\r\n\r\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\r\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\r\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\r\n const isV12_19Params = layout !== null && layout !== undefined &&\r\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\r\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\r\n\r\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\r\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\r\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\r\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\r\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\r\n\r\n // Basic params present in all layouts (offsets 0-55 are identical)\r\n const result: RiskParams = {\r\n warmupPeriodSlots: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\r\n maintenanceMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\r\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\r\n initialMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 8)\r\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\r\n tradingFeeBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 16)\r\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\r\n maxAccounts: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\r\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\r\n newAccountFee: isV12_19Params\r\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\r\n : isV12_15Params\r\n ? readU128LE(data, base + 32) // offset 32 in v12.15\r\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\r\n // Extended params: defaults; overwritten below if layout supports them\r\n riskReductionThreshold: 0n,\r\n maintenanceFeePerSlot: 0n,\r\n maxCrankStalenessSlots: 0n,\r\n liquidationFeeBps: 0n,\r\n liquidationFeeCap: 0n,\r\n liquidationBufferBps: 0n,\r\n minLiquidationAbs: 0n,\r\n minInitialDeposit: 0n,\r\n minNonzeroMmReq: 0n,\r\n minNonzeroImReq: 0n,\r\n insuranceFloor: 0n,\r\n hMin: 0n,\r\n hMax: 0n,\r\n };\r\n\r\n if (isV12_19Params) {\r\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\r\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\r\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\r\n result.riskReductionThreshold = 0n;\r\n result.maintenanceFeePerSlot = 0n;\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = 0n;\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = 0n;\r\n } else if (isV12_15Params) {\r\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\r\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\r\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\r\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\r\n result.riskReductionThreshold = 0n; // removed in v12.15\r\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\r\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\r\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\r\n result.liquidationFeeBps = readU64LE(data, base + 56);\r\n result.liquidationFeeCap = readU128LE(data, base + 64);\r\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\r\n result.minLiquidationAbs = readU128LE(data, base + 80);\r\n result.minInitialDeposit = readU128LE(data, base + 96);\r\n result.minNonzeroMmReq = readU128LE(data, base + 112);\r\n result.minNonzeroImReq = readU128LE(data, base + 128);\r\n } else if (isV12_1Sbf) {\r\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\r\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n } else if (paramsSize >= 144) {\r\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\r\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\r\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\r\n */\r\nexport function parseEngine(data: Uint8Array): EngineState {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseEngine: invalid slab magic');\r\n }\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\r\n }\r\n if (data.length < layout.accountsOff) {\r\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\r\n }\r\n\r\n const base = layout.engineOff;\r\n\r\n // Detect layout versions\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\r\n\r\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\r\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\r\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\r\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_17 || isV12_19) {\r\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\r\n\r\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\r\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\r\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\r\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\r\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\r\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\r\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\r\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\r\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\r\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\r\n // resolved_k offsets: native 304/320, SBF 288/304\r\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\r\n const resolvedKLongOff = isV12_19 ? 288\r\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\r\n const resolvedKShortOff = isV12_19 ? 304\r\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\r\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\r\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\r\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\r\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\r\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\r\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\r\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\r\n\r\n const longOi = readU128LE(data, base + oiEffLongOff);\r\n const shortOi = readU128LE(data, base + oiEffShortOff);\r\n\r\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\r\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: 0n,\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + currentSlotOff),\r\n fundingIndexQpbE6: 0n, // replaced by per-side funding\r\n lastFundingSlot: 0n,\r\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\r\n fundingRateE9: 0n, // no stored funding rate in v12.17\r\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\r\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\r\n maxCrankStalenessSlots: 0n,\r\n totalOpenInterest: longOi + shortOi,\r\n longOi,\r\n shortOi,\r\n cTot: readU128LE(data, base + cTotOff),\r\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\r\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\r\n liqCursor: 0,\r\n gcCursor: readU16LE(data, base + gcCursorOff),\r\n lastSweepStartSlot: 0n,\r\n lastSweepCompleteSlot: 0n,\r\n crankCursor: 0,\r\n sweepStartIdx: 0,\r\n lifetimeLiquidations: 0n,\r\n lifetimeForceCloses: 0n,\r\n netLpPos: 0n,\r\n lpSumAbs: 0n,\r\n lpMaxAbs: 0n,\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n,\r\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\r\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\r\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\r\n\r\n // V12_17 fields\r\n fLongNum: readI128LE(data, base + fLongNumOff),\r\n fShortNum: readI128LE(data, base + fShortNumOff),\r\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\r\n fundPxLast: readU64LE(data, base + fundPxLastOff),\r\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\r\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\r\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\r\n };\r\n }\r\n\r\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\r\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\r\n const fundingRateBpsPerSlotLast = isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + layout.engineInsuranceOff),\r\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\r\n feeRevenue: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\r\n : 0n,\r\n isolatedBalance: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\r\n : 0n,\r\n isolationBps: layout.hasInsuranceIsolation\r\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\r\n : 0,\r\n },\r\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\r\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\r\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\r\n : readI128LE(data, base + layout.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\r\n fundingRateBpsPerSlotLast,\r\n fundingRateE9: isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : 0n,\r\n marketMode: isV12_15\r\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\r\n : null,\r\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\r\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\r\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\r\n totalOpenInterest: layout.engineTotalOiOff >= 0\r\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\r\n longOi: layout.engineLongOiOff >= 0\r\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\r\n shortOi: layout.engineShortOiOff >= 0\r\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\r\n cTot: readU128LE(data, base + layout.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\r\n pnlMaturedPosTot: isV12_15\r\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\r\n : 0n,\r\n liqCursor: layout.engineLiqCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\r\n gcCursor: layout.engineGcCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\r\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\r\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\r\n crankCursor: layout.engineCrankCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\r\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\r\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\r\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\r\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\r\n netLpPos: layout.engineNetLpPosOff >= 0\r\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\r\n lpSumAbs: layout.engineLpSumAbsOff >= 0\r\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\r\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\r\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\r\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\r\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\r\n : false,\r\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\r\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\r\n markPriceE6: layout.engineMarkPriceOff >= 0\r\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\r\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\r\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\r\n oraclePriceE6: isV12_15\r\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\r\n : 0n,\r\n numUsedAccounts: (() => {\r\n if (layout.postBitmap < 18) return 0;\r\n const bw = layout.bitmapWords;\r\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\r\n })(),\r\n nextAccountId: (() => {\r\n if (layout.postBitmap < 18) return 0n;\r\n const bw = layout.bitmapWords;\r\n const numUsedOff = layout.engineBitmapOff + bw * 8;\r\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\r\n })(),\r\n\r\n // V12_17 fields (not present in pre-v12.17)\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n };\r\n}\r\n\r\n/**\r\n * Read bitmap to get list of used account indices.\r\n */\r\n/**\r\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\r\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\r\n */\r\nexport function parseUsedIndices(data: Uint8Array): number[] {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n if (data.length < base + layout.bitmapWords * 8) {\r\n throw new Error(\"Slab data too short for bitmap\");\r\n }\r\n\r\n const used: number[] = [];\r\n for (let word = 0; word < layout.bitmapWords; word++) {\r\n const bits = readU64LE(data, base + word * 8);\r\n if (bits === 0n) continue;\r\n for (let bit = 0; bit < 64; bit++) {\r\n if ((bits >> BigInt(bit)) & 1n) {\r\n used.push(word * 64 + bit);\r\n }\r\n }\r\n }\r\n return used;\r\n}\r\n\r\n/**\r\n * Check if a specific account index is used.\r\n */\r\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) return false;\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n const word = Math.floor(idx / 64);\r\n const bit = idx % 64;\r\n const bits = readU64LE(data, base + word * 8);\r\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\r\n}\r\n\r\n/**\r\n * Calculate the maximum valid account index for a given slab size.\r\n */\r\nexport function maxAccountIndex(dataLen: number): number {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return 0;\r\n const accountsEnd = dataLen - layout.accountsOff;\r\n if (accountsEnd <= 0) return 0;\r\n return Math.floor(accountsEnd / layout.accountSize);\r\n}\r\n\r\n/**\r\n * Parse a single account by index.\r\n */\r\nexport function parseAccount(data: Uint8Array, idx: number): Account {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const maxIdx = maxAccountIndex(data.length);\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\r\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\r\n }\r\n\r\n const base = layout.accountsOff + idx * layout.accountSize;\r\n if (data.length < base + layout.accountSize) {\r\n throw new Error(\"Slab data too short for account\");\r\n }\r\n\r\n // Select layout-dependent account field offsets.\r\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\r\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\r\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\r\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\r\n // Pre-ADL (account_size<312): original offsets.\r\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\r\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\r\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\r\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\r\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\r\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\r\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\r\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\r\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\r\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\r\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\r\n\r\n if (isV12_17) {\r\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\r\n //\r\n // SBF vs native alignment delta:\r\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\r\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\r\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\r\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\r\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\r\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\r\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\r\n\r\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: 0n, // removed in v12.17\r\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\r\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\r\n warmupStartedAtSlot: 0n, // removed\r\n warmupSlopePerStep: 0n, // removed\r\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\r\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\r\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\r\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\r\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\r\n lastFeeSlot: 0n, // removed\r\n feesEarnedTotal: 0n, // removed in v12.17\r\n exactReserveCohorts: null, // replaced by two-bucket warmup\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // V12_17 fields\r\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\r\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\r\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\r\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\r\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\r\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\r\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\r\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\r\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\r\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\r\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\r\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\r\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\r\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\r\n };\r\n }\r\n\r\n if (isV12_15) {\r\n // V12_15 fast path: fixed offsets, all fields explicit.\r\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n // Parse the 62 reserve cohorts\r\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\r\n const exactReserveCohorts: ReserveCohortBytes[] = [];\r\n for (let i = 0; i < 62; i++) {\r\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\r\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\r\n }\r\n\r\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\r\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\r\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: 0n, // removed in v12.15\r\n warmupSlopePerStep: 0n, // removed in v12.15\r\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\r\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\r\n fundingIndex: 0n, // not present in v12.15 account struct\r\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\r\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\r\n lastFeeSlot: 0n, // removed in v12.15\r\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\r\n exactReserveCohorts,\r\n exactCohortCount: cohortCount,\r\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\r\n overflowOlderPresent,\r\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\r\n overflowNewestPresent,\r\n\r\n // v12.17 fields (not present in v12.15)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n }\r\n\r\n // Pre-v12.15 path\r\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\r\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\r\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\r\n 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));\r\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\r\n 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));\r\n 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));\r\n 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));\r\n 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));\r\n\r\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\r\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\r\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\r\n positionSize: readI128LE(data, base + positionSizeOff),\r\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\r\n // V12_1/V12_1_EP: funding_index not present in SBF layout\r\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\r\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\r\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\r\n feeCredits: readI128LE(data, base + feeCreditsOff),\r\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\r\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\r\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // v12.17 fields (not present in pre-v12.17)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\r\n//\r\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\r\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\r\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\r\n// is a full account-layout break — every v16-version market account is\r\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\r\n// =============================================================================\r\n\r\n/**\r\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\r\n * Stored at bytes [0..8] of every v17 percolator-owned account.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\n/**\r\n * v17 account version (u16 at offset 8).\r\n *\r\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\r\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\r\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\r\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\r\n */\r\nexport const V17_EXPECTED_VERSION = 17;\r\n\r\n/**\r\n * v17 account-kind byte (offset 10 of the 16-byte header).\r\n *\r\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\r\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\r\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\r\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\r\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\r\n * discovery — every other kind shares the same magic+version and would falsely\r\n * pass the looser {@link isV17Account} check (#264).\r\n */\r\nexport const V17_KIND_MARKET = 1;\r\n\r\n/** Byte offset of the v17 account-kind discriminator within the header. */\r\nexport const V17_KIND_OFF = 10;\r\n\r\n/**\r\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\r\n *\r\n * Growth history, each stage purely additive at the tail with all earlier\r\n * offsets UNCHANGED:\r\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\r\n * @432, `protocol_fee_accrued_atoms` u128 @464,\r\n * `protocol_fee_withdrawn_atoms` u128 @480.\r\n * 496 -> 576 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\r\n * @496/512/528/544, three u16 shares @560/562/564, then\r\n * `_padding_split` [u8;10] @566.\r\n *\r\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\r\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\r\n * it is u128-aligned; placing the u16 shares first would push the u128s to\r\n * offset 502 and force the compiler to insert implicit padding, failing the\r\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\r\n * padding out to the 16-byte alignment boundary.\r\n *\r\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\r\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\r\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\r\n * at line 1159.\r\n *\r\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\r\n * still carries the 496-byte layout. Reading a market created by that build\r\n * with this decoder will throw \"data too short\"; a 576-byte read against a\r\n * 496-byte account is a length error, not a silent misparse.\r\n */\r\nexport const V17_WRAPPER_CONFIG_LEN = 576;\r\n\r\n/**\r\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\r\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\r\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\r\n *\r\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\r\n * `_padding_split` tail at the only 8-aligned slot inside it, so\r\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\r\n * 592, and NO pre-existing offset moves. Growing the config instead would have\r\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\r\n * markets — a repeat of the 496→576 incident. If you ever find yourself\r\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\r\n *\r\n * Source of truth: percolator-prog `src/v16_program.rs` struct\r\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\r\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\r\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\r\n */\r\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\r\n\r\n/** v17 AssetOracleProfileV16 length (400 bytes). */\r\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\r\n\r\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\r\nexport const V17_HEADER_LEN = 16;\r\n\r\n/**\r\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\r\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\r\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\r\n * downstream offset in this file chains off it.\r\n */\r\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\r\n\r\n/**\r\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\r\n * verified against percolator-prog `cargo run --example dump_layout`.\r\n */\r\nexport const V17_MARKET_GROUP_LEN = 758;\r\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\r\n\r\n/**\r\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\r\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\r\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\r\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\r\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\r\n */\r\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\r\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\r\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\r\n }\r\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\r\n}\r\n\r\n/**\r\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\r\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\r\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\r\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\r\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\r\n */\r\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\r\n\r\n/**\r\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\r\n *\r\n * Field offsets follow SBF alignment (u128 align=8, not 16).\r\n * Full offset table (verified against v17 wrapper source v16_program.rs,\r\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\r\n * 0 marketauth [32]\r\n * 32 collateral_mint [32]\r\n * 64 secondary_collateral_mint [32]\r\n * 96 maintenance_fee_per_slot u128\r\n * 112 permissionless_market_init_fee u128\r\n * 128 trade_fee_base_bps u64\r\n * 136 permissionless_resolve_stale_slots u64\r\n * 144 force_close_delay_slots u64\r\n * 152 last_good_oracle_slot u64\r\n * 160 insurance_withdraw_deposit_remaining u128\r\n * 176 insurance_withdraw_max_bps u16\r\n * 178 liquidation_cranker_fee_share_bps u16\r\n * 180 maintenance_cranker_fee_share_bps u16\r\n * 182 backing_trade_fee_bps_long u16\r\n * 184 unit_scale u32\r\n * 188 conf_filter_bps u16\r\n * 190 backing_trade_fee_bps_short u16\r\n * 192 insurance_withdraw_deposits_only u8\r\n * 193 oracle_mode u8\r\n * 194 oracle_leg_count u8\r\n * 195 oracle_leg_flags u8\r\n * 196 invert u8\r\n * 197 _padding0 u8\r\n * 198 free_market_slot_count u16\r\n * 200 insurance_withdraw_cooldown_slots u64\r\n * 208 last_insurance_withdraw_slot u64\r\n * 216 max_staleness_secs u64\r\n * 224 hybrid_soft_stale_slots u64\r\n * 232 mark_ewma_e6 u64\r\n * 240 mark_ewma_last_slot u64\r\n * 248 mark_ewma_halflife_slots u64\r\n * 256 mark_min_fee u64\r\n * 264 oracle_target_price_e6 u64\r\n * 272 oracle_target_publish_time i64\r\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 400 oracle_leg_publish_times [i64;3] (24B)\r\n * 424 backing_trade_fee_policy_count u16\r\n * 426 backing_trade_fee_insurance_share_bps_long u16\r\n * 428 backing_trade_fee_insurance_share_bps_short u16\r\n * 430 fee_redirect_to_market_0_bps u16\r\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\r\n * 432 protocol_fee_authority [32]\r\n * 464 protocol_fee_accrued_atoms u128\r\n * 480 protocol_fee_withdrawn_atoms u128\r\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\r\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\r\n * 496 lp_fee_accrued_atoms u128\r\n * 512 lp_fee_withdrawn_atoms u128\r\n * 528 insurance_reserve_accrued_atoms u128\r\n * 544 insurance_reserve_withdrawn_atoms u128\r\n * 560 creator_share_bps u16\r\n * 562 lp_share_bps u16\r\n * 564 insurance_share_bps u16\r\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\r\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\r\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\r\n * Total: 576\r\n */\r\nexport interface WrapperConfigV17 {\r\n marketauth: PublicKey;\r\n collateralMint: PublicKey;\r\n secondaryCollateralMint: PublicKey;\r\n maintenanceFeePerSlot: bigint;\r\n permissionlessMarketInitFee: bigint;\r\n tradeFeeBps: bigint;\r\n permissionlessResolveStaleSlots: bigint;\r\n forceCloseDelaySlots: bigint;\r\n lastGoodOracleSlot: bigint;\r\n insuranceWithdrawDepositRemaining: bigint;\r\n insuranceWithdrawMaxBps: number;\r\n liquidationCrankerFeeShareBps: number;\r\n maintenanceCrankerFeeShareBps: number;\r\n backingTradeFeeBpsLong: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsShort: number;\r\n insuranceWithdrawDepositsOnly: number;\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n freeMarketSlotCount: number;\r\n insuranceWithdrawCooldownSlots: bigint;\r\n lastInsuranceWithdrawSlot: bigint;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n backingTradeFeePolicyCount: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n feeRedirectToMarket0Bps: number;\r\n /**\r\n * Destination pubkey for the protocol's accrued fee share. Set to a\r\n * hardcoded program-level constant at InitMarket; rotatable only via\r\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\r\n * by marketauth/insurance_authority/any creator-facing gate.\r\n */\r\n protocolFeeAuthority: PublicKey;\r\n /**\r\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\r\n * itself credited into any domain's insurance budget — tracks an\r\n * unbudgeted slice of header.insurance no insurance_operator can reach.\r\n */\r\n protocolFeeAccruedAtoms: bigint;\r\n /**\r\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\r\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\r\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\r\n */\r\n protocolFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\r\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\r\n * principal.\r\n *\r\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\r\n * it can be impaired by backing losses between crank and redemption.\r\n *\r\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\r\n * can never be cranked. Outstanding = accrued - withdrawn.\r\n */\r\n lpFeeAccruedAtoms: bigint;\r\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\r\n lpFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\r\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\r\n * bound stake pool's vault.\r\n *\r\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\r\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\r\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\r\n * unbudgeted by construction. Keepers should crank before resolution.\r\n */\r\n insuranceReserveAccruedAtoms: bigint;\r\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\r\n insuranceReserveWithdrawnAtoms: bigint;\r\n /**\r\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\r\n * (3600). Lands in insurance_domain_budget; claimed via\r\n * WithdrawInsuranceAsset (tag 57).\r\n */\r\n creatorShareBps: number;\r\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\r\n lpShareBps: number;\r\n /**\r\n * Insurance/staker share of T in bps. Default 1600, floor\r\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\r\n * split_trade_fee computes this leg as the remainder.\r\n */\r\n insuranceShareBps: number;\r\n /**\r\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\r\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\r\n *\r\n * This is the honest claimable balance a creator-claim UI should display.\r\n * Before the creator-fee-claim change the creator leg was credited into the\r\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\r\n * had no on-chain representation at all and a claim button was really a\r\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\r\n * alone.\r\n *\r\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\r\n * / insurance legs above, this is a single live balance: trades add to it and\r\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\r\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\r\n * claimable right now. (Forced by the 10-byte pad budget; see\r\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\r\n *\r\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\r\n * were explicit padding, so the value is well-defined rather than garbage,\r\n * and the counter simply accrues fresh after an in-place upgrade.\r\n */\r\n creatorFeeClaimableAtoms: bigint;\r\n}\r\n\r\n/**\r\n * Parse a v17 WrapperConfigV16 block from raw account data.\r\n *\r\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\r\n *\r\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\r\n * This function reads the 496-byte wrapper config block directly. It does NOT\r\n * validate the account header magic or version — callers must do that separately.\r\n *\r\n * @param data Raw bytes of the market group account.\r\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\r\n * @returns Parsed WrapperConfigV17 object.\r\n *\r\n * @example\r\n * ```ts\r\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\r\n * if (!accountInfo) throw new Error(\"account not found\");\r\n * const magic = readU64FromBytes(accountInfo.data, 0);\r\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\r\n * const config = parseWrapperConfigV17(accountInfo.data);\r\n * console.log(config.collateralMint.toBase58());\r\n * ```\r\n */\r\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\r\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = configOff;\r\n\r\n // Offsets from the WrapperConfigV16 offset table above\r\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\r\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\r\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\r\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\r\n const tradeFeeBps = readU64LE(data, b + 128);\r\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\r\n const forceCloseDelaySlots = readU64LE(data, b + 144);\r\n const lastGoodOracleSlot = readU64LE(data, b + 152);\r\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\r\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\r\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\r\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\r\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\r\n const unitScale = readU32LE(data, b + 184);\r\n const confFilterBps = readU16LE(data, b + 188);\r\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\r\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\r\n const oracleMode = readU8(data, b + 193);\r\n const oracleLegCount = readU8(data, b + 194);\r\n const oracleLegFlags = readU8(data, b + 195);\r\n const invert = readU8(data, b + 196);\r\n // _padding0 at b+197\r\n const freeMarketSlotCount = readU16LE(data, b + 198);\r\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\r\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\r\n const maxStalenessSecs = readU64LE(data, b + 216);\r\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\r\n const markEwmaE6 = readU64LE(data, b + 232);\r\n const markEwmaLastSlot = readU64LE(data, b + 240);\r\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\r\n const markMinFee = readU64LE(data, b + 256);\r\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\r\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\r\n\r\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\r\n const ORACLE_LEG_CAP = 3;\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\r\n }\r\n\r\n // oracle_leg_prices_e6: [u64;3] at b+376\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\r\n }\r\n\r\n // oracle_leg_publish_times: [i64;3] at b+400\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\r\n }\r\n\r\n // Tail policy fields at b+424\r\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\r\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\r\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\r\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\r\n\r\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\r\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\r\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\r\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\r\n\r\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\r\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\r\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\r\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\r\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\r\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\r\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\r\n const creatorShareBps = readU16LE(data, b + 560);\r\n const lpShareBps = readU16LE(data, b + 562);\r\n const insuranceShareBps = readU16LE(data, b + 564);\r\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\r\n\r\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\r\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\r\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\r\n\r\n return {\r\n marketauth,\r\n collateralMint,\r\n secondaryCollateralMint,\r\n maintenanceFeePerSlot,\r\n permissionlessMarketInitFee,\r\n tradeFeeBps,\r\n permissionlessResolveStaleSlots,\r\n forceCloseDelaySlots,\r\n lastGoodOracleSlot,\r\n insuranceWithdrawDepositRemaining,\r\n insuranceWithdrawMaxBps,\r\n liquidationCrankerFeeShareBps,\r\n maintenanceCrankerFeeShareBps,\r\n backingTradeFeeBpsLong,\r\n unitScale,\r\n confFilterBps,\r\n backingTradeFeeBpsShort,\r\n insuranceWithdrawDepositsOnly,\r\n oracleMode,\r\n oracleLegCount,\r\n oracleLegFlags,\r\n invert,\r\n freeMarketSlotCount,\r\n insuranceWithdrawCooldownSlots,\r\n lastInsuranceWithdrawSlot,\r\n maxStalenessSecs,\r\n hybridSoftStaleSlots,\r\n markEwmaE6,\r\n markEwmaLastSlot,\r\n markEwmaHalflifeSlots,\r\n markMinFee,\r\n oracleTargetPriceE6,\r\n oracleTargetPublishTime,\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n backingTradeFeePolicyCount,\r\n backingTradeFeeInsuranceShareBpsLong,\r\n backingTradeFeeInsuranceShareBpsShort,\r\n feeRedirectToMarket0Bps,\r\n protocolFeeAuthority,\r\n protocolFeeAccruedAtoms,\r\n protocolFeeWithdrawnAtoms,\r\n lpFeeAccruedAtoms,\r\n lpFeeWithdrawnAtoms,\r\n insuranceReserveAccruedAtoms,\r\n insuranceReserveWithdrawnAtoms,\r\n creatorShareBps,\r\n lpShareBps,\r\n insuranceShareBps,\r\n creatorFeeClaimableAtoms,\r\n };\r\n}\r\n\r\n/**\r\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\r\n *\r\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\r\n * 0 oracle_mode u8\r\n * 1 oracle_leg_count u8\r\n * 2 oracle_leg_flags u8\r\n * 3 invert u8\r\n * 4 unit_scale u32\r\n * 8 conf_filter_bps u16\r\n * 10 backing_trade_fee_bps_long u16\r\n * 12 backing_trade_fee_bps_short u16\r\n * 14 backing_trade_fee_insurance_share_bps_long u16\r\n * 16 backing_trade_fee_insurance_share_bps_short u16\r\n * 18 _padding0 [u8;6]\r\n * 24 insurance_authority [32]\r\n * 56 insurance_operator [32]\r\n * 88 backing_bucket_authority [32]\r\n * 120 oracle_authority [32]\r\n * 152 max_staleness_secs u64\r\n * 160 hybrid_soft_stale_slots u64\r\n * 168 mark_ewma_e6 u64\r\n * 176 mark_ewma_last_slot u64\r\n * 184 mark_ewma_halflife_slots u64\r\n * 192 mark_min_fee u64\r\n * 200 oracle_target_price_e6 u64\r\n * 208 oracle_target_publish_time i64\r\n * 216 last_good_oracle_slot u64\r\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 344 oracle_leg_publish_times [i64;3] (24B)\r\n * 368 asset_admin [32] ← v17 NEW\r\n * Total: 400\r\n */\r\nexport interface AssetOracleProfileV17 {\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsLong: number;\r\n backingTradeFeeBpsShort: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n insuranceAuthority: PublicKey;\r\n insuranceOperator: PublicKey;\r\n backingBucketAuthority: PublicKey;\r\n oracleAuthority: PublicKey;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n lastGoodOracleSlot: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n /** v17 NEW: asset_admin pubkey at offset 368. */\r\n assetAdmin: PublicKey;\r\n}\r\n\r\n/**\r\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\r\n *\r\n * @param data Raw bytes containing the profile block.\r\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\r\n * @returns Parsed AssetOracleProfileV17 object.\r\n */\r\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\r\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = profileOff;\r\n const ORACLE_LEG_CAP = 3;\r\n\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\r\n }\r\n\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\r\n }\r\n\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\r\n }\r\n\r\n return {\r\n oracleMode: readU8(data, b + 0),\r\n oracleLegCount: readU8(data, b + 1),\r\n oracleLegFlags: readU8(data, b + 2),\r\n invert: readU8(data, b + 3),\r\n unitScale: readU32LE(data, b + 4),\r\n confFilterBps: readU16LE(data, b + 8),\r\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\r\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\r\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\r\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\r\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\r\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\r\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\r\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\r\n maxStalenessSecs: readU64LE(data, b + 152),\r\n hybridSoftStaleSlots: readU64LE(data, b + 160),\r\n markEwmaE6: readU64LE(data, b + 168),\r\n markEwmaLastSlot: readU64LE(data, b + 176),\r\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\r\n markMinFee: readU64LE(data, b + 192),\r\n oracleTargetPriceE6: readU64LE(data, b + 200),\r\n oracleTargetPublishTime: readI64LE(data, b + 208),\r\n lastGoodOracleSlot: readU64LE(data, b + 216),\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\r\n };\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer contains a v17 percolator account.\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\r\n */\r\nexport function isV17Account(data: Uint8Array): boolean {\r\n if (data.length < 10) return false;\r\n const magic = readU64LE(data, 0);\r\n const version = readU16LE(data, 8);\r\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer is a v17 percolator MARKET account.\r\n *\r\n * Stricter than {@link isV17Account}: requires both that the account is a valid\r\n * v17 account (magic + version) AND that the kind byte at offset 10 is\r\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\r\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\r\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\r\n */\r\nexport function isV17MarketAccount(data: Uint8Array): boolean {\r\n if (data.length < V17_KIND_OFF + 1) return false;\r\n if (!isV17Account(data)) return false;\r\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\r\n}\r\n\r\n// =============================================================================\r\n// V17 OI parser\r\n// =============================================================================\r\n\r\n/**\r\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\r\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\r\n */\r\nconst V17_HEADER_INSURANCE_OFF = 301;\r\n\r\n/**\r\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\r\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\r\n */\r\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\r\n\r\n/**\r\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\r\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\r\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\r\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\r\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\r\n * oi_eff_short_q follows at 273 + 16 = 289\r\n */\r\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\r\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\r\n\r\n/**\r\n * Aggregated open-interest parsed from a v17 market group account.\r\n *\r\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\r\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\r\n * slots in the account and also returns per-asset breakdown.\r\n *\r\n * All quantities are in token micro-units (raw, not scaled by decimals).\r\n */\r\nexport interface V17MarketGroupOI {\r\n /** Group-level insurance reserve (u128, micro-units) */\r\n insuranceBalance: bigint;\r\n /** Sum of oi_eff_long_q across all asset slots */\r\n totalLongOiQ: bigint;\r\n /** Sum of oi_eff_short_q across all asset slots */\r\n totalShortOiQ: bigint;\r\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\r\n assets: Array<{\r\n assetIndex: number;\r\n oiEffLongQ: bigint;\r\n oiEffShortQ: bigint;\r\n }>;\r\n}\r\n\r\n/**\r\n * Parse open-interest fields from a v17 market group account.\r\n *\r\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\r\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\r\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\r\n * which follows the 512-byte wrapper T at the start of each slot).\r\n *\r\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\r\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\r\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\r\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are exact byte offsets.\r\n *\r\n * The absolute offsets below follow from the CURRENT wrapper layout —\r\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\r\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\r\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\r\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\r\n * - insurance: 592 + 301 = 893\r\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\r\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\r\n *\r\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\r\n * giving insurance @ 813. The CODE was always correct — it composes the named\r\n * constants — but the stated numbers were stale. Verified against the first real\r\n * v17 market on the new devnet deployment.)\r\n *\r\n * @param data Raw bytes of the v17 market group account.\r\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\r\n * @throws Error if the buffer is not a valid v17 market account or is too short.\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketGroupPk);\r\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\r\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\r\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\r\n * ```\r\n */\r\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\r\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\r\n const insuranceBalance = readU128LE(data, insuranceOff);\r\n\r\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\r\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\r\n const numSlots = Math.floor(\r\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\r\n );\r\n\r\n let totalLongOiQ = 0n;\r\n let totalShortOiQ = 0n;\r\n const assets: V17MarketGroupOI[\"assets\"] = [];\r\n\r\n for (let i = 0; i < numSlots; i++) {\r\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\r\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\r\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\r\n const longOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\r\n const shortOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\r\n\r\n // Guard against a truncated buffer (should not happen on well-formed accounts).\r\n if (shortOff + 16 > data.length) break;\r\n\r\n const oiEffLongQ = readU128LE(data, longOff);\r\n const oiEffShortQ = readU128LE(data, shortOff);\r\n\r\n totalLongOiQ += oiEffLongQ;\r\n totalShortOiQ += oiEffShortQ;\r\n\r\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\r\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\r\n }\r\n }\r\n\r\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\r\n}\r\n\r\n// =============================================================================\r\n// V17 account decoders (DESYNC fixes — new standalone account types)\r\n// =============================================================================\r\n\r\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\r\nconst V17_ACCOUNT_HEADER_LEN = 16;\r\nconst V17_KIND_PORTFOLIO = 2;\r\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\r\nconst V17_KIND_LP_REDEMPTION = 6;\r\n\r\nfunction assertV17StandaloneHeader(\r\n data: Uint8Array,\r\n parserName: string,\r\n expectedKind: number,\r\n): void {\r\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\r\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\r\n }\r\n const magic = readU64LE(data, 0);\r\n if (magic !== V17_MAGIC) {\r\n throw new Error(`${parserName}: invalid v17 magic`);\r\n }\r\n const version = readU16LE(data, 8);\r\n if (version !== V17_EXPECTED_VERSION) {\r\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\r\n }\r\n const kind = readU8(data, 10);\r\n if (kind !== expectedKind) {\r\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\r\n }\r\n}\r\n\r\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\r\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\r\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\r\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\r\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\r\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\r\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\r\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\r\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\r\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\r\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\r\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\r\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\r\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\r\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\r\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\r\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\r\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\r\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\r\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\r\n// PortfolioLegV16Account (144 bytes each):\r\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\r\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\r\nconst PF_LEG_SIZE = 144;\r\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\r\nconst PF_LEGS_COUNT = 16;\r\n// PortfolioSourceDomainV16Account (196 bytes each):\r\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\r\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\r\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\r\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\r\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\r\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\r\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\r\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\r\nconst PF_SOURCE_DOMAIN_SIZE = 196;\r\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\r\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\r\n// HealthCertV16Account (121 bytes):\r\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\r\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\r\n// CloseProgressLedgerV16Account (188 bytes):\r\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\r\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\r\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\r\n// ResolvedPayoutReceiptV16Account (66 bytes):\r\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\r\n\r\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\r\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\r\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\r\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\r\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\r\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\r\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\r\n// noted above (188) does not even match its own field breakdown (sums to 184; see\r\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\r\n// the same anchor-from-the-end offset).\r\nconst PF_MATCHER_CONFIG_LEN = 104;\r\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\r\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\r\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\r\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\r\n\r\n/** Per-leg decoded data returned by parsePortfolioV17. */\r\nexport interface PortfolioLegV17 {\r\n active: boolean;\r\n assetIndex: number;\r\n marketId: bigint;\r\n /** 0 = long, 1 = short */\r\n side: number;\r\n basisPosQ: bigint;\r\n aBasis: bigint;\r\n kSnap: bigint;\r\n fSnap: bigint;\r\n epochSnap: bigint;\r\n lossWeight: bigint;\r\n bSnap: bigint;\r\n bRem: bigint;\r\n bEpochSnap: bigint;\r\n bStale: boolean;\r\n stale: boolean;\r\n}\r\n\r\n/** Per source-domain slot returned by parsePortfolioV17. */\r\nexport interface PortfolioSourceDomainV17 {\r\n domain: number;\r\n sourceClaimMarketId: bigint;\r\n sourceClaimBoundNum: bigint;\r\n sourceClaimLienedNum: bigint;\r\n sourceClaimCounterpartyLienedNum: bigint;\r\n sourceClaimInsuranceLienedNum: bigint;\r\n sourceLienEffectiveReserved: bigint;\r\n sourceLienCounterpartyBackingNum: bigint;\r\n sourceLienInsuranceBackingNum: bigint;\r\n sourceLienFeeLastSlot: bigint;\r\n sourceClaimImpairedNum: bigint;\r\n sourceLienImpairedEffectiveReserved: bigint;\r\n sourceLienCapitalAtRiskFeeRevenue: bigint;\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\r\n}\r\n\r\n/** Decoded v17 PortfolioAccountV16Account. */\r\nexport interface PortfolioV17 {\r\n /** Market group this portfolio belongs to. */\r\n marketGroupId: PublicKey;\r\n /** Portfolio account identity pubkey (immutable PDA). */\r\n portfolioAccountId: PublicKey;\r\n /** Owner wallet pubkey from the provenance header. */\r\n provenanceOwner: PublicKey;\r\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\r\n owner: PublicKey;\r\n /** Collateral capital in atoms (u128). */\r\n capital: bigint;\r\n /** Unrealised P&L in atoms (i128). */\r\n pnl: bigint;\r\n /** Capital reserved for pending payout (u128). */\r\n reservedPnl: bigint;\r\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\r\n residualCrystallizedLossAtomsTotal: bigint;\r\n /** Genesis farming: cumulative spent principal atoms (u128). */\r\n residualSpentPrincipalAtomsTotal: bigint;\r\n /** Genesis farming: cumulative received atoms (u128). */\r\n residualReceivedAtomsTotal: bigint;\r\n /** Fee credits (i128, can be negative). */\r\n feeCredits: bigint;\r\n /** Cancel-deposit escrow holding (u128). */\r\n cancelDepositEscrow: bigint;\r\n /** Slot when fees were last accrued. */\r\n lastFeeSlot: bigint;\r\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\r\n activeBitmap: bigint;\r\n /** All 16 position leg slots (active or empty). */\r\n legs: PortfolioLegV17[];\r\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\r\n sourceDomains: PortfolioSourceDomainV17[];\r\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\r\n matcherProgram: PublicKey;\r\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\r\n matcherContext: PublicKey;\r\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\r\n matcherDelegate: PublicKey;\r\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\r\n matcherEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Parse a v17 PortfolioAccountV16Account from raw account data.\r\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\r\n *\r\n * @param data - Raw account bytes from `connection.getAccountInfo`.\r\n * @returns Decoded portfolio state.\r\n * @throws If data is too short or magic does not match.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(portfolioPubkey);\r\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\r\n * console.log('capital:', portfolio.capital);\r\n * ```\r\n */\r\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\r\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\r\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\r\n if (data.length < MIN_PORTFOLIO_BYTES) {\r\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\r\n }\r\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\r\n\r\n // Provenance header\r\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\r\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\r\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\r\n\r\n // Body fields\r\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\r\n const capital = readU128LE(data, PF_CAPITAL_OFF);\r\n const pnl = readI128LE(data, PF_PNL_OFF);\r\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\r\n\r\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\r\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\r\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\r\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\r\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\r\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\r\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\r\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\r\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\r\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\r\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\r\n\r\n // Legs\r\n const legs: PortfolioLegV17[] = [];\r\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\r\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\r\n if (data.length < b + PF_LEG_SIZE) break;\r\n legs.push({\r\n active: data[b] !== 0,\r\n assetIndex: readU32LE(data, b + 1),\r\n marketId: readU64LE(data, b + 5),\r\n side: data[b + 13],\r\n basisPosQ: readI128LE(data, b + 14),\r\n aBasis: readU128LE(data, b + 30),\r\n kSnap: readI128LE(data, b + 46),\r\n fSnap: readI128LE(data, b + 62),\r\n epochSnap: readU64LE(data, b + 78),\r\n lossWeight: readU128LE(data, b + 86),\r\n bSnap: readU128LE(data, b + 102),\r\n bRem: readU128LE(data, b + 118),\r\n bEpochSnap: readU64LE(data, b + 134),\r\n bStale: data[b + 142] !== 0,\r\n stale: data[b + 143] !== 0,\r\n });\r\n }\r\n\r\n // Source domains\r\n const sourceDomains: PortfolioSourceDomainV17[] = [];\r\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\r\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\r\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\r\n sourceDomains.push({\r\n domain: readU32LE(data, b + 0),\r\n sourceClaimMarketId: readU64LE(data, b + 4),\r\n sourceClaimBoundNum: readU128LE(data, b + 12),\r\n sourceClaimLienedNum: readU128LE(data, b + 28),\r\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\r\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\r\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\r\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\r\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\r\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\r\n sourceClaimImpairedNum: readU128LE(data, b + 132),\r\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\r\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\r\n });\r\n }\r\n\r\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\r\n : PublicKey.default;\r\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\r\n : PublicKey.default;\r\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\r\n : PublicKey.default;\r\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\r\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\r\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\r\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\r\n // for an account the program itself would refuse to operate on.\r\n let matcherEnabled = false;\r\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\r\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\r\n if (rawEnabled > 1n) {\r\n throw new Error(\r\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\r\n );\r\n }\r\n matcherEnabled = rawEnabled === 1n;\r\n }\r\n\r\n return {\r\n marketGroupId,\r\n portfolioAccountId,\r\n provenanceOwner,\r\n owner,\r\n capital,\r\n pnl,\r\n reservedPnl,\r\n residualCrystallizedLossAtomsTotal,\r\n residualSpentPrincipalAtomsTotal,\r\n residualReceivedAtomsTotal,\r\n feeCredits,\r\n cancelDepositEscrow,\r\n lastFeeSlot,\r\n activeBitmap,\r\n legs,\r\n sourceDomains,\r\n matcherProgram,\r\n matcherContext,\r\n matcherDelegate,\r\n matcherEnabled,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpVaultRegistryV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\r\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\r\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\r\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\r\n// _padding[6]+_reserved[16] = 160 bytes.\r\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\r\n\r\n/** Decoded v17 LpVaultRegistryV16 account. */\r\nexport interface LpVaultRegistryV17 {\r\n marketGroup: PublicKey;\r\n lpMint: PublicKey;\r\n totalLpSharesOutstanding: bigint;\r\n insuranceFeeSnapshotAtoms: bigint;\r\n feeDistributionTotalAtoms: bigint;\r\n epoch: bigint;\r\n redemptionCooldownSlots: bigint;\r\n feeShareBps: number;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n paused: boolean;\r\n version: number;\r\n bump: number;\r\n mintBump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\r\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP vault registry state.\r\n * @throws If data is shorter than 176 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(registryPubkey);\r\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\r\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\r\n * ```\r\n */\r\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\r\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\r\n throw new Error(\r\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\r\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\r\n totalLpSharesOutstanding: readU128LE(data, b + 64),\r\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\r\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\r\n epoch: readU64LE(data, b + 112),\r\n redemptionCooldownSlots: readU64LE(data, b + 120),\r\n feeShareBps: readU16LE(data, b + 128),\r\n oiReservationThresholdBps: readU16LE(data, b + 130),\r\n domain: readU16LE(data, b + 132),\r\n paused: data[b + 134] !== 0,\r\n version: data[b + 135],\r\n bump: data[b + 136],\r\n mintBump: data[b + 137],\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpRedemptionV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\r\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\r\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\r\n\r\n/** Decoded v17 LpRedemptionV16 account. */\r\nexport interface LpRedemptionV17 {\r\n registry: PublicKey;\r\n redeemer: PublicKey;\r\n /** LP shares requested for redemption (u128). */\r\n shares: bigint;\r\n /** Slot when RequestRedeemLpShares was called. */\r\n requestSlot: bigint;\r\n version: number;\r\n bump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpRedemptionV16 account from raw bytes.\r\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP redemption request state.\r\n * @throws If data is shorter than 112 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(redemptionPubkey);\r\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\r\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\r\n * ```\r\n */\r\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\r\n if (data.length < LP_REDEMPTION_TOTAL) {\r\n throw new Error(\r\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\r\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\r\n shares: readU128LE(data, b + 64),\r\n requestSlot: readU64LE(data, b + 80),\r\n version: data[b + 88],\r\n bump: data[b + 89],\r\n };\r\n}\r\n\r\n/**\r\n * Parse all used accounts.\r\n */\r\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\r\n const indices = parseUsedIndices(data);\r\n const maxIdx = maxAccountIndex(data.length);\r\n const validIndices = indices.filter(idx => idx < maxIdx);\r\n const droppedCount = indices.length - validIndices.length;\r\n if (droppedCount > 0) {\r\n console.warn(\r\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\r\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\r\n );\r\n }\r\n return validIndices.map(idx => ({\r\n idx,\r\n account: parseAccount(data, idx),\r\n }));\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Encode a u16 as a 2-byte little-endian buffer.\r\n * Used for PDA seed segments that include a domain/index as u16 LE.\r\n */\r\nfunction u16LE(value: number): Uint8Array {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isInteger(value) ||\r\n value < 0 ||\r\n value > 0xffff\r\n ) {\r\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive vault authority PDA.\r\n * Seeds: [\"vault\", slab_key]\r\n *\r\n * Mirrors `derive_vault_authority(program_id, market_key)` in\r\n * `percolator-prog/src/v16_program.rs:17339-17341`.\r\n */\r\nexport function deriveVaultAuthority(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"vault\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * SPL Associated Token Account program.\r\n *\r\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\r\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\r\n */\r\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\r\n);\r\n\r\n/**\r\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\r\n *\r\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\r\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\r\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\r\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\r\n * ATA's middle seed is always this program id.\r\n */\r\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n);\r\n\r\n/**\r\n * Derive the CANONICAL vault token account for a market + collateral mint.\r\n *\r\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\r\n *\r\n * ```text\r\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\r\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\r\n * ```\r\n *\r\n * Mirrors `canonical_vault_address(vault_authority, mint)`\r\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\r\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\r\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\r\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\r\n * without it an attacker could route deposits to a second `vault_authority`-owned account\r\n * and strand honest withdrawals against the canonical one.\r\n *\r\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\r\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\r\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\r\n * address with a detected token program would produce a key the program rejects with\r\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\r\n *\r\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\r\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\r\n * token path.\r\n *\r\n * @param programId - The Percolator wrapper program ID (the market's owner).\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\r\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketData);\r\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * ```\r\n */\r\nexport function deriveCanonicalVault(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\r\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\r\n}\r\n\r\n/**\r\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\r\n *\r\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\r\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\r\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\r\n *\r\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\r\n * @param mint - The market's collateral mint.\r\n * @returns `[vaultTokenAccount, bump]`\r\n *\r\n * @example\r\n * ```ts\r\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\r\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\r\n * ```\r\n */\r\nexport function deriveCanonicalVaultForAuthority(\r\n vaultAuthority: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n vaultAuthority.toBytes(),\r\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n ASSOCIATED_TOKEN_PROGRAM_ID\r\n );\r\n}\r\n\r\n/** Both halves of a market's vault, as required by tags 84 and 87. */\r\nexport interface MarketVaultAccounts {\r\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\r\n vaultAuthority: PublicKey;\r\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\r\n vaultAuthorityBump: number;\r\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\r\n vaultToken: PublicKey;\r\n /** Bump for `vaultToken`. */\r\n vaultTokenBump: number;\r\n /** The token program that must be passed alongside — always legacy SPL Token. */\r\n tokenProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\r\n *\r\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\r\n * the vault token account, the vault authority PDA and the token program as three separate\r\n * accounts that must agree with one another; deriving them together makes disagreement\r\n * impossible.\r\n *\r\n * Account positions:\r\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\r\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\r\n *\r\n * @param programId - The Percolator wrapper program ID.\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint.\r\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\r\n *\r\n * @example\r\n * ```ts\r\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * const keys = [\r\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\r\n * { pubkey: marketPk, isSigner: false, isWritable: true },\r\n * { pubkey: destToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\r\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\r\n * ];\r\n * ```\r\n */\r\nexport function deriveMarketVaultAccounts(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): MarketVaultAccounts {\r\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\r\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\r\n vaultAuthority,\r\n mint\r\n );\r\n return {\r\n vaultAuthority,\r\n vaultAuthorityBump,\r\n vaultToken,\r\n vaultTokenBump,\r\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\r\n };\r\n}\r\n\r\n/**\r\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\r\n * Seeds: [\"lp_vault_mint\", slab_key]\r\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\r\n */\r\nexport function deriveInsuranceLpMint(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\nconst LP_INDEX_U16_MAX = 0xffff;\r\n\r\n/**\r\n * Derive LP PDA for TradeCpi.\r\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\r\n */\r\nexport function deriveLpPda(\r\n programId: PublicKey,\r\n slab: PublicKey,\r\n lpIdx: number\r\n): [PublicKey, number] {\r\n if (\r\n typeof lpIdx !== \"number\" ||\r\n !Number.isInteger(lpIdx) ||\r\n lpIdx < 0 ||\r\n lpIdx > LP_INDEX_U16_MAX\r\n ) {\r\n throw new Error(\r\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\r\n );\r\n }\r\n const idxBuf = new Uint8Array(2);\r\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DEX Program IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/** PumpSwap AMM program ID. */\r\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\r\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\r\n);\r\n\r\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\r\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\r\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\r\n);\r\n\r\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\r\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\r\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth Push Oracle\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Pyth Push Oracle program on mainnet. */\r\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\r\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Creator Lock PDA (PERC-627)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Seed used to derive the creator lock PDA.\r\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\r\n */\r\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\r\n\r\n/**\r\n * Derive the creator lock PDA for a given slab.\r\n * Seeds: [\"creator_lock\", slab_key]\r\n *\r\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\r\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\r\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\r\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\r\n *\r\n * @param programId - The percolator program ID.\r\n * @param slab - The slab (market) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * ```\r\n */\r\nexport function deriveCreatorLockPda(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// LP Vault PDAs (v17 — tags 74-80)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the LP Vault registry PDA.\r\n * Seeds: [\"lp_vault\", marketGroup]\r\n *\r\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\r\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\r\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\r\n *\r\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpVaultRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP redemption ticket PDA for a specific redeemer.\r\n * Seeds: [\"lp_redemption\", registry, redeemer]\r\n *\r\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\r\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\r\n * @param redeemer - The wallet public key of the redeemer.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\r\n * ```\r\n */\r\nexport function deriveLpRedemption(\r\n programId: PublicKey,\r\n registry: PublicKey,\r\n redeemer: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_redemption\"),\r\n registry.toBytes(),\r\n redeemer.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP backing-domain ledger PDA.\r\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\r\n *\r\n * Required by: DepositToLpVault (tag 75) at accounts[7],\r\n * LpVaultCrankFees (tag 78) at accounts[3].\r\n *\r\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\r\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\r\n * (line 3127) — domain is encoded as 2-byte little-endian.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\r\n * ```\r\n */\r\nexport function deriveLpBackingLedger(\r\n programId: PublicKey,\r\n marketGroup: PublicKey,\r\n domainIdx: number\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_backing_ledger\"),\r\n marketGroup.toBytes(),\r\n u16LE(domainIdx),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP escrow SPL token account PDA.\r\n * Seeds: [\"lp_escrow\", marketGroup]\r\n *\r\n * The escrow is owned by the registry PDA and holds LP tokens during the\r\n * redemption window. Required by ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\r\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpEscrow(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NFT Registry PDA (v17 — tag 73)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the per-market NFT program-id registry PDA.\r\n * Seeds: [\"nft_registry\", marketGroup]\r\n *\r\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\r\n * (TransferPortfolioOwnership, tag 72).\r\n *\r\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\r\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveNftRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the matcher delegate PDA.\r\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\r\n * (all six seed segments are 32-byte public keys)\r\n *\r\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\r\n * The program signs CPI calls to the external matcher program using this PDA.\r\n *\r\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\r\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param market - The market (slab) public key.\r\n * @param accountB - The maker/LP portfolio account public key.\r\n * @param accountBOwner - The owner of accountB.\r\n * @param matcherProg - The external matcher program public key.\r\n * @param matcherCtx - The matcher context account public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [delegatePda] = deriveMatcherDelegate(\r\n * PROGRAM_ID,\r\n * marketKey,\r\n * accountBKey,\r\n * accountBOwnerKey,\r\n * matcherProgKey,\r\n * matcherCtxKey,\r\n * );\r\n * ```\r\n */\r\nexport function deriveMatcherDelegate(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n accountB: PublicKey,\r\n accountBOwner: PublicKey,\r\n matcherProg: PublicKey,\r\n matcherCtx: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"matcher\"),\r\n market.toBytes(),\r\n accountB.toBytes(),\r\n accountBOwner.toBytes(),\r\n matcherProg.toBytes(),\r\n matcherCtx.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\r\nconst PYTH_FEED_ID_HEX_LEN = 64;\r\n\r\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\r\n let s = feedIdHex.trim();\r\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\r\n s = s.slice(2);\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Derive the Pyth Push Oracle PDA for a given feed ID.\r\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\r\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\r\n */\r\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\r\n const normalized = normalizePythFeedIdHex(feedIdHex);\r\n if (!FEED_HEX_RE.test(normalized)) {\r\n throw new Error(\r\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\r\n }\r\n const feedId = new Uint8Array(32);\r\n for (let i = 0; i < 32; i++) {\r\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\r\n }\r\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\r\n return PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n PYTH_PUSH_ORACLE_PROGRAM_ID,\r\n );\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n getAssociatedTokenAddress,\r\n getAssociatedTokenAddressSync,\r\n getAccount,\r\n Account,\r\n TOKEN_PROGRAM_ID,\r\n} from \"@solana/spl-token\";\r\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\r\n\r\n/**\r\n * Get the associated token address for an owner and mint.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport async function getAta(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Synchronous version of getAta.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport function getAtaSync(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): PublicKey {\r\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Fetch token account info.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n * Throws if account doesn't exist.\r\n */\r\nexport async function fetchTokenAccount(\r\n connection: Connection,\r\n address: PublicKey,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAccount(connection, address, undefined, tokenProgramId);\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n parseHeader,\r\n parseConfig,\r\n parseParams,\r\n detectSlabLayout,\r\n isV17MarketAccount,\r\n parseWrapperConfigV17,\r\n SLAB_TIERS_V1M,\r\n SLAB_TIERS_V1M2,\r\n SLAB_TIERS_V2,\r\n SLAB_TIERS_V_ADL,\r\n SLAB_TIERS_V12_1,\r\n SLAB_TIERS_V12_15,\r\n SLAB_TIERS_V12_17,\r\n SLAB_TIERS_V12_19,\r\n SLAB_TIERS_V_SETDEXPOOL,\r\n type SlabHeader,\r\n type MarketConfig,\r\n type EngineState,\r\n type RiskParams,\r\n type SlabLayout,\r\n type WrapperConfigV17,\r\n} from \"./slab.js\";\r\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\r\nimport { type Network } from \"../config/program-ids.js\";\r\n\r\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\r\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\r\n/** V0 bitmap offset within engine struct (deployed devnet program) */\r\nconst ENGINE_BITMAP_OFF_V0 = 320;\r\n\r\n/**\r\n * A discovered Percolator market from on-chain program accounts.\r\n */\r\nexport interface DiscoveredMarket {\r\n slabAddress: PublicKey;\r\n /** The program that owns this slab account */\r\n programId: PublicKey;\r\n /**\r\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\r\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\r\n */\r\n header: SlabHeader;\r\n /**\r\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\r\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\r\n */\r\n config: MarketConfig;\r\n /**\r\n * v12.x engine state (bitmap, account counts).\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n engine: EngineState;\r\n /**\r\n * v12.x risk parameters.\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n params: RiskParams;\r\n /**\r\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\r\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\r\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\r\n * Absent for v12 slab accounts.\r\n *\r\n * Use `isV17Market(m)` to narrow the type:\r\n * ```ts\r\n * if (m.configV17) {\r\n * console.log(m.configV17.collateralMint.toBase58());\r\n * }\r\n * ```\r\n */\r\n configV17?: WrapperConfigV17;\r\n}\r\n\r\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\r\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\r\n * These are the first 8 bytes of every v17 percolator-owned market group account.\r\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\r\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\r\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\r\n */\r\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\r\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\r\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\r\n *\r\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\r\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\r\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\r\n *\r\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\r\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\r\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\r\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\r\n *\r\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\r\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\r\n * See GH #1109, GH #1112.\r\n *\r\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\r\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\r\n */\r\n/**\r\n * Default slab tiers for the current mainnet program (v12.17).\r\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\r\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\r\n */\r\nexport const SLAB_TIERS = {\r\n small: SLAB_TIERS_V12_17[\"small\"],\r\n medium: SLAB_TIERS_V12_17[\"medium\"],\r\n large: SLAB_TIERS_V12_17[\"large\"],\r\n} as const;\r\n\r\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\r\nexport const SLAB_TIERS_V0 = {\r\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\r\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\r\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\r\n} as const;\r\n\r\n/**\r\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\r\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\r\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\r\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\r\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\r\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\r\n * micro = 17,064 (64 slots)\r\n * small = 65,088 (256 slots)\r\n * medium = 257,184 (1,024 slots)\r\n * large = 1,025,568 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D = {\r\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\r\n} as const;\r\n\r\n/**\r\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\r\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\r\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\r\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\r\n * micro = 17,080 (64 slots)\r\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\r\n * medium = 257,200 (1,024 slots)\r\n * large = 1,025,584 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D_LEGACY = {\r\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\r\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\r\n} as const;\r\n\r\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\r\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\r\n */\r\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\r\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\r\n\r\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\r\n\r\n/** Calculate slab data size for arbitrary account count.\r\n *\r\n * Layout (SBF, u128 align = 8):\r\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\r\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\r\n * + bitmap: ceil(N/64)*8\r\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\r\n * + next_free: N*2\r\n * + pad to 8-byte alignment for Account array\r\n * + accounts: N*248\r\n *\r\n * Must match the on-chain program's SLAB_LEN exactly.\r\n */\r\nexport function slabDataSize(maxAccounts: number): number {\r\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\r\n const ENGINE_OFF_V0 = 480;\r\n const ENGINE_BITMAP_OFF_V0 = 320;\r\n const ACCOUNT_SIZE_V0 = 240;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\r\n}\r\n\r\n/**\r\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\r\n *\r\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\r\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\r\n * difference at high account counts or a post-PERC-118 struct addition in the\r\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\r\n * verified on-chain) over this formula for production use.\r\n */\r\nexport function slabDataSizeV1(maxAccounts: number): number {\r\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\r\n const ENGINE_BITMAP_OFF_V1 = 656;\r\n const ACCOUNT_SIZE_V1 = 248;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\r\n}\r\n\r\n/**\r\n * Validate that a slab data size matches one of the known tier sizes.\r\n * Use this to catch tier↔program mismatches early (PERC-277).\r\n *\r\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\r\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\r\n * @returns true if sizes match, false if there's a mismatch\r\n */\r\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\r\n return dataSize === programSlabLen;\r\n}\r\n\r\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\r\nconst ALL_SLAB_SIZES = [\r\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\r\n];\r\n\r\n/** Legacy constant for backward compat */\r\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\r\n\r\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\r\nconst HEADER_SLICE_LENGTH = 1940;\r\n\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\r\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\r\n *\r\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\r\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\r\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\r\n */\r\nexport function parseEngineLight(\r\n data: Uint8Array,\r\n layout: SlabLayout | null,\r\n maxAccounts: number = 4096,\r\n): EngineState {\r\n const isV0 = !layout || layout.version === 0;\r\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\r\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\r\n\r\n const minLen = base + bitmapOff;\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\r\n }\r\n\r\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\r\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\r\n\r\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\r\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\r\n\r\n if (isV0) {\r\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\r\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\r\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\r\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\r\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\r\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\r\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\r\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: readU128LE(data, base + 32),\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + 104),\r\n fundingIndexQpbE6: readI128LE(data, base + 112),\r\n lastFundingSlot: readU64LE(data, base + 128),\r\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: readU64LE(data, base + 144),\r\n maxCrankStalenessSlots: readU64LE(data, base + 152),\r\n totalOpenInterest: readU128LE(data, base + 160),\r\n longOi: 0n,\r\n shortOi: 0n,\r\n cTot: readU128LE(data, base + 176),\r\n pnlPosTot: readU128LE(data, base + 192),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: readU16LE(data, base + 208),\r\n gcCursor: readU16LE(data, base + 210),\r\n lastSweepStartSlot: readU64LE(data, base + 216),\r\n lastSweepCompleteSlot: readU64LE(data, base + 224),\r\n crankCursor: readU16LE(data, base + 232),\r\n sweepStartIdx: readU16LE(data, base + 234),\r\n lifetimeLiquidations: readU64LE(data, base + 240),\r\n lifetimeForceCloses: readU64LE(data, base + 248),\r\n netLpPos: readI128LE(data, base + 256),\r\n lpSumAbs: readU128LE(data, base + 272),\r\n lpMaxAbs: readU128LE(data, base + 288),\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n, // V0 engine has no mark_price field\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\r\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\r\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\r\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\r\n // (the currently-deployed mainnet tier line) were being routed through this branch's\r\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\r\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\r\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\r\n // per the layout-driven branch's own comment below, which already documents that it\r\n // covers V12_15/17/19 — that was the intended path all along.\r\n\r\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\r\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\r\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\r\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\r\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\r\n // that share engineOff=640 but have different internal struct sizes.\r\n if (layout !== null) {\r\n const l = layout;\r\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\r\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\r\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\r\n // struct for that tier has no such field, and `base + (-1)` would read\r\n // garbage straddling the byte before the engine region rather than failing.\r\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\r\n // below goes through these instead of reading the offset directly.\r\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\r\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\r\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\r\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\r\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + l.engineInsuranceOff),\r\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\r\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\r\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\r\n },\r\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\r\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\r\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\r\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\r\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\r\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\r\n : readI128LE(data, base + l.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\r\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\r\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\r\n totalOpenInterest: u128At(l.engineTotalOiOff),\r\n longOi: u128At(l.engineLongOiOff),\r\n shortOi: u128At(l.engineShortOiOff),\r\n cTot: readU128LE(data, base + l.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: u16At(l.engineLiqCursorOff),\r\n gcCursor: u16At(l.engineGcCursorOff),\r\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\r\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\r\n crankCursor: u16At(l.engineCrankCursorOff),\r\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\r\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\r\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\r\n netLpPos: i128At(l.engineNetLpPosOff),\r\n lpSumAbs: u128At(l.engineLpSumAbsOff),\r\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\r\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\r\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\r\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\r\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\r\n markPriceE6: u64At(l.engineMarkPriceOff),\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // layout === null: unrecognized slab format — callers should have skipped via the\r\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\r\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\r\n}\r\n\r\n/** Options for `discoverMarkets`. */\r\nexport interface DiscoverMarketsOptions {\r\n /**\r\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\r\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\r\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\r\n * Default: false (preserves original parallel behaviour).\r\n *\r\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\r\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\r\n */\r\n sequential?: boolean;\r\n /**\r\n * Delay in ms between sequential tier queries (only used when sequential=true).\r\n * Default: 200 ms.\r\n */\r\n interTierDelayMs?: number;\r\n /**\r\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\r\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\r\n */\r\n rateLimitBackoffMs?: number[];\r\n\r\n /**\r\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\r\n * at once to avoid accidental RPC storms from client code.\r\n *\r\n * Default: 6\r\n */\r\n maxParallelTiers?: number;\r\n\r\n /**\r\n * Hard cap on how many tier dataSize queries are attempted.\r\n * Default: all known tiers.\r\n */\r\n maxTierQueries?: number;\r\n\r\n /**\r\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\r\n *\r\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\r\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\r\n * mainnet RPCs that reject `getProgramAccounts`).\r\n *\r\n * The API returns slab addresses which are then fetched on-chain via\r\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\r\n *\r\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * });\r\n * ```\r\n */\r\n apiBaseUrl?: string;\r\n\r\n /**\r\n * Timeout in ms for the API fallback HTTP request.\r\n * Only used when `apiBaseUrl` is set.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n apiTimeoutMs?: number;\r\n\r\n /**\r\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\r\n *\r\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\r\n * `discoverMarkets` will fall back to a bundled static list of known slab\r\n * addresses for the specified network. The addresses are fetched on-chain\r\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * If not set, tier-3 fallback is disabled.\r\n *\r\n * The static list can be extended at runtime via `registerStaticMarkets()`.\r\n *\r\n * @see {@link registerStaticMarkets} to add addresses at runtime\r\n * @see {@link getStaticMarkets} to inspect the current static list\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * network: \"mainnet\", // enables tier-3 static fallback\r\n * });\r\n * ```\r\n */\r\n network?: Network;\r\n}\r\n\r\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\r\nfunction isRateLimitError(err: unknown): boolean {\r\n if (!err) return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return (\r\n msg.includes(\"429\") ||\r\n msg.toLowerCase().includes(\"rate limit\") ||\r\n msg.toLowerCase().includes(\"too many requests\")\r\n );\r\n}\r\n\r\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\r\nfunction withJitter(delayMs: number): number {\r\n const half = Math.floor(delayMs / 2);\r\n return half + Math.floor(Math.random() * (delayMs - half + 1));\r\n}\r\n\r\n/**\r\n * Discover all Percolator markets owned by the given program.\r\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\r\n *\r\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\r\n */\r\nexport async function discoverMarkets(\r\n connection: Connection,\r\n programId: PublicKey,\r\n options: DiscoverMarketsOptions = {},\r\n): Promise {\r\n const {\r\n sequential = false,\r\n interTierDelayMs = 200,\r\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\r\n maxParallelTiers = 6,\r\n } = options;\r\n\r\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\r\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\r\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\r\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\r\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\r\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\r\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\r\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\r\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\r\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\r\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\r\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\r\n //\r\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\r\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\r\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\r\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\r\n const ALL_TIERS_RAW = [\r\n ...Object.values(SLAB_TIERS), // v12.17 (default)\r\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\r\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\r\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\r\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\r\n ...Object.values(SLAB_TIERS_V0),\r\n ...Object.values(SLAB_TIERS_V1D),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\r\n ...Object.values(SLAB_TIERS_V2),\r\n ...Object.values(SLAB_TIERS_V1M),\r\n ...Object.values(SLAB_TIERS_V1M2),\r\n ...Object.values(SLAB_TIERS_V_ADL),\r\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\r\n ];\r\n const tierBySize = new Map();\r\n for (const tier of ALL_TIERS_RAW) {\r\n const existing = tierBySize.get(tier.dataSize);\r\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\r\n tierBySize.set(tier.dataSize, tier);\r\n }\r\n }\r\n const ALL_TIERS = [...tierBySize.values()];\r\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\r\n let rawAccounts: RawEntry[] = [];\r\n\r\n /**\r\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\r\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\r\n */\r\n async function fetchTierWithRetry(\r\n tier: { dataSize: number; maxAccounts: number },\r\n ): Promise {\r\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\r\n try {\r\n const results = await connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\r\n } catch (err) {\r\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\r\n const delay = withJitter(rateLimitBackoffMs[attempt]);\r\n console.warn(\r\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\r\n );\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n // Non-429 or exhausted retries\r\n console.warn(\r\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n return [];\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\r\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\r\n\r\n // Avoid accidental `0`/negative or NaN causing infinite loops.\r\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\r\n\r\n try {\r\n if (sequential) {\r\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\r\n for (let i = 0; i < tiersToQuery.length; i++) {\r\n const tier = tiersToQuery[i];\r\n const entries = await fetchTierWithRetry(tier);\r\n rawAccounts.push(...entries);\r\n if (i < tiersToQuery.length - 1) {\r\n await new Promise(r => setTimeout(r, interTierDelayMs));\r\n }\r\n }\r\n } else {\r\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\r\n // getProgramAccounts calls at once from a single client call.\r\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\r\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\r\n const queries = chunk.map(tier =>\r\n connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n }).then(results =>\r\n results.map(entry => ({\r\n ...entry,\r\n maxAccounts: tier.maxAccounts,\r\n dataSize: tier.dataSize,\r\n })),\r\n ),\r\n );\r\n\r\n const results = await Promise.allSettled(queries);\r\n for (const result of results) {\r\n if (result.status === \"fulfilled\") {\r\n for (const entry of result.value) {\r\n rawAccounts.push(entry as RawEntry);\r\n }\r\n } else {\r\n console.warn(\r\n \"[discoverMarkets] Tier query rejected:\",\r\n result.reason instanceof Error ? result.reason.message : result.reason,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\r\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\r\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\r\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\r\n try {\r\n const v17Results = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\r\n encoding: \"base64\",\r\n },\r\n },\r\n ],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n for (const e of v17Results) {\r\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\r\n }\r\n } catch {\r\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\r\n }\r\n\r\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\r\n // account size changed; RPC returns no error, so we must fallback on empty results too.\r\n if (rawAccounts.length === 0) {\r\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\r\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\r\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\r\n err instanceof Error ? err.message : err,\r\n );\r\n try {\r\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n } catch (memcmpErr) {\r\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\r\n console.warn(\r\n \"[discoverMarkets] memcmp fallback also failed:\",\r\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\r\n );\r\n }\r\n }\r\n\r\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\r\n // rejects it) and an API base URL is configured, fall back to the REST API to\r\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\r\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\r\n console.warn(\r\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\r\n );\r\n try {\r\n const apiResult = await discoverMarketsViaApi(\r\n connection,\r\n programId,\r\n options.apiBaseUrl,\r\n { timeoutMs: options.apiTimeoutMs },\r\n );\r\n if (apiResult.length > 0) {\r\n return apiResult;\r\n }\r\n // API returned 0 markets — fall through to tier 3\r\n console.warn(\r\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\r\n );\r\n } catch (apiErr) {\r\n console.warn(\r\n \"[discoverMarkets] API fallback also failed:\",\r\n apiErr instanceof Error ? apiErr.message : apiErr,\r\n );\r\n // Fall through to tier 3\r\n }\r\n }\r\n\r\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\r\n // the REST API failed (or returned 0 results) and a network hint is provided,\r\n // use the bundled static market list as a last-resort address directory.\r\n if (rawAccounts.length === 0 && options.network) {\r\n const staticEntries = getStaticMarkets(options.network);\r\n if (staticEntries.length > 0) {\r\n console.warn(\r\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\r\n );\r\n try {\r\n return await discoverMarketsViaStaticBundle(\r\n connection,\r\n programId,\r\n staticEntries,\r\n );\r\n } catch (staticErr) {\r\n console.warn(\r\n \"[discoverMarkets] Static bundle fallback also failed:\",\r\n staticErr instanceof Error ? staticErr.message : staticErr,\r\n );\r\n // Fall through to return empty array\r\n }\r\n } else {\r\n console.warn(\r\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\r\n );\r\n }\r\n }\r\n\r\n const accounts = rawAccounts;\r\n\r\n const markets: DiscoveredMarket[] = [];\r\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\r\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\r\n const seenPubkeys = new Set();\r\n\r\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\r\n const pkStr = pubkey.toBase58();\r\n if (seenPubkeys.has(pkStr)) continue;\r\n seenPubkeys.add(pkStr);\r\n const data = new Uint8Array(account.data);\r\n\r\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\r\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\r\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\r\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\r\n // memcmp fallback or if the account happens to match a tier size by coincidence.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\r\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\r\n // — are not mis-parsed as markets.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) continue;\r\n\r\n // Detect layout from actual slab size — not slice length — so parse functions\r\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\r\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\r\n const layout = detectSlabLayout(dataSize, data);\r\n\r\n if (!layout) {\r\n console.warn(\r\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n/**\r\n * Options for `getMarketsByAddress`.\r\n */\r\nexport interface GetMarketsByAddressOptions {\r\n /**\r\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\r\n * Solana limits a single call to 100 accounts; callers may lower this\r\n * to reduce per-request payload size or avoid 429s.\r\n *\r\n * Default: 100 (Solana maximum).\r\n */\r\n batchSize?: number;\r\n\r\n /**\r\n * Delay in ms between batches when the address list exceeds `batchSize`.\r\n * Helps avoid rate-limiting on public RPCs.\r\n *\r\n * Default: 0 (no delay).\r\n */\r\n interBatchDelayMs?: number;\r\n}\r\n\r\n/**\r\n * Fetch and parse Percolator markets by their known slab addresses.\r\n *\r\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\r\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\r\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\r\n *\r\n * Callers must already know the market slab addresses (e.g. from an indexer,\r\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param programId - The Percolator program that owns these slabs\r\n * @param addresses - Array of slab account public keys to fetch\r\n * @param options - Optional batching/delay configuration\r\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection, PublicKey } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const slabs = [\r\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n * // ... more known slab addresses\r\n * ];\r\n *\r\n * const markets = await getMarketsByAddress(connection, programId, slabs);\r\n * console.log(`Found ${markets.length} markets`);\r\n * ```\r\n */\r\nexport async function getMarketsByAddress(\r\n connection: Connection,\r\n programId: PublicKey,\r\n addresses: PublicKey[],\r\n options: GetMarketsByAddressOptions = {},\r\n): Promise {\r\n if (addresses.length === 0) return [];\r\n\r\n const {\r\n batchSize = 100,\r\n interBatchDelayMs = 0,\r\n } = options;\r\n\r\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\r\n\r\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\r\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\r\n const fetched: AccountResult[] = [];\r\n\r\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\r\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\r\n\r\n const response = await connection.getMultipleAccountsInfo(batch);\r\n\r\n for (let i = 0; i < batch.length; i++) {\r\n const info = response[i];\r\n if (info && info.data) {\r\n if (!info.owner.equals(programId)) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\r\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\r\n );\r\n continue;\r\n }\r\n fetched.push({ pubkey: batch[i], data: info.data });\r\n }\r\n }\r\n\r\n // Inter-batch delay to avoid rate-limiting\r\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\r\n await new Promise(r => setTimeout(r, interBatchDelayMs));\r\n }\r\n }\r\n\r\n // Parse each account into a DiscoveredMarket\r\n const markets: DiscoveredMarket[] = [];\r\n\r\n for (const entry of fetched) {\r\n if (!entry) continue;\r\n const { pubkey, data: rawData } = entry;\r\n const data = new Uint8Array(rawData);\r\n\r\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\r\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n // v17 accounts have no slab header/config/engine/params; supply defaults so\r\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\r\n // to detect a v17 market.\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n // Validate v12 magic bytes\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\r\n );\r\n continue;\r\n }\r\n\r\n // Detect layout from full account data length\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// REST API-based market discovery (GH#59 / PERC-8424)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Shape of a single market entry returned by the Percolator REST API\r\n * (`GET /markets`). Only the fields needed for discovery are typed here;\r\n * the full API response may contain additional statistics fields.\r\n */\r\nexport interface ApiMarketEntry {\r\n slab_address: string;\r\n symbol?: string;\r\n name?: string;\r\n decimals?: number;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Options for {@link discoverMarketsViaApi}. */\r\nexport interface DiscoverMarketsViaApiOptions {\r\n /**\r\n * Timeout in ms for the HTTP request to the REST API.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n timeoutMs?: number;\r\n\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets by first querying the REST API for slab addresses,\r\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\r\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\r\n *\r\n * This is the recommended discovery path for mainnet users who do not have a\r\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\r\n *\r\n * The REST API acts as an address directory only — all market data is verified\r\n * on-chain via `getMarketsByAddress`, so the caller gets the same\r\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\r\n *\r\n * @param connection - Solana RPC connection (any endpoint, including public)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param apiBaseUrl - Base URL of the Percolator REST API\r\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\r\n * @param options - Optional timeout and on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts discovered via the API\r\n *\r\n * @example\r\n * ```ts\r\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const markets = await discoverMarketsViaApi(\r\n * connection,\r\n * programId,\r\n * \"https://percolatorlaunch.com/api\",\r\n * );\r\n * console.log(`Discovered ${markets.length} markets via API fallback`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaApi(\r\n connection: Connection,\r\n programId: PublicKey,\r\n apiBaseUrl: string,\r\n options: DiscoverMarketsViaApiOptions = {},\r\n): Promise {\r\n const { timeoutMs = 10_000, onChainOptions } = options;\r\n\r\n // Normalise base URL — strip trailing slash to avoid double-slash in path\r\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\r\n const url = `${base}/markets`;\r\n\r\n // Fetch market list from REST API\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: \"GET\",\r\n headers: { Accept: \"application/json\" },\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\r\n );\r\n }\r\n\r\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\r\n const apiMarkets = body.markets;\r\n\r\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\r\n return [];\r\n }\r\n\r\n // Extract valid slab addresses\r\n const addresses: PublicKey[] = [];\r\n for (const entry of apiMarkets) {\r\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slab_address));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\r\n );\r\n\r\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\r\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Static bundle fallback (PERC-8435 — tier 3)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options for {@link discoverMarketsViaStaticBundle}. */\r\nexport interface DiscoverMarketsViaStaticBundleOptions {\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets from a static list of known slab addresses.\r\n *\r\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\r\n * a bundled list of known slab addresses and fetches their full account data\r\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * The static list acts as an address directory only — all market data is verified\r\n * on-chain, so stale entries are silently skipped (the account won't have valid\r\n * magic bytes or will have been closed).\r\n *\r\n * @param connection - Solana RPC connection (any endpoint)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\r\n * @param options - Optional on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import {\r\n * discoverMarketsViaStaticBundle,\r\n * getStaticMarkets,\r\n * getProgramId,\r\n * } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const entries = getStaticMarkets(\"mainnet\");\r\n *\r\n * const markets = await discoverMarketsViaStaticBundle(\r\n * connection,\r\n * programId,\r\n * entries,\r\n * );\r\n * console.log(`Recovered ${markets.length} markets from static bundle`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaStaticBundle(\r\n connection: Connection,\r\n programId: PublicKey,\r\n entries: StaticMarketEntry[],\r\n options: DiscoverMarketsViaStaticBundleOptions = {},\r\n): Promise {\r\n if (entries.length === 0) return [];\r\n\r\n // Extract valid slab addresses from static entries\r\n const addresses: PublicKey[] = [];\r\n for (const entry of entries) {\r\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slabAddress));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\r\n );\r\n\r\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\r\n}\r\n","/**\r\n * Static market registry — bundled list of known Percolator slab addresses.\r\n *\r\n * This is the tier-3 fallback for `discoverMarkets()`: when both\r\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\r\n * the SDK falls back to this bundled list to bootstrap market discovery.\r\n *\r\n * The addresses are fetched on-chain via `getMarketsByAddress`\r\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\r\n * list only provides the *address directory* — no cached market data is used.\r\n *\r\n * ## Maintenance\r\n *\r\n * Update this list when new markets are deployed or old ones are retired.\r\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\r\n * or the REST API.\r\n *\r\n * @module\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport type { Network } from \"../config/program-ids.js\";\r\n\r\n/**\r\n * A single entry in the static market registry.\r\n *\r\n * Only the slab address (base58) is required. Optional metadata fields\r\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\r\n * they are **not** used for on-chain data and may become stale.\r\n */\r\nexport interface StaticMarketEntry {\r\n /** Base58-encoded slab account address. */\r\n slabAddress: string;\r\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\r\n symbol?: string;\r\n /** Optional descriptive name. */\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Known mainnet market slab addresses.\r\n *\r\n * These are the markets deployed to the mainnet Percolator program\r\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\r\n *\r\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\r\n */\r\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\r\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\r\n];\r\n\r\n/**\r\n * Known devnet market slab addresses.\r\n *\r\n * These are discovered from the devnet Percolator program\r\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\r\n *\r\n * **Last updated:** 2026-04-04.\r\n */\r\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\r\n // Populated from prior discoverMarkets() runs on devnet.\r\n // These serve as the tier-3 safety net for devnet users.\r\n];\r\n\r\n/**\r\n * Full static registry indexed by network.\r\n */\r\nconst STATIC_REGISTRY: Record = {\r\n mainnet: MAINNET_MARKETS,\r\n devnet: DEVNET_MARKETS,\r\n};\r\n\r\n/**\r\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\r\n * Keyed by network.\r\n */\r\nconst USER_MARKETS: Record = {\r\n mainnet: [],\r\n devnet: [],\r\n};\r\n\r\n/**\r\n * Get the bundled static market list for a given network.\r\n *\r\n * Returns the built-in list merged with any entries added via\r\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\r\n * automatically — user-registered entries take precedence.\r\n *\r\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\r\n * @returns Array of static market entries (may be empty if no markets are known)\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * const markets = getStaticMarkets(\"mainnet\");\r\n * console.log(`${markets.length} known mainnet slab addresses`);\r\n * ```\r\n */\r\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\r\n const builtin = STATIC_REGISTRY[network] ?? [];\r\n const user = USER_MARKETS[network] ?? [];\r\n\r\n if (user.length === 0) return [...builtin];\r\n\r\n // Merge: user entries override builtin entries with same slabAddress\r\n const seen = new Map();\r\n for (const entry of builtin) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n for (const entry of user) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n return [...seen.values()];\r\n}\r\n\r\n/**\r\n * Register additional static market entries at runtime.\r\n *\r\n * Use this to inject known slab addresses before calling `discoverMarkets()`\r\n * so that tier-3 fallback has addresses to work with — especially useful\r\n * right after mainnet launch when the bundled list may be empty.\r\n *\r\n * Entries are deduplicated by `slabAddress` — calling this multiple times\r\n * with the same address is safe.\r\n *\r\n * @param network - Target network\r\n * @param entries - One or more static market entries to register\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * registerStaticMarkets(\"mainnet\", [\r\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\r\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\r\n * ]);\r\n * ```\r\n */\r\nexport function registerStaticMarkets(\r\n network: Network,\r\n entries: StaticMarketEntry[],\r\n): void {\r\n const existing = USER_MARKETS[network];\r\n const seen = new Set(existing.map(e => e.slabAddress));\r\n\r\n for (const entry of entries) {\r\n if (!entry.slabAddress) continue;\r\n if (seen.has(entry.slabAddress)) continue;\r\n // Validate that slabAddress is a valid base58 public key\r\n try {\r\n new PublicKey(entry.slabAddress);\r\n } catch {\r\n console.warn(\r\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\r\n );\r\n continue;\r\n }\r\n seen.add(entry.slabAddress);\r\n existing.push(entry);\r\n }\r\n}\r\n\r\n/**\r\n * Clear all user-registered static market entries for a network.\r\n *\r\n * Useful in tests or when resetting state.\r\n *\r\n * @param network - Target network to clear (omit to clear all networks)\r\n */\r\nexport function clearStaticMarkets(network?: Network): void {\r\n if (network) {\r\n USER_MARKETS[network] = [];\r\n } else {\r\n USER_MARKETS.mainnet = [];\r\n USER_MARKETS.devnet = [];\r\n }\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n PUMPSWAP_PROGRAM_ID,\r\n RAYDIUM_CLMM_PROGRAM_ID,\r\n METEORA_DLMM_PROGRAM_ID,\r\n} from \"./pda.js\";\r\n\r\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\r\n\r\nexport interface DexPoolInfo {\r\n dexType: DexType;\r\n poolAddress: PublicKey;\r\n baseMint: PublicKey;\r\n quoteMint: PublicKey;\r\n baseVault?: PublicKey; // PumpSwap only\r\n quoteVault?: PublicKey; // PumpSwap only\r\n}\r\n\r\n/**\r\n * Detect DEX type from the program that owns the pool account.\r\n *\r\n * @param ownerProgramId - The program ID that owns the pool account\r\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\r\n *\r\n * Supported DEX programs:\r\n * - PumpSwap (constant-product AMM)\r\n * - Raydium CLMM (concentrated liquidity)\r\n * - Meteora DLMM (discretized liquidity)\r\n */\r\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\r\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\r\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\r\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\r\n *\r\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\r\n * @param poolAddress - The on-chain address of the pool account\r\n * @param data - Raw account data bytes\r\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\r\n * @throws Error if data is too short for the given DEX type\r\n */\r\nexport function parseDexPool(\r\n dexType: DexType,\r\n poolAddress: PublicKey,\r\n data: Uint8Array,\r\n): DexPoolInfo {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n return parsePumpSwapPool(poolAddress, data);\r\n case \"raydium-clmm\":\r\n return parseRaydiumClmmPool(poolAddress, data);\r\n case \"meteora-dlmm\":\r\n return parseMeteoraPool(poolAddress, data);\r\n }\r\n}\r\n\r\n/**\r\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\r\n *\r\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\r\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\r\n * markets, prefer Pyth or Chainlink oracles.\r\n *\r\n * @param dexType - The type of DEX\r\n * @param data - Raw pool account data\r\n * @param vaultData - For PumpSwap only: base and quote vault account data\r\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\r\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\r\n * ignored for raydium-clmm (decimals are embedded in the pool account).\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\r\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\r\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\r\n * and for PumpSwap pools quoted in a non-WSOL mint.\r\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\r\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\r\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\r\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\r\n * price mislabeled as USD.\r\n * @throws Error if data is too short, required params are missing, or computation fails\r\n */\r\nexport function computeDexSpotPriceE6(\r\n dexType: DexType,\r\n data: Uint8Array,\r\n vaultData?: { base: Uint8Array; quote: Uint8Array },\r\n decimals?: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\r\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\r\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\r\n // MUST supply decimals (fetched from the base/quote mints), matching the\r\n // meteora-dlmm contract below.\r\n if (!decimals) {\r\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\r\n case \"raydium-clmm\":\r\n return computeRaydiumClmmPriceE6(data);\r\n case \"meteora-dlmm\":\r\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\r\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\r\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\r\n if (!decimals) {\r\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Mint decimals helper\r\n// ============================================================================\r\n\r\n/**\r\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\r\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\r\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\r\n * can read this field directly instead of duplicating the magic number.\r\n */\r\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\r\n\r\n/**\r\n * Read the `decimals` field of any SPL mint account (including native WSOL).\r\n *\r\n * This replaces `getMint(connection, mint).decimals` for callers that need to\r\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\r\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\r\n * because the system account is not a valid token-program mint; this function\r\n * reads raw account data and extracts byte 44 directly, which works for all\r\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param mint - The mint public key to query\r\n * @returns The `decimals` field value (0–255)\r\n * @throws Error if the account does not exist or is too short to hold a mint\r\n *\r\n * @example\r\n * ```ts\r\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\r\n *\r\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\r\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\r\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\r\n * base: baseDecimals,\r\n * quote: quoteDecimals,\r\n * });\r\n * ```\r\n */\r\nexport async function fetchMintDecimals(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) {\r\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\r\n }\r\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\r\n throw new Error(\r\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\r\n );\r\n }\r\n return info.data[SPL_MINT_DECIMALS_OFFSET];\r\n}\r\n\r\n// ============================================================================\r\n// PumpSwap\r\n// ============================================================================\r\n\r\n/**\r\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\r\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\r\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\r\n */\r\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\r\n\r\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\r\n// account layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8] pool_bump u8\r\n// [9:11] index u16\r\n// [11:43] creator Pubkey\r\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\r\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\r\n// [107:139] lp_mint Pubkey\r\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\r\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\r\n// [203:211] lp_supply u64\r\n// [211:243] coin_creator Pubkey\r\n//\r\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\r\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\r\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\r\n// pubkeys. Verified against the live ANSEM pool on mainnet\r\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\r\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\r\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\r\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\r\n// balance at verification time). Note the base vault (holding the pump.fun token)\r\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\r\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\r\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\r\n\r\n/**\r\n * Parse a PumpSwap constant-product AMM pool account.\r\n * @internal\r\n */\r\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"pumpswap\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(43, 75)),\r\n quoteMint: new PublicKey(data.slice(75, 107)),\r\n baseVault: new PublicKey(data.slice(139, 171)),\r\n quoteVault: new PublicKey(data.slice(171, 203)),\r\n };\r\n}\r\n\r\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\r\n\r\n/**\r\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\r\n * converted to USD.\r\n *\r\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\r\n *\r\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\r\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\r\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\r\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\r\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\r\n * at all unless multiplied by the SOL/USD rate.\r\n *\r\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\r\n * whether SOL→USD conversion applies)\r\n * @param vaultData - Base and quote vault (SPL token account) raw data\r\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\r\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\r\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\r\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\r\n * PumpSwap pool).\r\n * @internal\r\n */\r\nfunction computePumpSwapPriceE6(\r\n poolData: Uint8Array,\r\n vaultData: { base: Uint8Array; quote: Uint8Array },\r\n decimals: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n if (poolData.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\r\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\r\n\r\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\r\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\r\n\r\n const baseAmount = readU64LE(baseDv, 64);\r\n const quoteAmount = readU64LE(quoteDv, 64);\r\n\r\n if (baseAmount === 0n) return 0n;\r\n\r\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\r\n // the numerator by both the base-decimal correction AND the 1e6 output scale\r\n // before the single division, so low-priced tokens don't truncate to 0n.\r\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\r\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\r\n const baseScale = 10n ** BigInt(decimals.base);\r\n const quoteScale = 10n ** BigInt(decimals.quote);\r\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\r\n\r\n const quoteMint = new PublicKey(poolData.slice(75, 107));\r\n if (quoteMint.equals(WSOL_MINT)) {\r\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\r\n if (solPriceE6 === undefined) {\r\n throw new Error(\r\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\r\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\r\n );\r\n }\r\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\r\n }\r\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\r\n // already ~USD once decimal-adjusted — no further conversion needed.\r\n return quotePerBaseE6;\r\n}\r\n\r\n// ============================================================================\r\n// Raydium CLMM\r\n// ============================================================================\r\n\r\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\r\n\r\n/**\r\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\r\n * @internal\r\n */\r\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"raydium-clmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(73, 105)),\r\n quoteMint: new PublicKey(data.slice(105, 137)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\r\n *\r\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\r\n *\r\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\r\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\r\n *\r\n * @internal\r\n */\r\nconst MAX_TOKEN_DECIMALS = 24;\r\n\r\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\r\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n}\r\n\r\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n const decimals0 = data[233];\r\n const decimals1 = data[234];\r\n\r\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n\r\n const sqrtPriceX64 = readU128LE(dv, 253);\r\n\r\n if (sqrtPriceX64 === 0n) return 0n;\r\n\r\n // #210: defer truncation to a single shift at the very end. The previous form\r\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\r\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\r\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\r\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\r\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\r\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\r\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\r\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\r\n\r\n const decimalDiff = 6 + decimals0 - decimals1;\r\n const adjustedDiff = decimalDiff - 6;\r\n\r\n if (adjustedDiff >= 0) {\r\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\r\n } else {\r\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Meteora DLMM\r\n// ============================================================================\r\n\r\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8:40] parameters (StaticParameters, 32 bytes)\r\n// [40:72] v_parameters (VariableParameters, 32 bytes)\r\n// [72] bump_seed u8\r\n// [73:75] bin_step_seed [u8;2]\r\n// [75] pair_type u8\r\n// [76:80] active_id i32\r\n// [80:82] bin_step u16\r\n// [82] status u8\r\n// [83] require_base_factor_seed u8\r\n// [84:86] base_factor_seed [u8;2]\r\n// [86] activation_type u8\r\n// [87] creator_pool_on_off_control u8\r\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\r\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\r\n// [152:184] reserve_x Pubkey\r\n// [184:216] reserve_y Pubkey\r\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\r\n\r\n/**\r\n * Parse a Meteora DLMM (discretized liquidity) pool account.\r\n *\r\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\r\n * on-chain `LbPair` struct layout (verified against mainnet pool\r\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\r\n *\r\n * @internal\r\n */\r\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"meteora-dlmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(88, 120)),\r\n quoteMint: new PublicKey(data.slice(120, 152)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Meteora DLMM spot price from active_id and bin_step.\r\n *\r\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\r\n *\r\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\r\n * For negative active_id, computes the inverse.\r\n *\r\n * @internal\r\n */\r\nconst MAX_BIN_STEP = 10_000;\r\nconst MAX_ACTIVE_ID_ABS = 500_000;\r\n\r\nfunction computeMeteoraDlmmPriceE6(\r\n data: Uint8Array,\r\n decimalsBase: number,\r\n decimalsQuote: number,\r\n): bigint {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\r\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\r\n // They happen to encode the same integer for most pools (explaining why the\r\n // old code produced correct prices), but reading the correct field is required\r\n // for correctness once those fields diverge.\r\n const binStep = dv.getUint16(80, true);\r\n const activeId = dv.getInt32(76, true);\r\n\r\n if (binStep === 0) return 0n;\r\n if (binStep > MAX_BIN_STEP) {\r\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\r\n }\r\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\r\n throw new Error(\r\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\r\n );\r\n }\r\n\r\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\r\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\r\n\r\n const isNeg = activeId < 0;\r\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\r\n\r\n let result = SCALE;\r\n let b = base;\r\n\r\n while (exp > 0n) {\r\n if (exp & 1n) {\r\n result = (result * b) / SCALE;\r\n }\r\n exp >>= 1n;\r\n if (exp > 0n) {\r\n b = (b * b) / SCALE;\r\n }\r\n }\r\n\r\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\r\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\r\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\r\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\r\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\r\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\r\n // arbitrary-precision, so the intermediate products cannot overflow.\r\n const diff = decimalsBase - decimalsQuote;\r\n\r\n if (isNeg) {\r\n if (result === 0n) return 0n;\r\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\r\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\r\n if (diff >= 0) {\r\n return (num * 10n ** BigInt(diff)) / result;\r\n }\r\n return num / (result * 10n ** BigInt(-diff));\r\n } else {\r\n // price_e6 = (result / 1e12) * 10^diff\r\n if (diff >= 0) {\r\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\r\n }\r\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Read a little-endian u64 from a DataView. */\r\nfunction readU64LE(dv: DataView, offset: number): bigint {\r\n const lo = BigInt(dv.getUint32(offset, true));\r\n const hi = BigInt(dv.getUint32(offset + 4, true));\r\n return lo | (hi << 32n);\r\n}\r\n\r\n/** Read a little-endian u128 from a DataView. */\r\nfunction readU128LE(dv: DataView, offset: number): bigint {\r\n const lo = readU64LE(dv, offset);\r\n const hi = readU64LE(dv, offset + 8);\r\n return lo | (hi << 64n);\r\n}\r\n","/**\r\n * Oracle account parsing utilities.\r\n *\r\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\r\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\r\n * so that this parser and the on-chain program agree byte-for-byte:\r\n *\r\n * CHAINLINK_HEADER_SIZE = 192\r\n * offset 8: version (u8) CL_OFF_VERSION\r\n * offset 138: decimals (u8) CL_OFF_DECIMALS\r\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\r\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\r\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\r\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\r\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\r\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\r\n *\r\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\r\n *\r\n * These utilities validate oracle data BEFORE parsing to prevent silent\r\n * propagation of stale or malformed Chainlink data as price.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Minimum buffer size to read Chainlink price data.\r\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\r\n * The previous value (224) was smaller than the program's own floor, so the SDK\r\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\r\n * answer at offset 216.\r\n */\r\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\r\n\r\n/** Maximum reasonable decimals for a price feed */\r\nconst MAX_DECIMALS = 18;\r\n\r\n/** Offset of decimals field in Chainlink aggregator account */\r\nconst CHAINLINK_DECIMALS_OFFSET = 138;\r\n\r\n/**\r\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\r\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\r\n */\r\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\r\n\r\n/**\r\n * Offset of the latest answer.\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\r\n */\r\nconst CHAINLINK_ANSWER_OFFSET = 216;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface OraclePrice {\r\n price: bigint;\r\n decimals: number;\r\n /** Unix timestamp (seconds) of the last oracle update, if available. */\r\n updatedAt?: number;\r\n}\r\n\r\nexport interface ParseChainlinkOptions {\r\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\r\n maxStalenessSeconds?: number;\r\n /**\r\n * How far ahead of the local clock a publish timestamp may be before it is\r\n * treated as invalid rather than as clock skew. Defaults to 60s.\r\n * Only consulted when `maxStalenessSeconds` is set.\r\n */\r\n futureToleranceSeconds?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Browser-compatible read helpers using DataView\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n return data[off];\r\n}\r\n\r\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\r\n}\r\n\r\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\r\n}\r\n\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\r\n}\r\n\r\n/**\r\n * Default tolerance for a publish timestamp that appears to be in the future.\r\n *\r\n * The program compares the feed timestamp against the on-chain clock\r\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\r\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\r\n * between a user's machine and the cluster would otherwise reject a perfectly\r\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\r\n */\r\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse price data from a Chainlink aggregator account buffer.\r\n *\r\n * Validates:\r\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\r\n * program's own CHAINLINK_FEED_MIN_LEN)\r\n * - Decimals are in a reasonable range (0-18)\r\n * - Price is positive (non-zero)\r\n *\r\n * @param data - Raw account data from Chainlink aggregator\r\n * @param options - Optional staleness check (maxStalenessSeconds)\r\n * @returns Parsed oracle price with decimals and last-update timestamp\r\n * @throws if the buffer is invalid, contains unreasonable data, or (when\r\n * maxStalenessSeconds is set) the last update is older than that bound\r\n */\r\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\r\n if (data.length < CHAINLINK_MIN_SIZE) {\r\n throw new Error(\r\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\r\n );\r\n }\r\n\r\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\r\n if (decimals > MAX_DECIMALS) {\r\n throw new Error(\r\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\r\n );\r\n }\r\n\r\n // The program reads the answer as a full i128 LE (read_i128_le at\r\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\r\n // high (signed) halves rather than reading only the low 8 bytes, which would\r\n // silently truncate a large answer into a different price than the chain sees.\r\n //\r\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\r\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\r\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\r\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\r\n // on-chain. `price` is a bigint and holds the full i128 range.\r\n const answer =\r\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\r\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\r\n if (answer <= 0n) {\r\n throw new Error(\r\n `Oracle price is non-positive: ${answer}`\r\n );\r\n }\r\n const price = answer;\r\n\r\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\r\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\r\n\r\n if (options?.maxStalenessSeconds !== undefined) {\r\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\r\n // skipping the check: a zero timestamp means the feed has never published,\r\n // which is maximally stale, not exempt from staleness.\r\n if (updatedAt <= 0) {\r\n throw new Error(\r\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\r\n );\r\n }\r\n const now = Math.floor(Date.now() / 1000);\r\n const age = now - updatedAt;\r\n // The program rejects a negative age, but it measures against the on-chain\r\n // clock. We only have the local one, so a couple of seconds of ordinary skew\r\n // must not condemn a healthy feed — only an implausible jump ahead should.\r\n const futureTolerance =\r\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\r\n if (age < -futureTolerance) {\r\n throw new Error(\r\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\r\n `check the feed or the local clock`\r\n );\r\n }\r\n if (age > options.maxStalenessSeconds) {\r\n throw new Error(\r\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\r\n );\r\n }\r\n }\r\n\r\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\r\n}\r\n\r\n/**\r\n * Validate that a buffer looks like a valid Chainlink aggregator account.\r\n * Returns true if the buffer passes all validation checks, false otherwise.\r\n * Use this for non-throwing validation.\r\n */\r\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\r\n try {\r\n parseChainlinkPrice(data);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-export constants for consumers\r\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Token2022 (Token Extensions) program ID.\r\n */\r\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\r\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\r\n);\r\n\r\n/**\r\n * Detect which token program owns a given mint account.\r\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\r\n *\r\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\r\n * attacker-controlled account owned by an arbitrary program (or a non-mint\r\n * account) would be accepted and its owner propagated as the \"token program\",\r\n * letting a forged program be passed into a later token CPI. Now we branch on\r\n * the owner and accept ONLY the two real token programs, throwing otherwise.\r\n *\r\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\r\n * Token-2022.\r\n */\r\nexport async function detectTokenProgram(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\r\n\r\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\r\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\r\n\r\n throw new Error(\r\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\r\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\r\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\r\n );\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is Token2022.\r\n */\r\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is the standard SPL Token program.\r\n */\r\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\r\n}\r\n","/**\r\n * @module stake\r\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\r\n *\r\n * Program: percolator-stake (dcccrypto/percolator-stake)\r\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\r\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\r\n * `src/config/program-ids.ts`)\r\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\r\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\r\n * this writing; treat as a placeholder until DevOps confirms)\r\n *\r\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\r\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\r\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\r\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\r\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\r\n * do not use it for new integrations).\r\n */\r\n\r\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\r\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\r\nexport { TOKEN_2022_PROGRAM_ID };\r\nimport { safeEnv } from '../config/program-ids.js';\r\nimport { concatBytes } from '../abi/encode.js';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Known stake program addresses per network.\r\n *\r\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\r\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\r\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\r\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\r\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\r\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\r\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\r\n * module targets — see the module doc above.\r\n *\r\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\r\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\r\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\r\n * confirms.\r\n *\r\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\r\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\r\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\r\n * silently default to mainnet: an unconfigured browser caller would have resolved to\r\n * a real, executing mainnet program rather than failing safe.\r\n */\r\nexport const STAKE_PROGRAM_IDS = {\r\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\r\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\r\n} as const;\r\nObject.freeze(STAKE_PROGRAM_IDS);\r\n\r\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\r\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\r\n\r\n/**\r\n * Resolve the stake program ID for the given network.\r\n *\r\n * Priority:\r\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\r\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\r\n *\r\n * Throws a clear error on mainnet when no address is available so callers\r\n * surface the gap instead of silently hitting the devnet program.\r\n */\r\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\r\n // Only consult the env override when no explicit network arg is provided.\r\n // An explicit network argument always wins so tests and multi-network callers\r\n // are not silently redirected to a DevOps-set override address.\r\n if (!network) {\r\n const override = safeEnv('STAKE_PROGRAM_ID');\r\n if (override) {\r\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\r\n // ambient env poisoning while allowing fresh pre-deploy addresses).\r\n if (\r\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\r\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\r\n ) {\r\n throw new Error(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\r\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\r\n );\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n const detectedNetwork =\r\n network ??\r\n (() => {\r\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\r\n safeEnv('NETWORK')?.toLowerCase() ?? '';\r\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\r\n if (n === 'devnet') return 'devnet' as const;\r\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\r\n // i.e. in every browser bundle, where process.env is empty because env vars\r\n // are not inlined into third-party SDK code. An unconfigured frontend caller\r\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\r\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\r\n //\r\n // We deliberately do NOT substitute a devnet default here. Unlike\r\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\r\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\r\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\r\n // defaulting to devnet would merely defer it to the day mainnet launches and\r\n // a forgotten env var silently points a mainnet UI at the devnet vault.\r\n // Refuse to guess: the network must be explicit.\r\n // The message must not assert a cause it has not established. This fires in\r\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\r\n // with process.env fully available — so claiming \"browser bundle\" would send\r\n // a server-side caller chasing the wrong thing.\r\n throw new Error(\r\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\r\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\r\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\r\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\r\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\r\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\r\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\r\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\r\n 'for the wrong network.',\r\n );\r\n })();\r\n\r\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\r\n if (!id) {\r\n throw new Error(\r\n `Stake program not deployed on ${detectedNetwork}. ` +\r\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\r\n );\r\n }\r\n return new PublicKey(id);\r\n}\r\n\r\n/**\r\n * Default export — resolves for the current runtime network.\r\n * Use getStakeProgramId() with an explicit network argument where possible.\r\n *\r\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\r\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\r\n * resolving to the devnet address.\r\n */\r\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Tags — ADOPTED percolator-stake lineage\r\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\r\n//\r\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\r\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\r\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\r\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\r\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\r\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\r\n// side-by-side tag-delta table this was verified against. The comparison is now\r\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\r\n// NEW address that already runs the ADOPTED lineage below — there is no more\r\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport const STAKE_IX = {\r\n InitPool: 0,\r\n Deposit: 1,\r\n Withdraw: 2,\r\n FlushToInsurance: 3,\r\n UpdateConfig: 4,\r\n /**\r\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\r\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\r\n * zero pubkey CANCELS an outstanding proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\r\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\r\n * wrapper marketauth rotation (a completely different key, done via the\r\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\r\n *\r\n * Wire: tag(1) + new_admin(32) = 33 bytes.\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\n ProposeAdmin: 5,\r\n /**\r\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to take ownership; requires an outstanding proposal\r\n * and the signer to equal `pool.pending_admin`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\r\n * removed `AdminSetOracleAuthority` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\n AcceptAdmin: 6,\r\n /**\r\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\r\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\r\n * LP holders an exit window. A decrease/unchanged value is rejected here\r\n * (use UpdateConfig, which applies decreases immediately).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\r\n * removed `AdminSetRiskThreshold` (rejects on-chain).\r\n *\r\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n ProposeCooldownIncrease: 7,\r\n /**\r\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\r\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n CommitCooldownIncrease: 8,\r\n /**\r\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\r\n * proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\r\n * removed `AdminResolveMarket` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n CancelCooldownIncrease: 9,\r\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\r\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\r\n TransferAdmin: 5,\r\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\r\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\r\n AdminSetOracleAuthority: 6,\r\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\r\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\r\n AdminSetRiskThreshold: 7,\r\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\r\n * CommitCooldownIncrease. */\r\n AdminSetMaintenanceFee: 8,\r\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\r\n * CancelCooldownIncrease. */\r\n AdminResolveMarket: 9,\r\n /**\r\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\r\n * percolator-vault program: transfer withdrawn insurance back into the pool\r\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\r\n * books admin-ATA -> pool-vault).\r\n */\r\n ReturnInsurance: 10,\r\n /** @deprecated Legacy alias for ReturnInsurance. */\r\n AdminWithdrawInsurance: 10,\r\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\r\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\r\n AdminSetInsurancePolicy: 11,\r\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\r\n AccrueFees: 12,\r\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\r\n InitTradingPool: 13,\r\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\r\n AdminSetHwmConfig: 14,\r\n /**\r\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\r\n * tranches. Sets `junior_fee_mult_bps`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * below). Sending this payload against the DEPLOYED vault program would\r\n * execute BindInsuranceAuthority instead; only send it against the\r\n * ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n AdminSetTrancheConfig: 15,\r\n /**\r\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\r\n * Same account shape as Deposit (tag 1).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\n DepositJunior: 16,\r\n /**\r\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\r\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\r\n * binds both in one call, unlike the deployed vault program which only\r\n * bound insurance_authority. The human admin signs the outer tx as the\r\n * current authority/operator; vault_auth signs via invoke_signed.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n BindInsuranceAuthority: 19,\r\n /**\r\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\r\n * escape that moves the market's `insurance_authority` OFF our vault_auth\r\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\r\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\r\n * authority. NEW in the adopted lineage — no equivalent in the deployed\r\n * percolator-vault program (which has no un-bind escape at all).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceAuthority: 20,\r\n /**\r\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\r\n * has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\r\n */\r\n BurnAssetAdmin: 21,\r\n /**\r\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceOperator: 22,\r\n /**\r\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\r\n * insurance_operator, not asset_admin. `amount` capped to\r\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\r\n * NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\r\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\r\n * tokenProgram, percolatorProgram]\r\n */\r\n RecoverFlushedInsurance: 23,\r\n /**\r\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\r\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\r\n * without this proxy every stake-initialized market would be permanently\r\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\r\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\r\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\r\n * percolator-stake (see src/instruction.rs / src/processor.rs\r\n * `process_admin_resolve_market`, tag 24).\r\n *\r\n * NOTE on the name: the on-chain enum variant is literally\r\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\r\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\r\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\r\n * avoid re-using that already-claimed object key/export name — the tag-9\r\n * alias and this tag-24 instruction are unrelated aside from sharing an\r\n * on-chain name across two different lineages.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n */\r\n AdminResolveMarketCpi: 24,\r\n /**\r\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n SetMarketResolved: 18,\r\n /**\r\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\r\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\r\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\r\n * signs the CPI via invoke_signed.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\r\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\r\n * Custom(52)/Custom(51) through the CPI.\r\n */\r\n AdminUpdateFeeSplit: 25,\r\n /**\r\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\r\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\r\n * signer model as tag 25.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\r\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\r\n * `read_u128`.\r\n */\r\n AdminUpdateMaintenanceFeePerSlot: 26,\r\n /**\r\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\r\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\r\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\r\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\r\n *\r\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\r\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\r\n *\r\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n AdminUpdateBackingFeePolicy: 27,\r\n /**\r\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\r\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\r\n * model as tag 27.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\r\n * `read_u64`, wrapper tag 88 with `read_u128`.\r\n */\r\n AdminUpdateTradeFeePolicy: 28,\r\n} as const;\r\nObject.freeze(STAKE_IX);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * User-facing hint text for `StakeError` custom program error codes\r\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\r\n *\r\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\r\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\r\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\r\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\r\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\r\n * error\" for 25-27 despite them being named enum variants); the hints below\r\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\r\n * (missing) on-chain string.\r\n */\r\nexport const STAKE_ERRORS: Record = {\r\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\r\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\r\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\r\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\r\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\r\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\r\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\r\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\r\n 8: \"Market is resolved — no new deposits allowed after resolution\",\r\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\r\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\r\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\r\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\r\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\r\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\r\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\r\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\r\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\r\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\r\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\r\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\r\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\r\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\r\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\r\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\r\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\r\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\r\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\r\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\r\n};\r\nObject.freeze(STAKE_ERRORS);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PDA Derivation\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\n/** Derive the stake pool PDA for a given slab (market). */\r\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\r\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\r\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getBigUint64(off, /* littleEndian= */ true);\r\n}\r\n\r\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getUint16(off, /* littleEndian= */ true);\r\n}\r\n\r\nfunction requireDiscriminator(\r\n accountName: string,\r\n data: Uint8Array,\r\n offset: number,\r\n expected: Uint8Array,\r\n): void {\r\n for (let i = 0; i < expected.length; i += 1) {\r\n if (data[offset + i] !== expected[i]) {\r\n throw new Error(`${accountName} invalid discriminator`);\r\n }\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Encoders\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction u64Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\r\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\r\n const arr = new Uint8Array(8);\r\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\r\n}\r\n\r\nfunction u128Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\r\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\r\n const arr = new Uint8Array(16);\r\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\r\n view.setBigUint64(8, big >> 64n, true);\r\n return arr;\r\n}\r\n\r\nfunction u16Le(v: number): Uint8Array {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\r\n return arr;\r\n}\r\n\r\n/** Tag 0: InitPool — create stake pool for a slab. */\r\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\r\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\r\n}\r\n\r\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\r\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\r\n}\r\n\r\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\r\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\r\n}\r\n\r\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\r\nexport function encodeStakeUpdateConfig(\r\n newCooldownSlots?: bigint | number,\r\n newDepositCap?: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.UpdateConfig]),\r\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\r\n u64Le(newCooldownSlots ?? 0n),\r\n new Uint8Array([newDepositCap != null ? 1 : 0]),\r\n u64Le(newDepositCap ?? 0n),\r\n );\r\n}\r\n\r\nfunction removedStakeInstruction(name: string, tag: number): never {\r\n throw new Error(\r\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\r\n );\r\n}\r\n\r\n/**\r\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\r\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\r\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\r\n * proposal.\r\n *\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeAdmin]),\r\n newAdmin.toBytes(),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to become admin. Requires an outstanding proposal.\r\n *\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAcceptAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\r\n}\r\n\r\n/**\r\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\r\n * until CommitCooldownIncrease is called after the on-chain timelock has\r\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\r\n u64Le(newCooldownSlots),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\r\n * increase proposal.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\r\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\r\n * percolator-stake lineage this module targets, tag 5 is the two-step\r\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\r\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\r\n */\r\nexport function encodeStakeTransferAdmin(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\r\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\r\n void newAuthority;\r\n throw new Error(\r\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\r\n 'lineage — use encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\r\n void newThreshold;\r\n throw new Error(\r\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\r\n void newFee;\r\n throw new Error(\r\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\r\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ReturnInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\r\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\r\n return encodeStakeReturnInsurance(amount);\r\n}\r\n\r\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\r\nexport function encodeStakeAccrueFees(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AccrueFees]);\r\n}\r\n\r\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\r\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitTradingPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\r\nexport function encodeStakeAdminSetHwmConfig(\r\n enabled: boolean,\r\n hwmFloorBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\r\n new Uint8Array([enabled ? 1 : 0]),\r\n u16Le(hwmFloorBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\r\n * percolator-stake lineage; sending it against the currently-deployed vault\r\n * program would silently execute BindInsuranceAuthority instead.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\r\n u16Le(juniorFeeMultBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\r\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\r\n}\r\n\r\n/**\r\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeSetMarketResolved(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\r\n}\r\n\r\n/**\r\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\r\n * then kind=2) — a broader bind than the deployed vault program's\r\n * single-CPI version (insurance_authority only). Must be called once after\r\n * InitPool, before FlushToInsurance will work.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\r\n *\r\n * @returns 1-byte Uint8Array `[0x13]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBindInsuranceAuthority();\r\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\r\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\r\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\r\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BindInsuranceAuthorityAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * Account order matches src/processor.rs process_bind_insurance_authority\r\n * (adopted lineage — same account shape as the deployed vault program's tag\r\n * 15, only the tag byte moved):\r\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\r\n * [1] pool_pda writable (stake pool PDA)\r\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n *\r\n * @example\r\n * ```ts\r\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\r\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\r\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function bindInsuranceAuthorityAccounts(\r\n a: BindInsuranceAuthorityAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\r\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\r\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\r\n * the deployed percolator-vault program (which has no un-bind escape).\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceAuthority();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceOperator();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\r\n}\r\n\r\n/**\r\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\r\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA.\r\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\r\n * @param newTarget The successor authority/operator — co-signs the outer tx.\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RotateInsuranceAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n newTarget: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\r\n * (tag 22) — identical account order in both (src/processor.rs\r\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only\r\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\r\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\r\n * [4] slab writable (wrapper market; needed for CPI)\r\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function rotateInsuranceAccounts(\r\n a: RotateInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after\r\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBurnAssetAdmin();\r\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\r\n}\r\n\r\n/**\r\n * Account inputs for BurnAssetAdmin (tag 21).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\r\n * @param poolPda Stake pool PDA (writable — records the burn).\r\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BurnAssetAdminAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\r\n * process_burn_asset_admin:\r\n * [0] admin signer, writable (current asset_admin == pool.admin)\r\n * [1] pool_pda writable (records asset_admin_burned)\r\n * [2] vault_auth read-only (placeholder new_authority slot)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function burnAssetAdminAccounts(\r\n a: BurnAssetAdminAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\r\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\r\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\r\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\r\n * adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n *\r\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\r\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\r\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for RecoverFlushedInsurance (tag 23).\r\n *\r\n * @param caller Permissionless caller — no signer check required.\r\n * @param poolPda Stake pool PDA (writable).\r\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\r\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\r\n * @param wrapperMarket Wrapper market/slab account (writable).\r\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\r\n * @param wrapperVaultAuth Wrapper vault authority PDA.\r\n * @param tokenProgram Token program.\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RecoverFlushedInsuranceAccounts {\r\n caller: PublicKey;\r\n poolPda: PublicKey;\r\n poolVault: PublicKey;\r\n vaultAuth: PublicKey;\r\n wrapperMarket: PublicKey;\r\n wrapperVault: PublicKey;\r\n wrapperVaultAuth: PublicKey;\r\n tokenProgram: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\r\n * process_recover_flushed_insurance:\r\n * [0] caller (no signer check — permissionless)\r\n * [1] pool_pda writable\r\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\r\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\r\n * [4] market (wrapper) writable\r\n * [5] wrapper_vault writable (source — wrapper insurance vault)\r\n * [6] wrapper_vault_auth read-only\r\n * [7] token_program read-only\r\n * [8] percolator_program read-only\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function recoverFlushedInsuranceAccounts(\r\n a: RecoverFlushedInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.caller, isSigner: false, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\r\n * can call the wrapper's ResolveMarket directly; this instruction has the\r\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\r\n * the (human) admin can trigger resolution. Does not mutate any local\r\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\r\n * separately afterward for local bookkeeping.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n *\r\n * @returns 1-byte Uint8Array `[24]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminResolveMarketCpi();\r\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\r\n}\r\n\r\n/**\r\n * Account inputs for AdminResolveMarketCpi (tag 24).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\r\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface AdminResolveMarketCpiAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\r\n * process_admin_resolve_market:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\r\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function adminResolveMarketCpiAccounts(\r\n a: AdminResolveMarketCpiAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\r\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\r\n//\r\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\r\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\r\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\r\n// transaction, so the affected wrapper setters become reachable ONLY through a\r\n// stake-program CPI proxy. Before these four, exactly one proxy existed\r\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\r\n// wrapper handlers reachable — which is the mechanical reason the fee split\r\n// was unachievable on a staked market.\r\n//\r\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\r\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\r\n// VAULT_AUTH PDA signs.\r\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n//\r\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\r\n * whose length is not exactly 6 bytes after the tag.\r\n *\r\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\r\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\r\n *\r\n * Share validation happens in the WRAPPER, not here: a split that does not sum\r\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\r\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\r\n *\r\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\r\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\r\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\r\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateFeeSplit(\r\n creatorShareBps: number,\r\n lpShareBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\r\n u16Le(creatorShareBps),\r\n u16Le(lpShareBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\r\n * wrapper tag 88.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\r\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\r\n * u64 fails at the stake program before the CPI is even attempted.\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\r\n * 0 (maintenance fee disabled). The wrapper\r\n * range-checks against MAX_PROTOCOL_FEE_ABS.\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\r\n maintenanceFeePerSlot: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\r\n u128Le(maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\r\n * tag 51, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\r\n * = 7 bytes.\r\n *\r\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\r\n * @param feeBps Backing fee in bps (u16).\r\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\r\n * const keys = adminUpdateBackingFeePolicyAccounts({\r\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\r\n * });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateBackingFeePolicy(\r\n domain: number,\r\n feeBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\r\n u16Le(domain),\r\n u16Le(feeBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\r\n * 55, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\r\n * checks `rest.len() == 8`.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\r\n * values above the market's `max_trading_fee_bps` or\r\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateTradeFeePolicy(\r\n tradeFeeBaseBps: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\r\n u64Le(tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\r\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupAProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP A proxies — src/processor.rs\r\n * `process_admin_update_fee_split` (tag 25) and\r\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\r\n * identical layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\r\n * [2] slab writable (wrapper market; CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupAProxyAccounts(\r\n a: StakeGroupAProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\r\n\r\n/**\r\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\r\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\r\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\r\n * insurance_authority; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupBProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP B proxies — src/processor.rs\r\n * `process_admin_update_backing_fee_policy` (tag 27) and\r\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\r\n * layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\r\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; CPI target)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\r\n * difference from GROUP A, and getting it wrong makes the CPI fail its\r\n * authority check rather than fail loudly at the account level.\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupBProxyAccounts(\r\n a: StakeGroupBProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\r\nexport function encodeStakeAdminSetInsurancePolicy(\r\n authority: PublicKey,\r\n minWithdrawBase: bigint | number,\r\n maxWithdrawBps: number,\r\n cooldownSlots: bigint | number,\r\n): Uint8Array {\r\n void authority;\r\n void minWithdrawBase;\r\n void maxWithdrawBps;\r\n void cooldownSlots;\r\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// On-Chain State Layout — StakePool decoded fields\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\r\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\r\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\r\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\r\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\r\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\r\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\r\n * and PERC-303 (tranches).\r\n *\r\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\r\n * `_reserved` layout (verified against `state.rs` on\r\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\r\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\r\n * whatever bytes the program actually writes):\r\n *\r\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\r\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\r\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\r\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\r\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\r\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\r\n * (added later, #242) write into [10..18]/[18..26] regardless.\r\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\r\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\r\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\r\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\r\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\r\n * - This decoder reads both field sets as the raw bytes currently define\r\n * them (matching on-chain reality); it does NOT attempt to reconcile or\r\n * invalidate one set when the other is in use. Callers combining HWM and\r\n * the cooldown timelock on one pool should treat both `hwm*` and\r\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\r\n * against a direct on-chain read before trusting either.\r\n */\r\nexport interface StakePoolState {\r\n isInitialized: boolean;\r\n bump: number;\r\n vaultAuthorityBump: number;\r\n adminTransferred: boolean;\r\n marketResolved: boolean;\r\n\r\n slab: PublicKey;\r\n admin: PublicKey;\r\n collateralMint: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n\r\n totalDeposited: bigint;\r\n totalLpSupply: bigint;\r\n cooldownSlots: bigint;\r\n depositCap: bigint;\r\n totalFlushed: bigint;\r\n totalReturned: bigint;\r\n totalWithdrawn: bigint;\r\n\r\n percolatorProgram: PublicKey;\r\n\r\n /**\r\n * Pending admin for the two-step rotation (stake v2, offset 288).\r\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\r\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\r\n */\r\n pendingAdmin: PublicKey | null;\r\n\r\n // PERC-272: Fee yield fields\r\n totalFeesEarned: bigint;\r\n lastFeeAccrualSlot: bigint;\r\n lastVaultSnapshot: bigint;\r\n poolMode: number;\r\n\r\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\r\n // [0..8] discriminator\r\n // [8] version\r\n // [9] market_resolved\r\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\r\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\r\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\r\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\r\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\r\n // [24..32] PERC-313 hwm_last_epoch (u64)\r\n // [32] PERC-303 tranche_enabled\r\n // [33..41] PERC-303 junior_balance (u64)\r\n // [41..49] PERC-303 junior_total_lp (u64)\r\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\r\n // [51..59] N-realized_junior_loss (u64) — issue #161\r\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\r\n // [60..64] free\r\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\r\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\r\n\r\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\r\n hwmEnabled: boolean;\r\n epochHighWaterTvl: bigint;\r\n hwmFloorBps: number;\r\n hwmLastEpoch: bigint;\r\n\r\n // PERC-303: Tranche fields (from _reserved[32..51])\r\n trancheEnabled: boolean;\r\n juniorBalance: bigint;\r\n juniorTotalLp: bigint;\r\n juniorFeeMultBps: number;\r\n\r\n /**\r\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\r\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n pendingCooldownSlots: bigint;\r\n /**\r\n * #242 timelock: the slot at which the pending cooldown increase was\r\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n cooldownProposedAtSlot: bigint;\r\n /**\r\n * Cumulative insurance loss a fully-exited junior tranche permanently\r\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\r\n * total_pool_value() so recovered tokens don't windfall senior.\r\n */\r\n realizedJuniorLoss: bigint;\r\n /**\r\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\r\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\r\n * stay disabled — the wrapper roles cannot be moved back to an\r\n * admin-controlled key.\r\n */\r\n assetAdminBurned: boolean;\r\n /**\r\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\r\n * collateral actually recovered from the WRAPPER via the tag-23\r\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\r\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\r\n * insurance back out of the wrapper. Real struct field at offset 384..392\r\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\r\n *\r\n * Deliberately separate from `totalReturned`, which is also bumped by two\r\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\r\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\r\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\r\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\r\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\r\n */\r\n totalRecoveredFromWrapper: bigint | null;\r\n}\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v1 layout.\r\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\r\n * The _reserved block in v1 starts at offset 288; version byte = 1.\r\n *\r\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\r\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\r\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\r\n * migration is needed\"). v1/352-byte pools can only ever be observed as\r\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\r\n * redeploy (which abandons every existing market/pool wholesale — VERSION\r\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\r\n * detection exists purely to decode those pre-redeploy artifacts if you ever\r\n * need to; the ADOPTED program itself never creates a v1 pool.\r\n */\r\nexport const STAKE_POOL_SIZE_V1 = 352;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v2 layout.\r\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\r\n * The _reserved block in v2 starts at offset 320; version byte = 2.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\r\n * padding (every u64 field lands on an 8-aligned cumulative offset).\r\n *\r\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\r\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\r\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\r\n * still needs to construct a v2-shaped buffer explicitly.\r\n */\r\nexport const STAKE_POOL_SIZE_V2 = 384;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\r\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\r\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\r\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\r\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\r\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\r\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\r\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\r\n * instead of the broader (and gameable) `total_returned` counter — see\r\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\r\n * padding (the appended u64 lands on the already-8-aligned offset 384).\r\n */\r\nexport const STAKE_POOL_SIZE_V3 = 392;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\r\n * ADOPTED percolator-stake lineage creates. Currently equal to\r\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\r\n * constants in new code so a future version bump doesn't silently change the\r\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\r\n */\r\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\r\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\r\nexport const STAKE_POOL_CURRENT_VERSION = 3;\r\n\r\n/**\r\n * Decode a StakePool account from raw data buffer.\r\n *\r\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\r\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\r\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\r\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\r\n * v2 and v3). The layout version is detected from the data length before\r\n * reading the discriminator.\r\n *\r\n * v1/v2 support exists only to decode legacy pools created before the\r\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\r\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\r\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\r\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\r\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\r\n * on-chain `_reserved` layout collision).\r\n *\r\n * Uses DataView for all u64/u16 reads — browser-safe.\r\n */\r\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\r\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\r\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\r\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\r\n if (!isV3 && !isV2 && !isV1) {\r\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\r\n }\r\n\r\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\r\n // AFTER _reserved, not inside it, so the block start doesn't move again).\r\n const reservedOffset = isV1 ? 288 : 320;\r\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\r\n const version = data[reservedOffset + 8];\r\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\r\n if (version !== expectedVersion) {\r\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\r\n }\r\n\r\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\r\n let off = 0;\r\n const isInitialized = bytes[off] === 1; off += 1;\r\n const bump = bytes[off]; off += 1;\r\n const vaultAuthorityBump = bytes[off]; off += 1;\r\n const adminTransferred = bytes[off] === 1; off += 1;\r\n off += 4; // _padding\r\n\r\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n const totalDeposited = readU64LE(bytes, off); off += 8;\r\n const totalLpSupply = readU64LE(bytes, off); off += 8;\r\n const cooldownSlots = readU64LE(bytes, off); off += 8;\r\n const depositCap = readU64LE(bytes, off); off += 8;\r\n const totalFlushed = readU64LE(bytes, off); off += 8;\r\n const totalReturned = readU64LE(bytes, off); off += 8;\r\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\r\n\r\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n // PERC-272 fields (offset 256..288 in both v1 and v2)\r\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\r\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\r\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\r\n const poolMode = bytes[off]; off += 1;\r\n off += 7; // _mode_padding (off is now 288)\r\n\r\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\r\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\r\n let pendingAdmin: PublicKey | null = null;\r\n if (isV2 || isV3) {\r\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\r\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\r\n ? null\r\n : new PublicKey(pendingAdminBytes);\r\n }\r\n\r\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\r\n const reservedStart = off;\r\n // _reserved[8] = version (skipped)\r\n // _reserved[9] = market_resolved\r\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\r\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\r\n const marketResolved = bytes[reservedStart + 9] === 1;\r\n const hwmEnabled = bytes[reservedStart + 10] === 1;\r\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\r\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\r\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\r\n\r\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\r\n const trancheEnabled = bytes[reservedStart + 32] === 1;\r\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\r\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\r\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\r\n\r\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\r\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\r\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\r\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\r\n\r\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\r\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\r\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\r\n\r\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\r\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\r\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\r\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\r\n const totalRecoveredFromWrapper = isV3\r\n ? readU64LE(bytes, reservedStart + 64)\r\n : null;\r\n\r\n return {\r\n isInitialized,\r\n bump,\r\n vaultAuthorityBump,\r\n adminTransferred,\r\n marketResolved,\r\n slab,\r\n admin,\r\n collateralMint,\r\n lpMint,\r\n vault,\r\n totalDeposited,\r\n totalLpSupply,\r\n cooldownSlots,\r\n depositCap,\r\n totalFlushed,\r\n totalReturned,\r\n totalWithdrawn,\r\n percolatorProgram,\r\n pendingAdmin,\r\n totalFeesEarned,\r\n lastFeeAccrualSlot,\r\n lastVaultSnapshot,\r\n poolMode,\r\n hwmEnabled,\r\n epochHighWaterTvl,\r\n hwmFloorBps,\r\n hwmLastEpoch,\r\n trancheEnabled,\r\n juniorBalance,\r\n juniorTotalLp,\r\n juniorFeeMultBps,\r\n pendingCooldownSlots,\r\n cooldownProposedAtSlot,\r\n realizedJuniorLoss,\r\n assetAdminBurned,\r\n totalRecoveredFromWrapper,\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// StakeDeposit PDA decoder\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Size of StakeDeposit on-chain (bytes). */\r\nexport const STAKE_DEPOSIT_SIZE = 152;\r\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\r\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\r\n\r\n/** Decoded StakeDeposit PDA state. */\r\nexport interface StakeDepositState {\r\n isInitialized: boolean;\r\n bump: number;\r\n pool: PublicKey;\r\n user: PublicKey;\r\n lastDepositSlot: bigint;\r\n lpAmount: bigint;\r\n}\r\n\r\n/**\r\n * Decode a StakeDeposit PDA account from raw data.\r\n *\r\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\r\n * [0] is_initialized u8\r\n * [1] bump u8\r\n * [2..8] _padding\r\n * [8..40] pool [u8; 32]\r\n * [40..72] user [u8; 32]\r\n * [72..80] last_deposit_slot u64\r\n * [80..88] lp_amount u64\r\n * [88..152] _reserved\r\n */\r\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\r\n if (data.length < STAKE_DEPOSIT_SIZE) {\r\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\r\n }\r\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\r\n return {\r\n isInitialized: data[0] === 1,\r\n bump: data[1],\r\n pool: new PublicKey(data.subarray(8, 40)),\r\n user: new PublicKey(data.subarray(40, 72)),\r\n lastDepositSlot: readU64LE(data, 72),\r\n lpAmount: readU64LE(data, 80),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Account Specs (for building TransactionInstructions)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface StakeAccounts {\r\n /** InitPool accounts */\r\n initPool: {\r\n admin: PublicKey;\r\n slab: PublicKey;\r\n pool: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n collateralMint: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n /** Deposit accounts */\r\n deposit: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vault: PublicKey;\r\n lpMint: PublicKey;\r\n userLpAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** Withdraw accounts */\r\n withdraw: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userLpAta: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** FlushToInsurance accounts (CPI from stake → percolator) */\r\n flushToInsurance: {\r\n caller: PublicKey;\r\n pool: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n wrapperVault: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n}\r\n\r\n/**\r\n * Build account keys for InitPool instruction.\r\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\r\n *\r\n * @param a - Named accounts for the InitPool instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function initPoolAccounts(\r\n a: StakeAccounts['initPool'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Deposit instruction.\r\n *\r\n * @param a - Named accounts for the Deposit instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function depositAccounts(\r\n a: StakeAccounts['deposit'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Withdraw instruction.\r\n *\r\n * @param a - Named accounts for the Withdraw instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function withdrawAccounts(\r\n a: StakeAccounts['withdraw'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for FlushToInsurance instruction.\r\n *\r\n * @param a - Named accounts for the FlushToInsurance instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function flushToInsuranceAccounts(\r\n a: StakeAccounts['flushToInsurance'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.caller, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n","/**\r\n * @module adl\r\n * Percolator ADL (Auto-Deleveraging) client utilities.\r\n *\r\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\r\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\r\n * The most profitable positions on the dominant side are deleveraged first.\r\n *\r\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\r\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\r\n * instruction being structurally available to any signer.\r\n *\r\n * API surface:\r\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\r\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\r\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\r\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\r\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\r\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\r\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\r\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\r\n * - AdlRankingResult — full ranking with trigger status\r\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\r\n * - AdlApiRanking — single ranked position from /api/adl/rankings\r\n * - AdlApiResult — full result from /api/adl/rankings\r\n * - AdlSide — \"long\" | \"short\"\r\n */\r\n\r\nimport {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n} from \"@solana/web3.js\";\r\nimport {\r\n fetchSlab,\r\n parseAllAccounts,\r\n parseEngine,\r\n parseConfig,\r\n detectSlabLayout,\r\n AccountKind,\r\n Account,\r\n SlabLayout,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Position side derived from positionSize sign. */\r\nexport type AdlSide = \"long\" | \"short\";\r\n\r\nconst V17_ADL_UNSUPPORTED_MESSAGE =\r\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\r\n\r\n/**\r\n * A ranked open position for ADL purposes.\r\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\r\n * and will be deleveraged first.\r\n */\r\nexport interface AdlRankedPosition {\r\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\r\n idx: number;\r\n /** Owner public key. */\r\n owner: PublicKey;\r\n /** Raw position size (i128 — negative = short, positive = long). */\r\n positionSize: bigint;\r\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\r\n pnl: bigint;\r\n /** Capital at entry in lamports (u128). */\r\n capital: bigint;\r\n /**\r\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\r\n * pnlPct = pnl * 10_000 / capital.\r\n * Higher = more profitable = deleveraged first.\r\n */\r\n pnlPct: bigint;\r\n /** Long or short. */\r\n side: AdlSide;\r\n /**\r\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\r\n * `-1` if position size is zero (inactive).\r\n */\r\n adlRank: number;\r\n}\r\n\r\n/**\r\n * Result of `fetchAdlRankedPositions`.\r\n */\r\nexport interface AdlRankingResult {\r\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\r\n ranked: AdlRankedPosition[];\r\n /**\r\n * Longs ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\r\n */\r\n longs: AdlRankedPosition[];\r\n /**\r\n * Shorts ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\r\n * unrealised gain for the short-side holder).\r\n */\r\n shorts: AdlRankedPosition[];\r\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\r\n isTriggered: boolean;\r\n /** pnl_pos_tot from engine state. */\r\n pnlPosTot: bigint;\r\n /** max_pnl_cap from market config. */\r\n maxPnlCap: bigint;\r\n /**\r\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\r\n *\r\n * `null` when the side cannot be determined — either engine state could not be\r\n * parsed at all, OR the detected slab layout carries no open-interest fields.\r\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\r\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\r\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\r\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\r\n *\r\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\r\n * convention, not an on-chain guarantee — the deployed wrapper\r\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\r\n */\r\n dominantSide: AdlSide | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute PnL% in basis points for a position.\r\n * Returns 0n when capital is 0 to avoid division by zero.\r\n */\r\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\r\n if (capital === 0n) return 0n;\r\n return (pnl * 10_000n) / capital;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check whether ADL is currently triggered on a slab.\r\n *\r\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\r\n *\r\n * @param slabData - Raw slab account bytes.\r\n * @returns true if ADL is triggered.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = await fetchSlab(connection, slabKey);\r\n * if (isAdlTriggered(data)) {\r\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\r\n * }\r\n * ```\r\n */\r\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n if (!layout) return false;\r\n try {\r\n const engine = parseEngine(slabData);\r\n if (engine.pnlPosTot === 0n) return false;\r\n const config = parseConfig(slabData, layout);\r\n if (config.maxPnlCap === 0n) return false;\r\n return engine.pnlPosTot > config.maxPnlCap;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\r\n *\r\n * Positions are ranked separately per side:\r\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\r\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\r\n *\r\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\r\n * the position at rank 0 of the dominant side is deleveraged first.\r\n *\r\n * @param connection - Solana connection.\r\n * @param slab - Slab (market) public key.\r\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\r\n *\r\n * @example\r\n * ```ts\r\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\r\n * if (isTriggered && longs.length > 0) {\r\n * const target = longs[0]; // highest PnL long\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankedPositions(\r\n connection: Connection,\r\n slab: PublicKey\r\n): Promise {\r\n const data = await fetchSlab(connection, slab);\r\n return rankAdlPositions(data);\r\n}\r\n\r\n/**\r\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\r\n * Useful when you already have the slab data (e.g., from a subscription).\r\n */\r\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n\r\n let pnlPosTot = 0n;\r\n let dominantSide: AdlSide | null = null;\r\n try {\r\n const engine = parseEngine(slabData);\r\n pnlPosTot = engine.pnlPosTot;\r\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\r\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\r\n // comparing them would fabricate \"long\" from absent data.\r\n const hasOiFields =\r\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\r\n if (hasOiFields) {\r\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\r\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\r\n }\r\n } catch (err) {\r\n console.warn(\r\n `[rankAdlPositions] parseEngine failed:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n let maxPnlCap = 0n;\r\n let isTriggered = false;\r\n if (layout) {\r\n try {\r\n const config = parseConfig(slabData, layout);\r\n maxPnlCap = config.maxPnlCap;\r\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\r\n } catch {\r\n // If config parse fails, leave isTriggered=false; ranking still useful.\r\n }\r\n }\r\n\r\n // Parse all used accounts.\r\n const accounts = parseAllAccounts(slabData);\r\n\r\n // Build ranked position list (user accounts with non-zero position only).\r\n const positions: AdlRankedPosition[] = [];\r\n for (const { idx, account } of accounts) {\r\n if (account.kind !== AccountKind.User) continue;\r\n if (account.positionSize === 0n) continue;\r\n\r\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\r\n // For shorts, positionSize is negative — PnL computation is symmetric:\r\n // a short profits when price falls, so pnl stored in the slab already\r\n // reflects mark-to-market gain/loss for both sides.\r\n const pnlPct = computePnlPct(account.pnl, account.capital);\r\n\r\n positions.push({\r\n idx,\r\n owner: account.owner,\r\n positionSize: account.positionSize,\r\n pnl: account.pnl,\r\n capital: account.capital,\r\n pnlPct,\r\n side,\r\n adlRank: -1, // assigned below\r\n });\r\n }\r\n\r\n // Rank longs: descending pnlPct (most profitable first).\r\n const longs = positions\r\n .filter(p => p.side === \"long\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n longs.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\r\n // magnitude, but pnlPct can be negative; sort descending still puts\r\n // the \"least negative\" aka \"most profitable\" short first).\r\n const shorts = positions\r\n .filter(p => p.side === \"short\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n shorts.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\r\n const ranked = [...longs, ...shorts].sort(\r\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\r\n );\r\n\r\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\r\n}\r\n\r\n/**\r\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\r\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\r\n * utilities remain available.\r\n *\r\n * This function is kept as a deprecated compatibility stub so consumers get a\r\n * deterministic error instead of a lower-level removed-instruction throw.\r\n *\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key for this market.\r\n * @param programId - Percolator program ID.\r\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\r\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\r\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\r\n */\r\nexport function buildAdlInstruction(\r\n _caller: PublicKey,\r\n _slab: PublicKey,\r\n _oracle: PublicKey,\r\n _programId: PublicKey,\r\n targetIdx: number,\r\n _backupOracles: PublicKey[] = []\r\n): TransactionInstruction {\r\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\r\n throw new Error(\r\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\r\n );\r\n }\r\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\r\n}\r\n\r\n/**\r\n * Choose which ranked position an ADL should target.\r\n *\r\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\r\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\r\n * a test routed through it could not observe the choice.\r\n *\r\n * - An explicit `preferSide` always wins.\r\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\r\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\r\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\r\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\r\n * a candidate, nothing more.\r\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\r\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\r\n * rather than guessing a side.\r\n */\r\nexport function selectAdlTarget(\r\n ranking: Pick,\r\n preferSide?: AdlSide,\r\n): AdlRankedPosition | undefined {\r\n if (preferSide === \"long\") return ranking.longs[0];\r\n if (preferSide === \"short\") return ranking.shorts[0];\r\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\r\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\r\n return ranking.ranked[0];\r\n}\r\n\r\n/**\r\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\r\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\r\n *\r\n * Returns `null` when ADL is not triggered or no eligible positions exist.\r\n *\r\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\r\n * When a target IS found it calls `buildAdlInstruction`, which throws\r\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\r\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\r\n * revision of this note claimed it did, which was simply wrong.) It is kept for\r\n * v12 slabs and for when an equivalent v17 instruction lands; the target\r\n * selection in `selectAdlTarget` stays valid either way.\r\n *\r\n * @param connection - Solana connection.\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key.\r\n * @param programId - Percolator program ID.\r\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\r\n * If omitted, picks the dominant side's (greater net OI)\r\n * top-ranked position — or the overall top-ranked position\r\n * when dominantSide is null (engine unparseable, or a\r\n * layout with no OI fields such as V0/V2/v12.15).\r\n * @param backupOracles - Optional extra oracle accounts.\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = await buildAdlTransaction(\r\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\r\n * );\r\n * if (ix) {\r\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\r\n * }\r\n * ```\r\n */\r\nexport async function buildAdlTransaction(\r\n connection: Connection,\r\n caller: PublicKey,\r\n slab: PublicKey,\r\n oracle: PublicKey,\r\n programId: PublicKey,\r\n preferSide?: AdlSide,\r\n backupOracles: PublicKey[] = []\r\n): Promise {\r\n const ranking = await fetchAdlRankedPositions(connection, slab);\r\n\r\n if (!ranking.isTriggered) return null;\r\n\r\n const target = selectAdlTarget(ranking, preferSide);\r\n\r\n if (!target) return null;\r\n\r\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AdlEvent — on-chain log decoder (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\r\n *\r\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\r\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\r\n *\r\n * Fields:\r\n * - `tag` — always `0xAD1E_0001` (2970353665n)\r\n * - `targetIdx` — slab account index that was deleveraged\r\n * - `price` — oracle price used (in market price units, e.g. e6)\r\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\r\n *\r\n * @example\r\n * ```ts\r\n * const logs = tx.meta?.logMessages ?? [];\r\n * const event = parseAdlEvent(logs);\r\n * if (event) {\r\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\r\n * }\r\n * ```\r\n */\r\nexport interface AdlEvent {\r\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\r\n tag: bigint;\r\n /** Slab account index that was deleveraged. */\r\n targetIdx: number;\r\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\r\n price: bigint;\r\n /**\r\n * Absolute position size closed (reassembled from lo+hi u64).\r\n * This is the i128 absolute value — always non-negative.\r\n */\r\n closedAbs: bigint;\r\n}\r\n\r\n/** Magic discriminator for the ADL event log line. */\r\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\r\n\r\n/**\r\n * Parse the AdlEvent from a transaction's log messages.\r\n *\r\n * Searches for a \"Program log: \" line where the first\r\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\r\n *\r\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\r\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\r\n * by this program ID are accepted. Events from CPI-called programs (which can\r\n * produce identical `Program log:` lines) are silently ignored. Pass the\r\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\r\n * Omit only in contexts where the full log has already been filtered.\r\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\r\n *\r\n * @example\r\n * ```ts\r\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\r\n * if (event) {\r\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\r\n * }\r\n * ```\r\n */\r\nexport function parseAdlEvent(\r\n logs: string[],\r\n percolatorProgramId?: string,\r\n): AdlEvent | null {\r\n // Track whether we are currently inside a top-level Percolator invocation.\r\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\r\n let insidePercolator = percolatorProgramId === undefined;\r\n let cpiDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n if (percolatorProgramId !== undefined) {\r\n // Detect Percolator entry / exit.\r\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\r\n insidePercolator = true;\r\n cpiDepth = 0;\r\n continue;\r\n }\r\n if (\r\n line.startsWith(`Program ${percolatorProgramId} success`) ||\r\n line.startsWith(`Program ${percolatorProgramId} failed`)\r\n ) {\r\n insidePercolator = false;\r\n continue;\r\n }\r\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\r\n if (insidePercolator) {\r\n if (/^Program \\S+ invoke/.test(line)) {\r\n cpiDepth++;\r\n continue;\r\n }\r\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\r\n cpiDepth = Math.max(0, cpiDepth - 1);\r\n continue;\r\n }\r\n }\r\n // Skip log lines that are not inside Percolator or are from a CPI callee.\r\n if (!insidePercolator || cpiDepth > 0) continue;\r\n }\r\n\r\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\r\n const match = line.match(\r\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\r\n );\r\n if (!match) continue;\r\n\r\n let tag: bigint;\r\n try {\r\n tag = BigInt(match[1]);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (tag !== ADL_EVENT_TAG) continue;\r\n\r\n try {\r\n const targetIdx = Number(BigInt(match[2]));\r\n const price = BigInt(match[3]);\r\n const closedLo = BigInt(match[4]);\r\n const closedHi = BigInt(match[5]);\r\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\r\n const closedAbs = (closedHi << 64n) | closedLo;\r\n return { tag, targetIdx, price, closedAbs };\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A single ranked position as returned by the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiRanking {\r\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\r\n rank: number;\r\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\r\n idx: number;\r\n /** Absolute PnL (lamports) as a decimal string. */\r\n pnlAbs: string;\r\n /** Capital at entry (lamports) as a decimal string. */\r\n capital: string;\r\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\r\n pnlPctMillionths: string;\r\n}\r\n\r\n/**\r\n * Full result from the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiResult {\r\n slabAddress: string;\r\n /** pnl_pos_tot from slab engine state (decimal string). */\r\n pnlPosTot: string;\r\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\r\n maxPnlCap: string;\r\n /** Insurance fund balance (decimal string). */\r\n insuranceFundBalance: string;\r\n /** Insurance fund lifetime fee revenue (decimal string). */\r\n insuranceFundFeeRevenue: string;\r\n /** Insurance utilization in basis points (0–10000). */\r\n insuranceUtilizationBps: number;\r\n /** true if pnlPosTot > maxPnlCap. */\r\n capExceeded: boolean;\r\n /** true if insurance fund is fully depleted (balance == 0). */\r\n insuranceDepleted: boolean;\r\n /** true if utilization BPS exceeds the configured ADL threshold. */\r\n utilizationTriggered: boolean;\r\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\r\n adlNeeded: boolean;\r\n /** Excess PnL above cap (decimal string). */\r\n excess: string;\r\n /** Ranked positions (empty if adlNeeded=false). */\r\n rankings: AdlApiRanking[];\r\n}\r\n\r\n/**\r\n * Fetch ADL rankings from the Percolator API.\r\n *\r\n * Calls `GET /api/adl/rankings?slab=
` and returns the\r\n * parsed result. Use this from the frontend or keeper to determine ADL\r\n * trigger status and pick the target index.\r\n *\r\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\r\n * @param slab - Slab (market) public key or base58 address string.\r\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\r\n * @returns Parsed `AdlApiResult`.\r\n * @throws On HTTP error or JSON parse failure.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\r\n * if (result.adlNeeded && result.rankings.length > 0) {\r\n * const target = result.rankings[0]; // rank 1 = highest PnL%\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankings(\r\n apiBase: string,\r\n slab: PublicKey | string,\r\n fetchFn: typeof fetch = fetch,\r\n): Promise {\r\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\r\n const base = apiBase.replace(/\\/$/, \"\");\r\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\r\n\r\n const res = await fetchFn(url);\r\n if (!res.ok) {\r\n let body = \"\";\r\n try { body = await res.text(); } catch { /* ignore */ }\r\n throw new Error(\r\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\r\n );\r\n }\r\n\r\n const json: unknown = await res.json();\r\n\r\n // Runtime validation — the API response shape is not guaranteed\r\n if (typeof json !== \"object\" || json === null) {\r\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\r\n }\r\n const obj = json as Record;\r\n if (!Array.isArray(obj.rankings)) {\r\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\r\n }\r\n if (typeof obj.adlNeeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\r\n }\r\n if (typeof obj.capExceeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\r\n }\r\n if (typeof obj.slabAddress !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\r\n }\r\n if (typeof obj.pnlPosTot !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\r\n }\r\n if (typeof obj.maxPnlCap !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\r\n }\r\n for (const entry of obj.rankings) {\r\n if (typeof entry !== \"object\" || entry === null) {\r\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\r\n }\r\n const r = entry as Record;\r\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\r\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\r\n }\r\n }\r\n\r\n return json as AdlApiResult;\r\n}\r\n","/**\r\n * @module backing-bucket\r\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\r\n *\r\n * ## Why this module exists\r\n *\r\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\r\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\r\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\r\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\r\n * predicate.\r\n *\r\n * ## Why lapsing is routine, not exceptional\r\n *\r\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\r\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\r\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\r\n * bucket and only computes a fresh horizon once the bucket is no longer\r\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\r\n * far-future expiry defers the lapse; it does not prevent it.\r\n *\r\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\r\n *\r\n * | Attempt against a lapsed domain | Result |\r\n * |---|---|\r\n * | settle a **loss** | `EngineLockActive` Custom(21) |\r\n * | settle a **gain** | `EngineStale` Custom(19) |\r\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\r\n *\r\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\r\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\r\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\r\n * keeper duty, alongside the fee crank.\r\n *\r\n * ## Layout provenance\r\n *\r\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\r\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\r\n *\r\n * ```\r\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\r\n * BackingBucketV16Account size=97\r\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\r\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\r\n * 88 expiry_slot 96 status\r\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\r\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\r\n * ```\r\n *\r\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\r\n */\r\n\r\nimport {\r\n V17_MARKET_GROUP_OFF,\r\n V17_MARKET_GROUP_LEN,\r\n V17_MARKET_ASSET_SLOT_LEN,\r\n isV17MarketAccount,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Little-endian readers (module-local, matching slab.ts's private helpers)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8At(data: Uint8Array, off: number): number {\r\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\r\n return data[off]!;\r\n}\r\n\r\nfunction readU32LEAt(data: Uint8Array, off: number): number {\r\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\r\n}\r\n\r\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\r\n}\r\n\r\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\r\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\r\n const lo = dv.getBigUint64(0, true);\r\n const hi = dv.getBigUint64(8, true);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Layout constants — all verified with offset_of! (see module doc)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\r\nexport const V17_GROUP_CONFIG_REL = 32;\r\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\r\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\r\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\r\nexport const V17_GROUP_MODE_REL = 626;\r\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\r\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\r\n\r\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\r\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\r\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\r\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\r\n/** `size_of::()`. */\r\nexport const V17_BACKING_BUCKET_LEN = 97;\r\n\r\n// BackingBucketV16Account field offsets, relative to the bucket start.\r\nconst BB_MARKET_ID = 0;\r\nconst BB_FRESH_UNLIENED = 8;\r\nconst BB_VALID_LIENED = 24;\r\nconst BB_CONSUMED_LIENED = 40;\r\nconst BB_IMPAIRED_LIENED = 56;\r\nconst BB_UTILIZATION_FEE = 72;\r\nconst BB_EXPIRY_SLOT = 88;\r\nconst BB_STATUS = 96;\r\n\r\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\r\nexport const V17_MARKET_MODE_LIVE = 0;\r\n\r\n/**\r\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\r\n * serialized as a single `u8` in declaration order.\r\n *\r\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\r\n */\r\nexport enum BackingBucketStatus {\r\n Empty = 0,\r\n Fresh = 1,\r\n Expired = 2,\r\n Impaired = 3,\r\n}\r\n\r\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\r\nexport function backingBucketStatusName(status: number): string {\r\n switch (status) {\r\n case BackingBucketStatus.Empty:\r\n return \"Empty\";\r\n case BackingBucketStatus.Fresh:\r\n return \"Fresh\";\r\n case BackingBucketStatus.Expired:\r\n return \"Expired\";\r\n case BackingBucketStatus.Impaired:\r\n return \"Impaired\";\r\n default:\r\n return `Unknown(${status})`;\r\n }\r\n}\r\n\r\n/** One source-domain backing bucket, decoded from a v17 market account. */\r\nexport interface BackingBucketV17 {\r\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\r\n domain: number;\r\n /** `domain / 2` — the asset slot this domain belongs to. */\r\n assetIndex: number;\r\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\r\n side: \"long\" | \"short\";\r\n /** `BackingBucketV16Account::market_id`. */\r\n marketId: bigint;\r\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\r\n freshUnlienedBackingNum: bigint;\r\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\r\n validLienedBackingNum: bigint;\r\n /** Principal already consumed by settlement. */\r\n consumedLienedBackingNum: bigint;\r\n /** Principal whose lien has been impaired. */\r\n impairedLienedBackingNum: bigint;\r\n /** Utilization fees accrued to this bucket. */\r\n utilizationFeeEarnings: bigint;\r\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\r\n expirySlot: bigint;\r\n /** Raw status byte. */\r\n status: number;\r\n /** `backingBucketStatusName(status)`. */\r\n statusName: string;\r\n /**\r\n * `status === Fresh && nowSlot >= expirySlot`.\r\n *\r\n * This is the *deadlock* condition — settlement against this domain fails in both\r\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\r\n * which additionally applies the wrapper's mode and domain-bound gates.\r\n */\r\n lapsed: boolean;\r\n /**\r\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\r\n * See {@link isBackingBucketExpirable} for the full derivation.\r\n */\r\n expirable: boolean;\r\n}\r\n\r\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\r\nexport interface BackingBucketMarketState {\r\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\r\n mode: number;\r\n /** `header.current_slot` — the engine's own monotone slot counter. */\r\n headerCurrentSlot: bigint;\r\n /**\r\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\r\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\r\n */\r\n nowSlot: bigint;\r\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\r\n maxMarketSlots: number;\r\n /** Asset slots physically present in the account buffer. */\r\n physicalAssetSlots: number;\r\n /**\r\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\r\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\r\n * this index are never expirable; see {@link isBackingBucketExpirable}.\r\n */\r\n addressableDomainCount: number;\r\n /** One entry per addressable domain, ascending by `domain`. */\r\n buckets: BackingBucketV17[];\r\n}\r\n\r\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\r\nexport interface BackingBucketExpiryContext {\r\n /** `header.mode`. */\r\n mode: number;\r\n /** `max(chainSlot, header.current_slot)`. */\r\n nowSlot: bigint;\r\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\r\n addressableDomainCount: number;\r\n}\r\n\r\n/**\r\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\r\n *\r\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\r\n * program rather than from prose. In order of evaluation on chain:\r\n *\r\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\r\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\r\n * market reaches the same transition through the engine's own\r\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\r\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\r\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\r\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\r\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\r\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\r\n * may be *configured* for more slots than its account was *sized* for.\r\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\r\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\r\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\r\n * both deadlocked and expirable, and the two boundaries agree\r\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\r\n *\r\n * `now_slot` is never caller-supplied — the program computes\r\n * `max(Clock::get().slot, header.current_slot)` itself\r\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\r\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\r\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\r\n * bricked. It cannot produce a false positive, because the program recomputes the same\r\n * `max` and no caller can lower it.\r\n *\r\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\r\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\r\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\r\n * two more u128 reads to defend against something that indicates corruption anyway.\r\n *\r\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\r\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\r\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\r\n *\r\n * @example\r\n * ```ts\r\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\r\n * for (const b of state.buckets) {\r\n * if (isBackingBucketExpirable(b, state)) {\r\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isBackingBucketExpirable(\r\n bucket: Pick,\r\n ctx: BackingBucketExpiryContext,\r\n): boolean {\r\n // (1) Live-only mode gate.\r\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\r\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\r\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\r\n // (4) The lapse condition, exactly as the engine states it.\r\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\r\n return ctx.nowSlot >= bucket.expirySlot;\r\n}\r\n\r\n/** Options for {@link parseBackingBucketsV17}. */\r\nexport interface ParseBackingBucketsOptions {\r\n /**\r\n * The current chain slot (`connection.getSlot()`).\r\n *\r\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\r\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\r\n * lapses, never over-report them) but a keeper should always supply it — a market whose\r\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\r\n * bricked.\r\n */\r\n chainSlot?: bigint | number;\r\n}\r\n\r\n/**\r\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\r\n *\r\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\r\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\r\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\r\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\r\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketPk);\r\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\r\n * chainSlot: await connection.getSlot(),\r\n * });\r\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\r\n * ```\r\n */\r\nexport function parseBackingBucketsV17(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): BackingBucketMarketState {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n const groupOff = V17_MARKET_GROUP_OFF;\r\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\r\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\r\n const maxMarketSlots = readU32LEAt(\r\n data,\r\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\r\n );\r\n\r\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\r\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\r\n const chainSlot =\r\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\r\n if (chainSlot < 0n) {\r\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\r\n }\r\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\r\n\r\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\r\n const physicalAssetSlots = Math.max(\r\n 0,\r\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\r\n );\r\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\r\n const addressableDomainCount = addressableAssetSlots * 2;\r\n\r\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\r\n const buckets: BackingBucketV17[] = [];\r\n\r\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\r\n const engineBase =\r\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\r\n for (const side of [\"long\", \"short\"] as const) {\r\n const bucketOff =\r\n engineBase +\r\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\r\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\r\n\r\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\r\n const status = readU8At(data, bucketOff + BB_STATUS);\r\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\r\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\r\n\r\n const bucket: BackingBucketV17 = {\r\n domain,\r\n assetIndex,\r\n side,\r\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\r\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\r\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\r\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\r\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\r\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\r\n expirySlot,\r\n status,\r\n statusName: backingBucketStatusName(status),\r\n lapsed,\r\n expirable: false,\r\n };\r\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\r\n buckets.push(bucket);\r\n }\r\n }\r\n\r\n return {\r\n mode,\r\n headerCurrentSlot,\r\n nowSlot,\r\n maxMarketSlots,\r\n physicalAssetSlots,\r\n addressableDomainCount,\r\n buckets,\r\n };\r\n}\r\n\r\n/**\r\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\r\n *\r\n * Returns domain indices in ascending order, ready to feed straight into\r\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\r\n * common case on a healthy market, and the case in which a keeper must send nothing.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns Ascending list of expirable domain indices; empty when none are due.\r\n *\r\n * @example\r\n * ```ts\r\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\r\n * for (const domain of domains) {\r\n * tx.add(new TransactionInstruction({\r\n * programId: WRAPPER_ID,\r\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\r\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\r\n * }));\r\n * }\r\n * ```\r\n */\r\nexport function findExpirableBackingDomains(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): number[] {\r\n return parseBackingBucketsV17(data, opts)\r\n .buckets.filter((b) => b.expirable)\r\n .map((b) => b.domain);\r\n}\r\n","import {\r\n Connection,\r\n type Commitment,\r\n type ConnectionConfig,\r\n} from \"@solana/web3.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Configuration for exponential-backoff retry on RPC calls.\r\n *\r\n * @example\r\n * ```ts\r\n * const retryConfig: RetryConfig = {\r\n * maxRetries: 3,\r\n * baseDelayMs: 500,\r\n * maxDelayMs: 10_000,\r\n * retryableStatusCodes: [429, 502, 503],\r\n * };\r\n * ```\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts after the initial request fails.\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Base delay in ms for exponential backoff.\r\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\r\n * @default 500\r\n */\r\n baseDelayMs?: number;\r\n\r\n /**\r\n * Maximum delay in ms (backoff cap).\r\n * @default 10_000\r\n */\r\n maxDelayMs?: number;\r\n\r\n /**\r\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\r\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\r\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\r\n * jitter entirely (deterministic backoff).\r\n * @default 0.25\r\n */\r\n jitterFactor?: number;\r\n\r\n /**\r\n * HTTP status codes considered retryable.\r\n * Errors matching these codes (or containing their string representation)\r\n * will be retried.\r\n * @default [429, 502, 503, 504]\r\n */\r\n retryableStatusCodes?: number[];\r\n}\r\n\r\n/**\r\n * Configuration for a single RPC endpoint in the pool.\r\n *\r\n * @example\r\n * ```ts\r\n * const endpoint: RpcEndpointConfig = {\r\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\r\n * weight: 10,\r\n * label: \"helius-primary\",\r\n * };\r\n * ```\r\n */\r\nexport interface RpcEndpointConfig {\r\n /** RPC endpoint URL. */\r\n url: string;\r\n\r\n /**\r\n * Relative weight for round-robin selection.\r\n * Higher weight = more requests routed here.\r\n * @default 1\r\n */\r\n weight?: number;\r\n\r\n /**\r\n * Human-readable label for logging / diagnostics.\r\n * @default url hostname\r\n */\r\n label?: string;\r\n\r\n /**\r\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\r\n * merged into the Solana `Connection` constructor for this endpoint.\r\n */\r\n connectionConfig?: ConnectionConfig;\r\n}\r\n\r\n/**\r\n * Strategy for selecting the next RPC endpoint from the pool.\r\n *\r\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\r\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\r\n */\r\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\r\n\r\n/**\r\n * Full configuration for the RPC connection pool.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3, baseDelayMs: 500 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Use like a Connection — same surface\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n * ```\r\n */\r\nexport interface RpcPoolConfig {\r\n /**\r\n * One or more RPC endpoints. At least one is required.\r\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\r\n */\r\n endpoints: (RpcEndpointConfig | string)[];\r\n\r\n /**\r\n * How to pick the next endpoint.\r\n * @default \"failover\"\r\n */\r\n strategy?: SelectionStrategy;\r\n\r\n /**\r\n * Retry config applied to every `call()`.\r\n * Set to `false` to disable retries entirely.\r\n * @default { maxRetries: 3, baseDelayMs: 500 }\r\n */\r\n retry?: RetryConfig | false;\r\n\r\n /**\r\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\r\n * calls where supported, and is used as a deadline for the health probe.\r\n * @default 30_000\r\n */\r\n requestTimeoutMs?: number;\r\n\r\n /**\r\n * Default Solana commitment level for connections.\r\n * @default \"confirmed\"\r\n */\r\n commitment?: Commitment;\r\n\r\n /**\r\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n\r\n /**\r\n * Time in ms after which a continuously unhealthy endpoint is automatically\r\n * restored to healthy so it can be retried. Set to 0 to disable time-based\r\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\r\n * endpoints are exhausted).\r\n * @default 60_000\r\n */\r\n recoveryAfterMs?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Health Probe\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Result of an RPC health probe.\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\r\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\r\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\r\n * ```\r\n */\r\nexport interface RpcHealthResult {\r\n /** The endpoint that was probed. */\r\n endpoint: string;\r\n /** Whether the probe succeeded (getSlot returned without error). */\r\n healthy: boolean;\r\n /** Round-trip latency in milliseconds (0 if unhealthy). */\r\n latencyMs: number;\r\n /** Current slot height (0 if unhealthy). */\r\n slot: number;\r\n /** Error message if the probe failed. */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\r\n *\r\n * @param endpoint - RPC URL to probe\r\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\r\n * @returns Health result with latency and slot height\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\r\n * if (result.healthy) {\r\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\r\n * } else {\r\n * console.error(`RPC down: ${result.error}`);\r\n * }\r\n * ```\r\n */\r\nexport async function checkRpcHealth(\r\n endpoint: string,\r\n timeoutMs: number = 5_000,\r\n): Promise {\r\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\r\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\r\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\r\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\r\n const start = performance.now();\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: 1,\r\n method: \"getSlot\",\r\n params: [{ commitment: \"processed\" }],\r\n }),\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n const latencyMs = Math.round(performance.now() - start);\r\n if (!res.ok) {\r\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\r\n }\r\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\r\n if (json?.error || typeof json?.result !== \"number\") {\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: json?.error?.message ?? \"invalid getSlot response\",\r\n };\r\n }\r\n return { endpoint, healthy: true, latencyMs, slot: json.result };\r\n } catch (err) {\r\n const latencyMs = Math.round(performance.now() - start);\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved defaults for RetryConfig. */\r\ninterface ResolvedRetryConfig {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n jitterFactor: number;\r\n retryableStatusCodes: number[];\r\n}\r\n\r\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\r\n if (cfg === false) return null;\r\n const c = cfg ?? {};\r\n return {\r\n maxRetries: c.maxRetries ?? 3,\r\n baseDelayMs: c.baseDelayMs ?? 500,\r\n maxDelayMs: c.maxDelayMs ?? 10_000,\r\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\r\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\r\n };\r\n}\r\n\r\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\r\n if (typeof ep === \"string\") return { url: ep };\r\n return ep;\r\n}\r\n\r\nfunction endpointLabel(ep: RpcEndpointConfig): string {\r\n if (ep.label) return ep.label;\r\n try {\r\n return new URL(ep.url).hostname;\r\n } catch {\r\n return ep.url.slice(0, 40);\r\n }\r\n}\r\n\r\nfunction isRetryable(err: unknown, codes: number[]): boolean {\r\n if (!err) return false;\r\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\r\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\r\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\r\n // error shapes by name BEFORE any substring match below.\r\n const errName = (err as { name?: unknown })?.name;\r\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n for (const code of codes) {\r\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\r\n let timer: ReturnType;\r\n const promise = new Promise((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(message)), ms);\r\n });\r\n return { promise, cancel: () => clearTimeout(timer!) };\r\n}\r\n\r\n/** Sleep utility. */\r\nfunction sleep(ms: number): Promise {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\r\n * key, password) from a URL so it is safe for logging / status output.\r\n */\r\nfunction redactUrl(raw: string): string {\r\n try {\r\n const u = new URL(raw);\r\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\r\n for (const k of [...u.searchParams.keys()]) {\r\n if (sensitive.test(k)) {\r\n u.searchParams.set(k, \"***\");\r\n }\r\n }\r\n return u.toString();\r\n } catch {\r\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\r\n return raw;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// RpcPool\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-endpoint tracked state. */\r\ninterface EndpointState {\r\n config: RpcEndpointConfig;\r\n connection: Connection;\r\n label: string;\r\n weight: number;\r\n /** Consecutive failure count. Resets on success. */\r\n failures: number;\r\n /** Whether this endpoint is considered healthy. */\r\n healthy: boolean;\r\n /** Last probe latency (ms), -1 if never probed. */\r\n lastLatencyMs: number;\r\n /**\r\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\r\n * failure streak. Cleared on success or manual recovery. Used by the\r\n * time-based auto-recovery logic in `selectEndpoint`.\r\n */\r\n unhealthySince?: number;\r\n}\r\n\r\n/**\r\n * RPC connection pool with retry, failover, and round-robin support.\r\n *\r\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\r\n * that automatically retries transient errors and fails over to alternate\r\n * endpoints when one goes down.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Execute any Connection method through the pool\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n *\r\n * // Or get a raw connection for one-off use\r\n * const conn = pool.getConnection();\r\n *\r\n * // Health check all endpoints\r\n * const results = await pool.healthCheck();\r\n * ```\r\n */\r\nexport class RpcPool {\r\n private readonly endpoints: EndpointState[];\r\n private readonly strategy: SelectionStrategy;\r\n private readonly retryConfig: ResolvedRetryConfig | null;\r\n private readonly requestTimeoutMs: number;\r\n private readonly verbose: boolean;\r\n /** Time-based recovery window in ms (0 = disabled). */\r\n private readonly recoveryAfterMs: number;\r\n\r\n /** Round-robin index tracker. */\r\n private rrIndex: number = 0;\r\n\r\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\r\n private static readonly UNHEALTHY_THRESHOLD = 3;\r\n\r\n /** Minimum endpoints before auto-recovery is attempted. */\r\n private static readonly MIN_HEALTHY = 1;\r\n\r\n constructor(config: RpcPoolConfig) {\r\n if (!config.endpoints || config.endpoints.length === 0) {\r\n throw new Error(\"RpcPool: at least one endpoint is required\");\r\n }\r\n\r\n this.strategy = config.strategy ?? \"failover\";\r\n this.retryConfig = resolveRetryConfig(config.retry);\r\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\r\n this.verbose = config.verbose ?? true;\r\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\r\n\r\n const commitment = config.commitment ?? \"confirmed\";\r\n\r\n this.endpoints = config.endpoints.map(raw => {\r\n const ep = normalizeEndpoint(raw);\r\n const connConfig: ConnectionConfig = {\r\n commitment,\r\n ...ep.connectionConfig,\r\n };\r\n return {\r\n config: ep,\r\n connection: new Connection(ep.url, connConfig),\r\n label: endpointLabel(ep),\r\n weight: Math.max(1, ep.weight ?? 1),\r\n failures: 0,\r\n healthy: true,\r\n lastLatencyMs: -1,\r\n };\r\n });\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Public API\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Execute a function against a pooled connection with automatic retry\r\n * and failover.\r\n *\r\n * @param fn - Async function that receives a `Connection` and returns a result.\r\n * @returns The result of `fn`.\r\n * @throws The last error if all retries and failovers are exhausted.\r\n *\r\n * @example\r\n * ```ts\r\n * const balance = await pool.call(c => c.getBalance(pubkey));\r\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\r\n * ```\r\n */\r\n async call(fn: (connection: Connection) => Promise): Promise {\r\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\r\n let lastError: unknown;\r\n\r\n // Track which endpoints we have tried in this call to avoid infinite loops.\r\n const triedEndpoints = new Set();\r\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\r\n const maxTotalIterations = maxAttempts + this.endpoints.length;\r\n let totalIterations = 0;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (++totalIterations > maxTotalIterations) break;\r\n const epIdx = this.selectEndpoint(triedEndpoints);\r\n if (epIdx === -1) {\r\n // All endpoints exhausted\r\n break;\r\n }\r\n const ep = this.endpoints[epIdx];\r\n\r\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\r\n try {\r\n const result = await Promise.race([\r\n fn(ep.connection),\r\n timeout.promise,\r\n ]);\r\n\r\n // Success — reset failure count\r\n ep.failures = 0;\r\n ep.healthy = true;\r\n ep.unhealthySince = undefined;\r\n return result;\r\n } catch (err) {\r\n lastError = err;\r\n ep.failures++;\r\n\r\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\r\n ep.healthy = false;\r\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\r\n );\r\n }\r\n }\r\n\r\n const retryable = this.retryConfig\r\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\r\n : false;\r\n\r\n if (!retryable) {\r\n // For non-retryable errors in failover mode, try the next endpoint\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n // Don't count this as a retry attempt — just failover\r\n attempt--;\r\n if (triedEndpoints.size >= this.endpoints.length) break;\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Retryable error\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n // In failover mode, try next endpoint before retrying same one\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n }\r\n\r\n // Backoff before retry\r\n if (attempt < maxAttempts - 1 && this.retryConfig) {\r\n const delay = computeDelay(attempt, this.retryConfig);\r\n await sleep(delay);\r\n }\r\n } finally {\r\n timeout.cancel();\r\n }\r\n }\r\n\r\n // All attempts exhausted — try recovery before giving up\r\n this.maybeRecoverEndpoints();\r\n\r\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\r\n }\r\n\r\n /**\r\n * Get a raw `Connection` from the current preferred endpoint.\r\n * Useful when you need to pass a Connection to external code.\r\n *\r\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\r\n *\r\n * @returns Solana Connection from the current preferred endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const conn = pool.getConnection();\r\n * const balance = await conn.getBalance(pubkey);\r\n * ```\r\n */\r\n getConnection(): Connection {\r\n const idx = this.selectEndpoint();\r\n if (idx === -1) {\r\n // All marked unhealthy — reset and use first\r\n this.maybeRecoverEndpoints();\r\n return this.endpoints[0].connection;\r\n }\r\n return this.endpoints[idx].connection;\r\n }\r\n\r\n /**\r\n * Run a health check against all endpoints in the pool.\r\n *\r\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\r\n * @returns Array of health results, one per endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await pool.healthCheck();\r\n * for (const r of results) {\r\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\r\n * }\r\n * ```\r\n */\r\n async healthCheck(timeoutMs: number = 5_000): Promise {\r\n const results = await Promise.all(\r\n this.endpoints.map(async (ep) => {\r\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\r\n ep.lastLatencyMs = result.latencyMs;\r\n ep.healthy = result.healthy;\r\n if (result.healthy) {\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n result.endpoint = redactUrl(result.endpoint);\r\n return result;\r\n }),\r\n );\r\n return results;\r\n }\r\n\r\n /**\r\n * Get the number of endpoints in the pool.\r\n */\r\n get size(): number {\r\n return this.endpoints.length;\r\n }\r\n\r\n /**\r\n * Get the number of currently healthy endpoints.\r\n */\r\n get healthyCount(): number {\r\n return this.endpoints.filter(ep => ep.healthy).length;\r\n }\r\n\r\n /**\r\n * Get endpoint labels and their current status.\r\n *\r\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\r\n */\r\n status(): Array<{\r\n label: string;\r\n url: string;\r\n healthy: boolean;\r\n failures: number;\r\n lastLatencyMs: number;\r\n }> {\r\n return this.endpoints.map(ep => ({\r\n label: ep.label,\r\n url: redactUrl(ep.config.url),\r\n healthy: ep.healthy,\r\n failures: ep.failures,\r\n lastLatencyMs: ep.lastLatencyMs,\r\n }));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Internals\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Select the next endpoint based on strategy.\r\n * Returns -1 if no endpoint is available.\r\n */\r\n private selectEndpoint(exclude?: Set): number {\r\n // Time-based auto-recovery: restore endpoints that have been unhealthy\r\n // for longer than recoveryAfterMs so they can be retried.\r\n if (this.recoveryAfterMs > 0) {\r\n const now = Date.now();\r\n for (const ep of this.endpoints) {\r\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n if (this.verbose) {\r\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthy = this.endpoints\r\n .map((ep, i) => ({ ep, i }))\r\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\r\n\r\n if (healthy.length === 0) {\r\n // No healthy endpoints — try all non-excluded\r\n const remaining = this.endpoints\r\n .map((_, i) => i)\r\n .filter(i => !(exclude?.has(i)));\r\n return remaining.length > 0 ? remaining[0] : -1;\r\n }\r\n\r\n if (this.strategy === \"failover\") {\r\n // Return first healthy (by insertion order)\r\n return healthy[0].i;\r\n }\r\n\r\n // Weighted round-robin\r\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\r\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\r\n\r\n let cumulative = 0;\r\n for (const { ep, i } of healthy) {\r\n cumulative += ep.weight;\r\n if (this.rrIndex < cumulative) return i;\r\n }\r\n\r\n return healthy[healthy.length - 1].i;\r\n }\r\n\r\n /**\r\n * If all endpoints are unhealthy, reset them so we at least try again.\r\n */\r\n private maybeRecoverEndpoints(): void {\r\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\r\n if (healthyCount < RpcPool.MIN_HEALTHY) {\r\n if (this.verbose) {\r\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\r\n }\r\n for (const ep of this.endpoints) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone retry wrapper (for use without a full pool)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute an async function with exponential-backoff retry.\r\n *\r\n * Use this when you already have a `Connection` and just want retry logic\r\n * without a full pool.\r\n *\r\n * @param fn - Async function to execute\r\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\r\n * @returns Result of `fn`\r\n * @throws The last error if all retries are exhausted\r\n *\r\n * @example\r\n * ```ts\r\n * import { withRetry } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const slot = await withRetry(\r\n * () => conn.getSlot(),\r\n * { maxRetries: 3, baseDelayMs: 1000 },\r\n * );\r\n * ```\r\n */\r\nexport async function withRetry(\r\n fn: () => Promise,\r\n config?: RetryConfig,\r\n): Promise {\r\n const resolved = resolveRetryConfig(config) ?? {\r\n maxRetries: 3,\r\n baseDelayMs: 500,\r\n maxDelayMs: 10_000,\r\n jitterFactor: 0.25,\r\n retryableStatusCodes: [429, 502, 503, 504],\r\n };\r\n\r\n let lastError: unknown;\r\n const maxAttempts = resolved.maxRetries + 1;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (err) {\r\n lastError = err;\r\n\r\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\r\n throw err;\r\n }\r\n\r\n if (attempt < maxAttempts - 1) {\r\n const delay = computeDelay(attempt, resolved);\r\n await sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-export helpers for testing\r\n// ---------------------------------------------------------------------------\r\n\r\n/** @internal — exposed for unit tests only */\r\nexport const _internal = {\r\n isRetryable,\r\n computeDelay,\r\n resolveRetryConfig,\r\n normalizeEndpoint,\r\n endpointLabel,\r\n} as const;\r\n","import {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n Transaction,\r\n Keypair,\r\n SendOptions,\r\n Commitment,\r\n AccountMeta,\r\n ComputeBudgetProgram,\r\n} from \"@solana/web3.js\";\r\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\r\n\r\n/**\r\n * Rank of the three cluster confirmation levels the RPC reports in\r\n * `SignatureStatus.confirmationStatus`.\r\n */\r\nconst CONFIRMATION_RANK = {\r\n processed: 0,\r\n confirmed: 1,\r\n finalized: 2,\r\n} as const;\r\n\r\n/**\r\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\r\n * The deprecated aliases map onto their modern equivalents exactly as\r\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\r\n * recent -> processed.\r\n */\r\nfunction requiredConfirmationRank(commitment: Commitment): number {\r\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\r\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\r\n // aliases as:\r\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\r\n // 'finalized' | 'max' | 'root' -> requires finalized\r\n // everything else ('processed', 'recent') -> requires >= processed\r\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\r\n // meant a caller asking for `singleGossip` and observing only a `processed`\r\n // status was told the transaction had SETTLED — reintroducing exactly the\r\n // premature-settlement bug this function exists to prevent.\r\n switch (commitment) {\r\n case \"confirmed\":\r\n case \"single\":\r\n case \"singleGossip\":\r\n return CONFIRMATION_RANK.confirmed;\r\n case \"finalized\":\r\n case \"max\":\r\n case \"root\":\r\n return CONFIRMATION_RANK.finalized;\r\n case \"processed\":\r\n case \"recent\":\r\n default:\r\n return CONFIRMATION_RANK.processed;\r\n }\r\n}\r\n\r\n/**\r\n * True when an observed signature status is at least as strong as the level the\r\n * caller asked for. A merely \"processed\" transaction can still be dropped or\r\n * rolled back, so treating it as settled would reintroduce exactly the premature\r\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\r\n */\r\nfunction meetsCommitment(\r\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\r\n required: Commitment\r\n): boolean {\r\n if (!observed) return false;\r\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\r\n}\r\n\r\nexport interface BuildIxParams {\r\n programId: PublicKey;\r\n keys: AccountMeta[];\r\n data: Uint8Array | Buffer;\r\n}\r\n\r\n/**\r\n * Build a transaction instruction.\r\n */\r\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\r\n return new TransactionInstruction({\r\n programId: params.programId,\r\n keys: params.keys,\r\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\r\n // Cast to avoid Buffer polyfill issues in the browser.\r\n data: params.data as Buffer,\r\n });\r\n}\r\n\r\nexport interface TxResult {\r\n signature: string;\r\n slot: number;\r\n err: string | null;\r\n hint?: string;\r\n logs: string[];\r\n unitsConsumed?: number;\r\n}\r\n\r\nexport interface SimulateOrSendParams {\r\n connection: Connection;\r\n ix: TransactionInstruction;\r\n signers: Keypair[];\r\n simulate: boolean;\r\n commitment?: Commitment;\r\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\r\n /**\r\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\r\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\r\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\r\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\r\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\r\n * multiple of 1024 in [32768, 262144].\r\n */\r\n heapFrameBytes?: number;\r\n}\r\n\r\n/**\r\n * Simulate or send a transaction.\r\n * Returns consistent output for both modes.\r\n */\r\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\r\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\r\n\r\n/**\r\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\r\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\r\n */\r\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\r\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\r\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\r\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\r\n\r\nexport async function simulateOrSend(\r\n params: SimulateOrSendParams\r\n): Promise {\r\n const {\r\n connection,\r\n ix,\r\n signers,\r\n simulate,\r\n commitment,\r\n computeUnitLimit,\r\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\r\n } = params;\r\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\r\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\r\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\r\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\r\n\r\n if (typeof simulate !== \"boolean\") {\r\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\r\n }\r\n\r\n if (!signers.length) {\r\n throw new Error(\"simulateOrSend: at least one signer is required\");\r\n }\r\n\r\n if (computeUnitLimit !== undefined) {\r\n if (\r\n typeof computeUnitLimit !== \"number\" ||\r\n !Number.isInteger(computeUnitLimit) ||\r\n computeUnitLimit < 1 ||\r\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\r\n ) {\r\n throw new Error(\r\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\r\n );\r\n }\r\n }\r\n\r\n if (heapFrameBytes !== 0) {\r\n if (\r\n typeof heapFrameBytes !== \"number\" ||\r\n !Number.isInteger(heapFrameBytes) ||\r\n heapFrameBytes % 1024 !== 0 ||\r\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\r\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\r\n ) {\r\n throw new Error(\r\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\r\n );\r\n }\r\n }\r\n\r\n const tx = new Transaction();\r\n\r\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\r\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\r\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\r\n if (heapFrameBytes !== 0) {\r\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\r\n }\r\n\r\n // Add compute budget instruction if custom limit is specified\r\n if (computeUnitLimit !== undefined) {\r\n tx.add(\r\n ComputeBudgetProgram.setComputeUnitLimit({\r\n units: computeUnitLimit,\r\n })\r\n );\r\n }\r\n\r\n tx.add(ix);\r\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\r\n tx.recentBlockhash = latestBlockhash.blockhash;\r\n tx.feePayer = signers[0].publicKey;\r\n\r\n if (simulate) {\r\n try {\r\n tx.sign(...signers);\r\n const result = await connection.simulateTransaction(tx, signers);\r\n const logs = result.value.logs ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (result.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(result.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature: \"(simulated)\",\r\n slot: result.context.slot,\r\n err,\r\n hint,\r\n logs,\r\n unitsConsumed: result.value.unitsConsumed ?? undefined,\r\n };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"(simulated)\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n }\r\n\r\n // Send\r\n const options: SendOptions = {\r\n skipPreflight: false,\r\n preflightCommitment: effectiveCommitment,\r\n };\r\n\r\n // sendTransaction is its own try/catch: only here is it true that no\r\n // signature was ever produced, so signature: \"\" is the correct result.\r\n let signature: string;\r\n try {\r\n signature = await connection.sendTransaction(tx, signers, options);\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n\r\n // Fetch logs at the same finality level used for confirmation.\r\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\r\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\r\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\r\n\r\n try {\r\n const confirmation = await connection.confirmTransaction(\r\n {\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n },\r\n effectiveCommitment\r\n );\r\n\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (confirmation.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(confirmation.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature,\r\n slot: txInfo?.slot ?? 0,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n } catch (e: unknown) {\r\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\r\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\r\n // only that we didn't observe confirmation in time. Previously this branch discarded\r\n // the real signature obtained above and returned signature: \"\", which left the caller\r\n // with no way to check whether it's safe to retry — for a non-idempotent operation\r\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\r\n // transaction that had actually already landed. Check the real on-chain status before\r\n // reporting failure, and always return the real signature so the caller can verify\r\n // it themselves even if this fallback check also fails.\r\n const message = e instanceof Error ? e.message : String(e);\r\n try {\r\n const status = await connection.getSignatureStatus(signature, {\r\n searchTransactionHistory: true,\r\n });\r\n // Only treat the fallback lookup as authoritative when the observed level\r\n // actually satisfies the commitment the caller asked for. `status.value`\r\n // being non-null merely means the cluster has SEEN the transaction — at\r\n // \"processed\" it can still be dropped or rolled back, and reporting that\r\n // as a settled success would be the same premature-settlement bug #311 fixed.\r\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n if (status.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(status.value.err);\r\n }\r\n }\r\n return {\r\n signature,\r\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\r\n // `status.context.slot` is the RPC's head slot at query time — a\r\n // different, much later number — so it must not be used as the tx slot.\r\n slot: txInfo?.slot ?? status.value.slot,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n }\r\n if (status.value) {\r\n // Seen, but weaker than requested. Report it as unresolved rather than\r\n // settled, while still handing back the signature and the real landing slot.\r\n const observed = status.value.confirmationStatus ?? \"unknown\";\r\n return {\r\n signature,\r\n slot: status.value.slot,\r\n err:\r\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\r\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\r\n `Check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n } catch {\r\n // Status lookup itself failed too — fall through to the ambiguous result below,\r\n // which still carries the real signature instead of discarding it.\r\n }\r\n return {\r\n signature,\r\n slot: 0,\r\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Format transaction result for output.\r\n */\r\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\r\n if (jsonMode) {\r\n return JSON.stringify(result, null, 2);\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n if (result.err) {\r\n lines.push(`Error: ${result.err}`);\r\n if (result.hint) {\r\n lines.push(`Hint: ${result.hint}`);\r\n }\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.logs.length > 0) {\r\n lines.push(\"Logs:\");\r\n result.logs.forEach((log) => lines.push(` ${log}`));\r\n }\r\n } else {\r\n lines.push(`Signature: ${result.signature}`);\r\n lines.push(`Slot: ${result.slot}`);\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.signature !== \"(simulated)\") {\r\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * @module lighthouse\r\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\r\n *\r\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\r\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\r\n * scanning service. It adds assertion instructions to transactions that verify account\r\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\r\n * X lamports\").\r\n *\r\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\r\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\r\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\r\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\r\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\r\n * logic is correct.\r\n *\r\n * **Solution:** The SDK provides utilities to:\r\n * 1. Detect Lighthouse instructions in a transaction\r\n * 2. Strip them before sending\r\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\r\n * 4. Provide clear, actionable error messages for end users\r\n *\r\n * @example\r\n * ```ts\r\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\r\n *\r\n * // Before sending: strip injected Lighthouse IXs\r\n * const cleanIxs = stripLighthouseInstructions(instructions);\r\n *\r\n * // After error: classify and give user-friendly message\r\n * if (isLighthouseError(error)) {\r\n * console.warn(\"Wallet middleware blocked the transaction\");\r\n * }\r\n * ```\r\n */\r\n\r\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\r\n *\r\n * This is an immutable Anchor program deployed at slot 294,179,293.\r\n * Wallets like Phantom inject instructions from this program into user\r\n * transactions to enforce Blowfish security assertions.\r\n */\r\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\r\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\r\n);\r\n\r\n/** Base58 string form for fast comparison without PublicKey instantiation. */\r\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\r\n\r\n/**\r\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\r\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\r\n * when an account constraint check fails.\r\n */\r\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\r\n\r\n/**\r\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\r\n * All are in the Anchor error range (0x1770–0x1900+).\r\n */\r\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\r\n 0x1770, // InstructionMissing\r\n 0x1771, // InstructionFallbackNotFound\r\n 0x1772, // InstructionDidNotDeserialize\r\n 0x1773, // InstructionDidNotSerialize\r\n 0x1780, // IdlInstructionStub\r\n 0x1790, // ConstraintMut\r\n 0x1791, // ConstraintHasOne\r\n 0x1792, // ConstraintSigner\r\n 0x1793, // ConstraintRaw\r\n 0x1794, // ConstraintOwner\r\n 0x1795, // ConstraintRentExempt\r\n 0x1796, // ConstraintSeeds\r\n 0x1797, // ConstraintExecutable\r\n 0x1798, // ConstraintState\r\n 0x1799, // ConstraintAssociated\r\n 0x179a, // ConstraintAssociatedInit\r\n 0x179b, // ConstraintClose\r\n 0x1900, // ConstraintAddress (the one we hit most often)\r\n] as const);\r\n\r\n// ============================================================================\r\n// Detection\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a TransactionInstruction is from the Lighthouse program.\r\n *\r\n * @param ix - A Solana transaction instruction.\r\n * @returns `true` if the instruction's programId is Lighthouse.\r\n *\r\n * @example\r\n * ```ts\r\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\r\n * ```\r\n */\r\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\r\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if an error message or error object indicates a Lighthouse assertion failure.\r\n *\r\n * Detects:\r\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\r\n * - References to the Lighthouse program ID in error text\r\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\r\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\r\n * failing program is Lighthouse (identified by program ID in logs)\r\n *\r\n * @param error - An Error object, error message string, or transaction logs array.\r\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await sendTransaction(tx);\r\n * } catch (e) {\r\n * if (isLighthouseError(e)) {\r\n * // Retry with skipPreflight or notify user about wallet middleware\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isLighthouseError(error: unknown): boolean {\r\n const msg = extractErrorMessage(error);\r\n if (!msg) return false;\r\n\r\n // Direct program ID reference\r\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\r\n\r\n // 0x1900 hex error code (case-insensitive)\r\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\r\n\r\n // JSON InstructionError format: {\"Custom\": 6400}\r\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if transaction logs contain evidence of a Lighthouse failure.\r\n *\r\n * More precise than `isLighthouseError` on a string — examines the program\r\n * invocation chain to confirm the error originates from Lighthouse, not from\r\n * a Percolator instruction that happens to return a similar code.\r\n *\r\n * @param logs - Array of transaction log lines from `getTransaction()`.\r\n * @returns `true` if logs show a Lighthouse program failure.\r\n */\r\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\r\n if (!Array.isArray(logs)) return false;\r\n\r\n let lighthouseDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n // Track Lighthouse program invocation depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\r\n lighthouseDepth++;\r\n continue;\r\n }\r\n\r\n // Lighthouse program returned success — decrement depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\r\n if (lighthouseDepth > 0) lighthouseDepth--;\r\n continue;\r\n }\r\n\r\n // Only report failure when the Lighthouse program itself explicitly fails\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// Stripping / Mitigation\r\n// ============================================================================\r\n\r\n/**\r\n * Remove all Lighthouse assertion instructions from an instruction array.\r\n *\r\n * Call this before building a Transaction to prevent Lighthouse assertion\r\n * failures. Safe to call even if no Lighthouse instructions are present.\r\n *\r\n * @param instructions - Array of transaction instructions.\r\n * @returns Filtered array with Lighthouse instructions removed.\r\n *\r\n * @example\r\n * ```ts\r\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\r\n *\r\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\r\n * const clean = stripLighthouseInstructions(instructions);\r\n * const tx = new Transaction().add(...clean);\r\n * ```\r\n */\r\nexport function stripLighthouseInstructions(\r\n instructions: TransactionInstruction[],\r\n percolatorProgramId?: PublicKey,\r\n): TransactionInstruction[] {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions — prevents misuse on\r\n // arbitrary transactions where Lighthouse guards are legitimate protection.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) {\r\n return instructions; // no Percolator instructions — leave guards intact\r\n }\r\n }\r\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\r\n}\r\n\r\n/**\r\n * Strip Lighthouse instructions from an already-built Transaction.\r\n *\r\n * Creates a new Transaction with the same recentBlockhash and feePayer\r\n * but without any Lighthouse instructions. The returned transaction is\r\n * unsigned and must be re-signed.\r\n *\r\n * @param transaction - A Transaction (signed or unsigned).\r\n * @returns A new Transaction without Lighthouse instructions, or the same\r\n * transaction if no Lighthouse instructions were found.\r\n *\r\n * @example\r\n * ```ts\r\n * const signed = await wallet.signTransaction(tx);\r\n * if (hasLighthouseInstructions(signed)) {\r\n * const clean = stripLighthouseFromTransaction(signed);\r\n * const reSigned = await wallet.signTransaction(clean);\r\n * await connection.sendRawTransaction(reSigned.serialize());\r\n * }\r\n * ```\r\n */\r\nexport function stripLighthouseFromTransaction(\r\n transaction: Transaction,\r\n percolatorProgramId?: PublicKey,\r\n): Transaction {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = transaction.instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) return transaction;\r\n }\r\n\r\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\r\n if (!hasLighthouse) return transaction;\r\n\r\n const clean = new Transaction();\r\n clean.recentBlockhash = transaction.recentBlockhash;\r\n clean.feePayer = transaction.feePayer;\r\n\r\n for (const ix of transaction.instructions) {\r\n if (!isLighthouseInstruction(ix)) {\r\n clean.add(ix);\r\n }\r\n }\r\n\r\n return clean;\r\n}\r\n\r\n/**\r\n * Count Lighthouse instructions in an instruction array or transaction.\r\n *\r\n * @param ixsOrTx - Array of instructions or a Transaction.\r\n * @returns Number of Lighthouse instructions found.\r\n */\r\nexport function countLighthouseInstructions(\r\n ixsOrTx: TransactionInstruction[] | Transaction,\r\n): number {\r\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\r\n return instructions.filter(isLighthouseInstruction).length;\r\n}\r\n\r\n// ============================================================================\r\n// User-facing error messages\r\n// ============================================================================\r\n\r\n/**\r\n * User-friendly error message for Lighthouse assertion failures.\r\n *\r\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\r\n */\r\nexport const LIGHTHOUSE_USER_MESSAGE =\r\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\r\n \"This is a known compatibility issue — the transaction itself is valid. \" +\r\n \"Try one of these workarounds:\\n\" +\r\n \"1. Disable transaction simulation in your wallet settings\\n\" +\r\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\r\n \"3. The SDK will automatically retry without the guard\";\r\n\r\n/**\r\n * Classify an error and return an appropriate user-facing message.\r\n *\r\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\r\n * Otherwise returns `null` (callers should use their own error display).\r\n *\r\n * @param error - An Error, string, or logs array.\r\n * @returns User-facing message string, or `null` if not a Lighthouse error.\r\n */\r\nexport function classifyLighthouseError(error: unknown): string | null {\r\n if (isLighthouseError(error)) {\r\n return LIGHTHOUSE_USER_MESSAGE;\r\n }\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Internal helpers\r\n// ============================================================================\r\n\r\nfunction extractErrorMessage(error: unknown): string | null {\r\n if (!error) return null;\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n if (typeof error === \"object\" && \"message\" in error) {\r\n return String((error as { message: unknown }).message);\r\n }\r\n try {\r\n return JSON.stringify(error);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Coin-margined perpetual trade math utilities.\r\n *\r\n * On-chain PnL formula:\r\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\r\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\r\n *\r\n * All prices are in e6 format (1 USD = 1_000_000).\r\n * All token amounts are in native units (e.g. lamports).\r\n */\r\n\r\n/**\r\n * Compute mark-to-market PnL for an open position.\r\n */\r\nexport function computeMarkPnl(\r\n positionSize: bigint,\r\n entryPrice: bigint,\r\n oraclePrice: bigint,\r\n): bigint {\r\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n const diff =\r\n positionSize > 0n\r\n ? oraclePrice - entryPrice\r\n : entryPrice - oraclePrice;\r\n return (diff * absPos) / oraclePrice;\r\n}\r\n\r\n/**\r\n * Compute liquidation price given entry, capital, position and maintenance margin.\r\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\r\n */\r\nexport function computeLiqPrice(\r\n entryPrice: bigint,\r\n capital: bigint,\r\n positionSize: bigint,\r\n maintenanceMarginBps: bigint,\r\n): bigint {\r\n if (positionSize === 0n || entryPrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n // capitalPerUnit scaled by 1e6 for precision\r\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\r\n\r\n if (positionSize > 0n) {\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\r\n const liq = entryPrice - adjusted;\r\n return liq > 0n ? liq : 0n;\r\n } else {\r\n // Guard: short positions liquidate when price rises above liq price.\r\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\r\n // meaning the position can never be liquidated. Return max u64 to signal this.\r\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\r\n return entryPrice + adjusted;\r\n }\r\n}\r\n\r\n/**\r\n * Compute estimated liquidation price BEFORE opening a trade.\r\n * Accounts for trading fees reducing effective capital.\r\n */\r\nexport function computePreTradeLiqPrice(\r\n oracleE6: bigint,\r\n margin: bigint,\r\n posSize: bigint,\r\n maintBps: bigint,\r\n feeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\r\n const absPos = posSize < 0n ? -posSize : posSize;\r\n const signedPos = direction === \"long\" ? absPos : -absPos;\r\n // Fee adjusts the effective entry price, not the capital.\r\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\r\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\r\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\r\n let adjustedEntry: bigint;\r\n if (direction === \"long\") {\r\n adjustedEntry = oracleE6 + feeAdjust;\r\n } else {\r\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\r\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\r\n // feeBps >= 10000, misleading the UI into showing the position is safe.\r\n const shortEntry = oracleE6 - feeAdjust;\r\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\r\n }\r\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\r\n}\r\n\r\n/**\r\n * Compute trading fee from notional value and fee rate in bps.\r\n */\r\nexport function computeTradingFee(\r\n notional: bigint,\r\n tradingFeeBps: bigint,\r\n): bigint {\r\n return (notional * tradingFeeBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Dynamic fee tier configuration.\r\n */\r\nexport interface FeeTierConfig {\r\n /** Base trading fee (Tier 1) in bps */\r\n baseBps: bigint;\r\n /** Tier 2 fee in bps (0 = disabled) */\r\n tier2Bps: bigint;\r\n /** Tier 3 fee in bps (0 = disabled) */\r\n tier3Bps: bigint;\r\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\r\n tier2Threshold: bigint;\r\n /** Notional threshold to enter Tier 3 */\r\n tier3Threshold: bigint;\r\n}\r\n\r\n/**\r\n * Compute the effective fee rate in bps using the tiered fee schedule.\r\n *\r\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\r\n * - notional < tier2Threshold → baseBps (Tier 1)\r\n * - notional < tier3Threshold → tier2Bps (Tier 2)\r\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\r\n *\r\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\r\n */\r\nexport function computeDynamicFeeBps(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n if (config.tier2Threshold === 0n) return config.baseBps;\r\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\r\n if (notional >= config.tier2Threshold) return config.tier2Bps;\r\n return config.baseBps;\r\n}\r\n\r\n/**\r\n * Compute the dynamic trading fee for a given notional and tier config.\r\n *\r\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\r\n * via micro-trades).\r\n */\r\nexport function computeDynamicTradingFee(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n const feeBps = computeDynamicFeeBps(notional, config);\r\n if (notional <= 0n || feeBps <= 0n) return 0n;\r\n return (notional * feeBps + 9999n) / 10000n;\r\n}\r\n\r\n/**\r\n * Fee split configuration.\r\n */\r\nexport interface FeeSplitConfig {\r\n /** LP vault share in bps (0–10_000) */\r\n lpBps: bigint;\r\n /** Protocol treasury share in bps */\r\n protocolBps: bigint;\r\n /** Market creator share in bps */\r\n creatorBps: bigint;\r\n}\r\n\r\n/**\r\n * Compute fee split for a total fee amount.\r\n *\r\n * Returns [lpShare, protocolShare, creatorShare].\r\n * If all split params are 0, 100% goes to LP (legacy behavior).\r\n * Creator gets the rounding remainder to ensure total is preserved.\r\n */\r\nexport function computeFeeSplit(\r\n totalFee: bigint,\r\n config: FeeSplitConfig,\r\n): [bigint, bigint, bigint] {\r\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\r\n return [totalFee, 0n, 0n];\r\n }\r\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\r\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\r\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\r\n }\r\n if (totalBps !== 10000n) {\r\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\r\n }\r\n\r\n const lp = (totalFee * config.lpBps) / 10000n;\r\n const protocol = (totalFee * config.protocolBps) / 10000n;\r\n const creator = totalFee - lp - protocol;\r\n return [lp, protocol, creator];\r\n}\r\n\r\n/**\r\n * Compute PnL as a percentage of capital.\r\n *\r\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\r\n * Number(bigint) silently truncates values above 2^53, which can produce\r\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\r\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\r\n */\r\nexport function computePnlPercent(\r\n pnlTokens: bigint,\r\n capital: bigint,\r\n): number {\r\n if (capital === 0n) return 0;\r\n const scaledPct = (pnlTokens * 10_000n) / capital;\r\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\r\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\r\n // unhandled exceptions from crashing the UI on large positions.\r\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\r\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\r\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\r\n return Number(scaledPct) / 100;\r\n}\r\n\r\n/**\r\n * Estimate entry price including fee impact (slippage approximation).\r\n */\r\nexport function computeEstimatedEntryPrice(\r\n oracleE6: bigint,\r\n tradingFeeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n) return 0n;\r\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\r\n if (direction === \"long\") return oracleE6 + feeImpact;\r\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\r\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\r\n // when fee >= 100%, misleading the UI.\r\n const shortEntry = oracleE6 - feeImpact;\r\n return shortEntry > 0n ? shortEntry : 1n;\r\n}\r\n\r\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\r\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\r\n\r\n/**\r\n * Convert per-slot funding rate (bps) to annualized percentage.\r\n */\r\nexport function computeFundingRateAnnualized(\r\n fundingRateBpsPerSlot: bigint,\r\n): number {\r\n // Clamp rather than throw: extreme funding rates are display-only values;\r\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\r\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\r\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\r\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\r\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\r\n return (bpsPerSlot * slotsPerYear) / 100;\r\n}\r\n\r\n/**\r\n * Compute margin required for a given notional and initial margin bps.\r\n */\r\nexport function computeRequiredMargin(\r\n notional: bigint,\r\n initialMarginBps: bigint,\r\n): bigint {\r\n return (notional * initialMarginBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, as an exact ratio.\r\n *\r\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\r\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\r\n * {@link computeMaxLeverageFloor} instead.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\r\n }\r\n // Use floating-point division so fractional leverage is preserved.\r\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\r\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\r\n return 10000 / Number(initialMarginBps);\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, floored to a whole\r\n * multiplier — the conservative integer form used by risk/sizing math.\r\n *\r\n * Kept separate from {@link computeMaxLeverage} because that one is a display\r\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\r\n * DOWN also keeps client-side caps at or below what the program enforces, so a\r\n * caller can never build a position the chain would reject on leverage.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\r\n }\r\n return 10000n / initialMarginBps;\r\n}\r\n","/**\r\n * Warmup leverage cap utilities.\r\n *\r\n * During the market warmup period, capital is released linearly over\r\n * `warmupPeriodSlots` slots, which constrains the effective leverage\r\n * and maximum position size available to traders.\r\n */\r\n\r\nimport { computeMaxLeverageFloor } from \"./trading.js\";\r\n\r\n// =============================================================================\r\n// Warmup leverage cap utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Compute unlocked capital during the warmup period.\r\n *\r\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\r\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\r\n * warmup period is 0, all capital is considered unlocked.\r\n *\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The amount of capital currently unlocked.\r\n */\r\nexport function computeWarmupUnlockedCapital(\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n // No warmup configured or not started → all capital available\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\r\n if (totalCapital <= 0n) return 0n;\r\n\r\n const elapsed = currentSlot > warmupStartSlot\r\n ? currentSlot - warmupStartSlot\r\n : 0n;\r\n\r\n // Warmup complete\r\n if (elapsed >= warmupPeriodSlots) return totalCapital;\r\n\r\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\r\n return (totalCapital * elapsed) / warmupPeriodSlots;\r\n}\r\n\r\n/**\r\n * Compute the effective maximum leverage during the warmup period.\r\n *\r\n * During warmup, only unlocked capital can be used as margin. The effective\r\n * leverage relative to *total* capital is therefore capped at:\r\n *\r\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\r\n *\r\n * This returns a floored integer value (leverage is always a whole number\r\n * in the UI), with a minimum of 1x if any capital is unlocked.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The effective maximum leverage (integer, ≥ 1).\r\n */\r\nexport function computeWarmupLeverageCap(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): number {\r\n // Integer form: this is risk/sizing math, and the fractional\r\n // computeMaxLeverage() is a display value that cannot be used in BigInt\r\n // arithmetic. Flooring also keeps the client cap at or below the program's.\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n\r\n // No warmup or warmup not started → full leverage\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\r\n if (totalCapital <= 0n) return 1;\r\n\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n\r\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\r\n\r\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\r\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\r\n return Math.max(1, effectiveLev);\r\n}\r\n\r\n/**\r\n * Compute the maximum position size allowed during warmup.\r\n *\r\n * This is the unlocked capital multiplied by the base max leverage.\r\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\r\n * relative to total capital), this gives the absolute notional cap.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns Maximum position size in native units.\r\n */\r\nexport function computeWarmupMaxPositionSize(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n return unlocked * maxLev;\r\n}\r\n","/**\r\n * Input validation utilities for CLI commands.\r\n * Provides descriptive error messages for invalid input.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\n// Constants for numeric limits\r\nconst U16_MAX = 65535;\r\nconst U64_MAX = BigInt(\"18446744073709551615\");\r\nconst I64_MIN = BigInt(\"-9223372036854775808\");\r\nconst I64_MAX = BigInt(\"9223372036854775807\");\r\nconst U128_MAX = (1n << 128n) - 1n;\r\nconst I128_MIN = -(1n << 127n);\r\nconst I128_MAX = (1n << 127n) - 1n;\r\n\r\nexport class ValidationError extends Error {\r\n constructor(\r\n public readonly field: string,\r\n message: string\r\n ) {\r\n super(`Invalid ${field}: ${message}`);\r\n this.name = \"ValidationError\";\r\n }\r\n}\r\n\r\n/**\r\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\r\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\r\n */\r\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\r\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n */\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\r\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n *\r\n * @param value - The string to validate.\r\n * @param field - The field name used in error messages.\r\n * @returns The trimmed, validated decimal string.\r\n */\r\nexport function requireDecimalUIntString(value: string, field: string): string {\r\n const t = value.trim();\r\n if (t === \"\") {\r\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\r\n }\r\n if (!DECIMAL_UINT_RE.test(t)) {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\r\n );\r\n }\r\n return t;\r\n}\r\n\r\n/**\r\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\r\n * (hex, scientific notation, underscores, fractions, leading zeros).\r\n *\r\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\r\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\r\n *\r\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\r\n * @param caller - The calling function name, used in the error message.\r\n * @returns The parsed BigInt value.\r\n * @throws {Error} When `val` does not match the strict decimal integer format.\r\n *\r\n * @example\r\n * safeBigInt(\"123\", \"encU64\") // 123n\r\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\r\n * safeBigInt(\"0x1\", \"encU64\") // throws\r\n * safeBigInt(\"1e5\", \"encU128\") // throws\r\n */\r\nexport function safeBigInt(val: string, caller: string): bigint {\r\n const t = val.trim();\r\n if (!DECIMAL_INT_RE.test(t)) {\r\n throw new Error(\r\n `${caller}: \"${val}\" is not a valid decimal integer ` +\r\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\r\n );\r\n }\r\n return BigInt(t);\r\n}\r\n\r\n/**\r\n * Validate a public key string.\r\n */\r\nexport function validatePublicKey(value: string, field: string): PublicKey {\r\n try {\r\n return new PublicKey(value);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid base58 public key. ` +\r\n `Example: \"11111111111111111111111111111111\"`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate a non-negative integer index (u16 range for accounts).\r\n */\r\nexport function validateIndex(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a non-negative amount (u64 range).\r\n */\r\nexport function validateAmount(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U64_MAX} (u64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a u128 value.\r\n */\r\nexport function validateU128(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U128_MAX} (u128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i64 value.\r\n */\r\nexport function validateI64(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I64_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I64_MIN} (i64 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I64_MAX} (i64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i128 value (trade sizes).\r\n */\r\nexport function validateI128(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I128_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I128_MIN} (i128 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I128_MAX} (i128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a basis points value (0-10000).\r\n */\r\nexport function validateBps(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > 10000n) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= 10000 (100%), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a u64 value.\r\n */\r\nexport function validateU64(value: string, field: string): bigint {\r\n return validateAmount(value, field);\r\n}\r\n\r\n/**\r\n * Validate a u16 value.\r\n */\r\nexport function validateU16(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n","/**\r\n * Smart Price Router — automatic oracle selection for any token.\r\n *\r\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\r\n * ranks them by liquidity/reliability, and returns the best oracle config.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\r\n\r\nexport interface PriceSource {\r\n type: PriceSourceType;\r\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\r\n address: string;\r\n /** DEX id for dex sources */\r\n dexId?: string;\r\n /** Pair label e.g. \"SOL / USDC\" */\r\n pairLabel?: string;\r\n /** USD liquidity depth — higher is better */\r\n liquidity: number;\r\n /** Latest spot price in USD */\r\n price: number;\r\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\r\n confidence: number;\r\n}\r\n\r\nexport interface PriceRouterResult {\r\n mint: string;\r\n bestSource: PriceSource | null;\r\n allSources: PriceSource[];\r\n /** ISO timestamp of resolution */\r\n resolvedAt: string;\r\n}\r\n\r\n/** Options for {@link resolvePrice}. */\r\nexport interface ResolvePriceOptions {\r\n timeoutMs?: number;\r\n}\r\n\r\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\r\n\r\nfunction isRecord(v: unknown): v is Record {\r\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\r\n const already = signals.find((s) => s.aborted);\r\n if (already) {\r\n const c = new AbortController();\r\n c.abort(already.reason);\r\n return c.signal;\r\n }\r\n const active = signals.filter((s) => !s.aborted);\r\n if (active.length === 0) {\r\n const c = new AbortController();\r\n c.abort();\r\n return c.signal;\r\n }\r\n if (active.length === 1) return active[0];\r\n const ctrl = new AbortController();\r\n for (const s of active) {\r\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\r\n }\r\n return ctrl.signal;\r\n}\r\n\r\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\r\n\r\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\r\n if (!isRecord(json)) return [];\r\n const rawPairs = json.pairs;\r\n if (!Array.isArray(rawPairs)) return [];\r\n const sources: PriceSource[] = [];\r\n\r\n for (const pair of rawPairs) {\r\n if (!isRecord(pair)) continue;\r\n if (pair.chainId !== \"solana\") continue;\r\n const dexId = String(pair.dexId || \"\").toLowerCase();\r\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\r\n\r\n let liquidity = 0;\r\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\r\n liquidity = pair.liquidity.usd;\r\n }\r\n if (liquidity < 100) continue;\r\n\r\n let confidence = 30;\r\n if (liquidity > 1_000_000) confidence = 90;\r\n else if (liquidity > 100_000) confidence = 75;\r\n else if (liquidity > 10_000) confidence = 60;\r\n else if (liquidity > 1_000) confidence = 45;\r\n\r\n const priceUsd = pair.priceUsd;\r\n const price =\r\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\r\n ? parseFloat(String(priceUsd)) || 0\r\n : 0;\r\n\r\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\r\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\r\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\r\n // any source without a usable positive price.\r\n if (!(price > 0)) continue;\r\n\r\n let baseSym = \"?\";\r\n let quoteSym = \"?\";\r\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\r\n baseSym = pair.baseToken.symbol;\r\n }\r\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\r\n quoteSym = pair.quoteToken.symbol;\r\n }\r\n\r\n const addr = pair.pairAddress;\r\n sources.push({\r\n type: \"dex\",\r\n address: typeof addr === \"string\" ? addr : \"\",\r\n dexId,\r\n pairLabel: `${baseSym} / ${quoteSym}`,\r\n liquidity,\r\n price,\r\n confidence,\r\n });\r\n }\r\n\r\n sources.sort((a, b) => b.liquidity - a.liquidity);\r\n return sources.slice(0, 10);\r\n}\r\n\r\n/**\r\n * Parse a Jupiter price row.\r\n *\r\n * Handles BOTH shapes:\r\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\r\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\r\n *\r\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\r\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\r\n * cross-validation in this module was silently inert, including the #227/#315\r\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\r\n * mock or a proxy that still speaks v2 keeps working.\r\n */\r\nfunction parseJupiterMintEntry(\r\n json: unknown,\r\n mint: string,\r\n): { price: number; mintSymbol: string; liquidity: number } | null {\r\n if (!isRecord(json)) return null;\r\n\r\n // v3: the mint is a top-level key.\r\n const v3Row = json[mint];\r\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\r\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\r\n if (price <= 0) return null;\r\n const liquidity =\r\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\r\n ? v3Row.liquidity\r\n : 0;\r\n return { price, mintSymbol: \"?\", liquidity };\r\n }\r\n\r\n // v2 (retired): rows live under `data`.\r\n const data = json.data;\r\n if (!isRecord(data)) return null;\r\n const row = data[mint];\r\n if (!isRecord(row)) return null;\r\n const rawPrice = row.price;\r\n if (rawPrice === undefined || rawPrice === null) return null;\r\n const price = parseFloat(String(rawPrice)) || 0;\r\n if (price <= 0) return null;\r\n let mintSymbol = \"?\";\r\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\r\n return { price, mintSymbol, liquidity: 0 };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const PYTH_SOLANA_FEEDS: Record = {\r\n // SOL\r\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\r\n // BTC\r\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\r\n // ETH\r\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\r\n // USDC\r\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\r\n // USDT\r\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\r\n // BONK\r\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\r\n // JTO\r\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\r\n // JUP\r\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\r\n // PYTH\r\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\r\n // RAY\r\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\r\n // ORCA\r\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\r\n // MNGO\r\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\r\n // MSOL\r\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\r\n // JITOSOL\r\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\r\n // WIF\r\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\r\n // RENDER\r\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\r\n // W\r\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\r\n // TNSR\r\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\r\n // HNT\r\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\r\n // MOBILE\r\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\r\n // IOT\r\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\r\n};\r\nObject.freeze(PYTH_SOLANA_FEEDS);\r\n\r\n// Reverse lookup: mint → feed ID\r\nconst MINT_TO_PYTH_FEED = new Map();\r\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\r\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DexScreener fetcher\r\n// ---------------------------------------------------------------------------\r\n\r\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\r\n\r\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\r\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\r\n}\r\n\r\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return [];\r\n const json: unknown = await resp.json();\r\n return parseDexScreenerPairs(json);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth lookup\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction lookupPythSource(mint: string): PriceSource | null {\r\n const entry = MINT_TO_PYTH_FEED.get(mint);\r\n if (!entry) return null;\r\n return {\r\n type: \"pyth\",\r\n address: entry.feedId,\r\n pairLabel: `${entry.symbol} / USD (Pyth)`,\r\n liquidity: Infinity, // Pyth is considered deep liquidity\r\n price: 0, // We don't fetch live price here; caller can enrich\r\n confidence: 95, // Pyth is highest reliability for supported tokens\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Jupiter price fallback\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return null;\r\n const json: unknown = await resp.json();\r\n const row = parseJupiterMintEntry(json, mint);\r\n if (!row) return null;\r\n return {\r\n type: \"jupiter\",\r\n address: mint,\r\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\r\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\r\n // Used below to decide whether Jupiter is a credible enough reference to\r\n // demote a disagreeing pool.\r\n liquidity: row.liquidity,\r\n price: row.price,\r\n confidence: 40, // Fallback — lower confidence\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main resolver\r\n// ---------------------------------------------------------------------------\r\n\r\nexport async function resolvePrice(\r\n mint: string,\r\n signal?: AbortSignal,\r\n options?: ResolvePriceOptions,\r\n): Promise {\r\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\r\n const combinedSignal = signal\r\n ? combineAbortSignals([signal, timeoutSignal])\r\n : timeoutSignal;\r\n\r\n const [dexSources, jupiterSource] = await Promise.all([\r\n fetchDexSources(mint, combinedSignal),\r\n fetchJupiterSource(mint, combinedSignal),\r\n ]);\r\n\r\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\r\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\r\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\r\n // the common case for permissionless markets — had its top DEX source ranked\r\n // purely on self-reported liquidity, with no check against an independent price\r\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\r\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\r\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\r\n // source's confidence to Jupiter's when they diverge beyond the same tightened\r\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\r\n // independent reference purely on liquidity. The source stays in allSources for\r\n // transparency; only its ranking weight is reduced.\r\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\r\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\r\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\r\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\r\n // ahead and bestSource unchanged.\r\n const DISTRUST_CONFIDENCE_MARGIN = 1;\r\n if (jupiterSource && jupiterSource.price > 0) {\r\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\r\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\r\n // itself — enrichment reads dexSources[0].price, which is untouched; only\r\n // ranking weight changes, and Pyth's own confidence (95) still outranks\r\n // everything here.\r\n //\r\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\r\n // Jupiter is an aggregate across venues, so it is normally the better\r\n // reference — but with v2 retired a malformed/empty response used to yield a\r\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\r\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\r\n // ranking alone rather than trust it.\r\n const jupiterIsCredible = jupiterSource.liquidity > 0;\r\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\r\n if (jupiterIsCredible) {\r\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\r\n // returns up to 10 pools and confidence is a step function of liquidity, so a\r\n // second pool in the same tier would otherwise keep its score and win\r\n // bestSource at the divergent price.\r\n for (const dex of dexSources) {\r\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\r\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\r\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\r\n dex.confidence = Math.min(dex.confidence, distrusted);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const pythSource = lookupPythSource(mint);\r\n\r\n const allSources: PriceSource[] = [];\r\n\r\n // Add Pyth if available (highest priority for supported tokens)\r\n if (pythSource) {\r\n // Enrich Pyth price from Jupiter or DEX if available.\r\n // Guard: only push a Pyth source when we have at least one live price\r\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\r\n // at crank time on devnet/mainnet.\r\n const dexPrice = dexSources[0]?.price ?? 0;\r\n const jupPrice = jupiterSource?.price ?? 0;\r\n // #227: cross-validate the enrichment reference so a single manipulable DEX\r\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\r\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\r\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\r\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\r\n //\r\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\r\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\r\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\r\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\r\n let enrichedPrice = 0;\r\n let singleSource = false;\r\n if (dexPrice > 0 && jupPrice > 0) {\r\n const mid = (dexPrice + jupPrice) / 2;\r\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\r\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\r\n enrichedPrice = mid;\r\n } else {\r\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\r\n // DEX and Jupiter are still added below at their own confidence levels.\r\n console.warn(\r\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\r\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\r\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\r\n );\r\n }\r\n } else if (dexPrice > 0 || jupPrice > 0) {\r\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\r\n singleSource = true;\r\n }\r\n if (enrichedPrice > 0) {\r\n pythSource.price = enrichedPrice;\r\n if (singleSource) {\r\n pythSource.confidence = Math.min(pythSource.confidence, 50);\r\n }\r\n allSources.push(pythSource);\r\n }\r\n }\r\n\r\n // Add DEX sources\r\n allSources.push(...dexSources);\r\n\r\n // Add Jupiter as fallback\r\n if (jupiterSource) {\r\n allSources.push(jupiterSource);\r\n }\r\n\r\n // Sort by confidence descending (already accounts for liquidity/reliability)\r\n allSources.sort((a, b) => b.confidence - a.confidence);\r\n\r\n return {\r\n mint,\r\n bestSource: allSources[0] || null,\r\n allSources,\r\n resolvedAt: new Date().toISOString(),\r\n };\r\n}\r\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;A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","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file diff --git a/src/abi/nft.ts b/src/abi/nft.ts index 55bfe29..39731fa 100644 --- a/src/abi/nft.ts +++ b/src/abi/nft.ts @@ -9,10 +9,16 @@ * - GetPositionValue (tag 3) * - ExecuteTransferHook (tag 4, SPL interface — not called directly) * - EmergencyBurn (tag 5) + * - RepairExtraMetas (tag 6) + * - ReconcileBurnedNft (tag 7) * * PDA seeds (matches percolator-nft/src/state_v16.rs): - * PositionNft state : ["position_nft", portfolio_account, asset_index_u16_LE] + * PositionNft state : ["position_nft", portfolio_account, market_id_u64_LE] * Mint authority : ["mint_authority"] + * + * NOTE: the PositionNft seed is keyed on `market_id`, NOT `asset_index` — see + * #108 and `deriveNftPda` below. This header claimed `asset_index_u16_LE` until + * 2026-08-31; the code was always correct. */ import { PublicKey } from "@solana/web3.js"; @@ -215,18 +221,33 @@ export const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [ ]; /** - * Account metas for ReconcileBurnedNft (tag 7, #138). 7 accounts. Permissionless. + * Account metas for ReconcileBurnedNft (tag 7, #138). 9 accounts. Permissionless. * * 0. [writable] PositionNft PDA (closed) - * 1. [] NFT mint (Token-2022 — supply must be 0) + * 1. [writable] NFT mint (Token-2022 — supply must be 0; closed, #182) * 2. [writable] Portfolio account (escrow released to the last holder) - * 3. [] Mint authority PDA (unwrap CPI signer) + * 3. [] Mint authority PDA (unwrap + mint-close CPI signer) * 4. [] Per-market NftRegistry PDA * 5. [] Percolator wrapper program (unwrap CPI target) - * 6. [writable] Recorded last-holder wallet (escrow + PDA-rent recipient) + * 6. [writable] Recorded last-holder wallet (escrow + all rent recipient) + * 7. [writable] ExtraAccountMetaList PDA (closed, #182) + * 8. [] Token-2022 program (mint-close CPI target, #182) + * + * dcccrypto/percolator-nft#182: Reconcile previously abandoned the NFT mint and + * the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable, + * because it closes the PositionNft PDA and every path that could later reclaim + * those two requires it to still be live. Accounts 7 and 8 are REQUIRED rather + * than optional: Reconcile is permissionless, irreversible and runs at most + * once, so an opt-in could be defeated permanently by whoever called first. + * + * Forward-compatible with the currently deployed programs: their handler pulls + * seven accounts off an iterator and never checks `accounts.len()`, so the two + * extra metas are simply unread, and it never checks `nft_mint.is_writable`. + * A nine-account call therefore behaves identically on both, which is why this + * can ship ahead of the program change rather than behind it. */ export const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [ - "w", "r", "w", "r", "r", "r", "w", + "w", "w", "w", "r", "r", "r", "w", "w", "r", ]; // --------------------------------------------------------------------------- diff --git a/test/drift-check.test.ts b/test/drift-check.test.ts index 7c7af48..1dd2bd9 100644 --- a/test/drift-check.test.ts +++ b/test/drift-check.test.ts @@ -1052,8 +1052,16 @@ describe("percolator-nft account-list ABI", () => { expect(f[7]).toEqual([false, true]); }); - it("ReconcileBurnedNft is permissionless — no account may be a signer", () => { - expect(flagsOf(ACCOUNTS_NFT_RECONCILE).every(([signer]) => !signer)).toBe(true); + it("ReconcileBurnedNft: 9 accounts, permissionless, writable at 0/1/2/6/7", () => { + // dcccrypto/percolator-nft#182 gives Reconcile the rent reclamation the two + // burn paths have had since #102: extra_metas at 7, Token-2022 at 8, both + // REQUIRED. The mint at 1 becomes writable because the fix closes it. + const f = flagsOf(ACCOUNTS_NFT_RECONCILE); + expect(f.length).toBe(9); + expect(f.every(([signer]) => !signer)).toBe(true); // permissionless + expect(f.map(([, w]) => w)).toEqual([ + true, true, true, false, false, false, true, true, false, + ]); }); it("buildNftAccountMetas rejects a key-count mismatch rather than truncating", () => { From 71403601ce23f8ec589be22e9312d0ab270bc0a5 Mon Sep 17 00:00:00 2001 From: 0X-SquidSol Date: Mon, 31 Aug 2026 10:02:31 -0400 Subject: [PATCH 3/3] =?UTF-8?q?feat(nft):=20expose=20PositionNftState.last?= =?UTF-8?q?Holder=20=E2=80=94=20the=20Reconcile=20recipient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bytes [167..199] were documented as `_reserved`. percolator-nft#138 claimed them for `last_holder: [u8; 32]`, the final field of PositionNftV16 and the one the transfer hook rewrites on every transfer. It matters here because ReconcileBurnedNft reads it as the sole authorisation: the program releases the escrowed portfolio and all rent to whichever account matches, and refuses any other. It is account 6 of ACCOUNTS_NFT_RECONCILE and cannot be derived — only read from the PositionNft account. So without this the SDK shipped the Reconcile account template while giving a caller no way to obtain the one key in it that is not a PDA or a program id. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 8 ++++++++ dist/abi/nft.d.ts | 17 ++++++++++++++++- dist/index.js | 3 ++- dist/index.js.map | 2 +- src/abi/nft.ts | 18 +++++++++++++++++- test/drift-check.test.ts | 20 ++++++++++++++++++++ 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a62ab6f..0c594bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,14 @@ this collects that change and everything since. ### Added +- **`PositionNftState.lastHolder`.** Bytes `[167..199]` were documented as + `_reserved`; #138 claimed them for `last_holder`, the field the transfer hook + rewrites on every transfer. It is the sole authorisation for + `ReconcileBurnedNft` — the program releases the escrowed portfolio and all + rent to whichever account matches it — and it is account 6 of + `ACCOUNTS_NFT_RECONCILE`, which cannot be derived. Without this the SDK + shipped the Reconcile account template but no way to obtain the one key in it. + - Account-list drift tests (`test/drift-check.test.ts`) that round-trip each `ACCOUNTS_NFT_*` template through `buildNftAccountMetas` and assert the resulting `{isSigner, isWritable}` booleans. The previous tests asserted the diff --git a/dist/abi/nft.d.ts b/dist/abi/nft.d.ts index 4985b99..e3c89f9 100644 --- a/dist/abi/nft.d.ts +++ b/dist/abi/nft.d.ts @@ -211,7 +211,13 @@ export declare function deriveExtraAccountMetas(nftMint: PublicKey, programId?: * [119..127] epoch_snap_at_mint u64 * [127..159] position_owner_at_mint [u8; 32] * [159..167] minted_at i64 - * [167..199] _reserved + * [167..199] last_holder [u8; 32] + * + * NOTE: [167..199] is `last_holder`, not reserved space. #138 claimed those + * bytes for the field the transfer hook rewrites on every transfer, and + * `ReconcileBurnedNft` reads it to decide who receives the released escrow and + * the rent — it is account 6 of that instruction and cannot be derived, only + * read from here. */ export declare const POSITION_NFT_STATE_LEN = 199; export interface PositionNftState { @@ -229,6 +235,15 @@ export interface PositionNftState { /** Backward-compatible alias for positionOwnerAtMint. */ positionOwner: PublicKey; mintedAt: bigint; + /** + * The wallet the transfer hook last recorded as holding this NFT (#138). + * + * This is the sole authorisation for `ReconcileBurnedNft`: the program + * releases the escrowed portfolio and all rent to whichever account matches + * it, and refuses any other. Supply it as account 6 of + * `ACCOUNTS_NFT_RECONCILE` — there is no way to derive it. + */ + lastHolder: PublicKey; } /** * Parse a PositionNft account from raw bytes. diff --git a/dist/index.js b/dist/index.js index f261d67..bac0592 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2875,7 +2875,8 @@ function parsePositionNftAccount(data) { epochSnapAtMint: view.getBigUint64(119, true), positionOwnerAtMint, positionOwner: positionOwnerAtMint, - mintedAt: view.getBigInt64(159, true) + mintedAt: view.getBigInt64(159, true), + lastHolder: new PublicKey4(data.subarray(167, 199)) }; } diff --git a/dist/index.js.map b/dist/index.js.map index e7bb39f..d854eef 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst U8_MAX = 0xFF;\r\nconst U16_MAX = 0xFFFF;\r\nconst U32_MAX = 0xFFFFFFFF;\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\r\n if (typeof val === \"bigint\") return val;\r\n if (typeof val !== \"string\") {\r\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\r\n }\r\n if (!DECIMAL_INT_RE.test(val)) {\r\n throw new Error(`${fnName}: value must be a decimal integer string`);\r\n }\r\n return BigInt(val);\r\n}\r\n\r\n/**\r\n * Encode u8 (1 byte)\r\n */\r\nexport function encU8(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\r\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\r\n }\r\n return new Uint8Array([val]);\r\n}\r\n\r\n/**\r\n * Encode u16 little-endian (2 bytes)\r\n */\r\nexport function encU16(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\r\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u32 little-endian (4 bytes)\r\n */\r\nexport function encU32(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\r\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\r\n }\r\n const buf = new Uint8Array(4);\r\n new DataView(buf.buffer).setUint32(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u64 little-endian (8 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU64\");\r\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\r\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i64 little-endian (8 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI64\");\r\n const min = -(1n << 63n);\r\n const max = (1n << 63n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigInt64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u128 little-endian (16 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU128\");\r\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\r\n const max = (1n << 128n) - 1n;\r\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = n & 0xffff_ffff_ffff_ffffn;\r\n const hi = n >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i128 little-endian (16 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI128\");\r\n const min = -(1n << 127n);\r\n const max = (1n << 127n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\r\n\r\n // Convert to unsigned representation (two's complement)\r\n let unsigned = n;\r\n if (n < 0n) {\r\n unsigned = (1n << 128n) + n;\r\n }\r\n\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\r\n const hi = unsigned >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\r\n *\r\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\r\n * objects are validated before their bytes are returned so JavaScript callers\r\n * cannot provide malformed `toBytes()` output.\r\n *\r\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\r\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\r\n */\r\nexport function encPubkey(val: PublicKey | string): Uint8Array {\r\n try {\r\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\r\n\r\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\r\n throw new Error(\"value must be a PublicKey or base58 string\");\r\n }\r\n\r\n const bytes = pk.toBytes();\r\n\r\n if (!(bytes instanceof Uint8Array)) {\r\n throw new Error(\"toBytes() must return a Uint8Array\");\r\n }\r\n\r\n if (bytes.length !== 32) {\r\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\r\n }\r\n\r\n return bytes;\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\r\n }\r\n}\r\n\r\n/**\r\n * Encode a boolean as u8 (0 = false, 1 = true)\r\n */\r\nexport function encBool(val: boolean): Uint8Array {\r\n return encU8(val ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\r\n */\r\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\r\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\r\n const result = new Uint8Array(totalLen);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n encU8,\r\n encU16,\r\n encU32,\r\n encU64,\r\n encI64,\r\n encU128,\r\n encI128,\r\n encPubkey,\r\n concatBytes,\r\n} from \"./encode.js\";\r\n\r\n/**\r\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\r\n * v17 converged wrapper (percolator-prog @v17-convergence, source\r\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\r\n * InvalidInstructionData.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\r\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\r\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\r\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\r\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\r\n * all callers — the program hard-rejects nonzero.\r\n * - Domain fields: u8→u16 everywhere.\r\n */\r\nexport const IX_TAG = {\r\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\r\n InitMarket: 0,\r\n InitPortfolio: 1,\r\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\r\n InitUser: 1,\r\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\r\n InitLP: 2,\r\n Deposit: 3,\r\n /** @alias DepositCollateral @since v12.x alias */\r\n DepositCollateral: 3,\r\n Withdraw: 4,\r\n /** @alias WithdrawCollateral @since v12.x alias */\r\n WithdrawCollateral: 4,\r\n /**\r\n * PermissionlessCrank (tag 5).\r\n *\r\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\r\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\r\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\r\n * construct the payload manually and omit this field — that produces a\r\n * malformed instruction (missing bytes).\r\n */\r\n PermissionlessCrank: 5,\r\n /** @alias KeeperCrank @since v12.x alias */\r\n KeeperCrank: 5,\r\n TradeNoCpi: 6,\r\n LiquidateAtOracle: 7,\r\n ClosePortfolio: 8,\r\n /** @alias CloseAccount @since v12.x alias */\r\n CloseAccount: 8,\r\n TopUpInsurance: 9,\r\n TradeCpi: 10,\r\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\r\n SetRiskThreshold: 11,\r\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\r\n UpdateAdmin: 12,\r\n CloseSlab: 13,\r\n ResolveMarket: 19,\r\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\r\n TopUpBackingBucket: 24,\r\n ConvertReleasedPnl: 28,\r\n CloseResolved: 30,\r\n /**\r\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\r\n *\r\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\r\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\r\n * rotation uses tag 65 (UpdateAssetAuthority).\r\n */\r\n UpdateAuthority: 32,\r\n ConfigureHybridOracle: 34,\r\n ConfigureEwmaMark: 35,\r\n PushEwmaMark: 36,\r\n UpdateLiquidationFeePolicy: 37,\r\n ConfigurePermissionlessResolve: 38,\r\n ResolveStalePermissionless: 39,\r\n UpdateAssetLifecycle: 40,\r\n WithdrawInsurance: 41,\r\n CureAndCancelClose: 42,\r\n ForfeitRecoveryLeg: 43,\r\n RebalanceReduce: 44,\r\n FinalizeResetSide: 45,\r\n ClaimResolvedPayoutTopup: 46,\r\n RefineResolvedUnreceiptedBound: 47,\r\n SyncMaintenanceFee: 48,\r\n UpdateMaintenanceFeePolicy: 49,\r\n WithdrawBackingBucket: 50,\r\n UpdateBackingFeePolicy: 51,\r\n WithdrawBackingBucketEarnings: 52,\r\n SyncBackingDomainLedger: 53,\r\n SyncInsuranceLedger: 54,\r\n UpdateTradeFeePolicy: 55,\r\n TopUpInsuranceDomain: 56,\r\n /**\r\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\r\n *\r\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\r\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\r\n */\r\n WithdrawInsuranceAsset: 57,\r\n UpdateFeeRedirectPolicy: 58,\r\n UpdateMarketInitFeePolicy: 59,\r\n UpdateBaseUnitMints: 60,\r\n SwapSecondaryForPrimary: 61,\r\n ConfigureAuthMark: 62,\r\n PushAuthMark: 63,\r\n ForceCloseAbandonedAsset: 64,\r\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\r\n /**\r\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\r\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\r\n * 1 = INSURANCE — insurance_authority\r\n * 2 = INSURANCE_OPERATOR — insurance_operator\r\n * 3 = BACKING_BUCKET — backing_bucket_authority\r\n * 4 = ORACLE — oracle_authority\r\n *\r\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\r\n * See stake-program docs.\r\n */\r\n UpdateAssetAuthority: 65,\r\n /**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\r\n */\r\n BatchTradeNoCpi: 66,\r\n /**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\r\n */\r\n BatchTradeCpi: 67,\r\n /**\r\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n */\r\n SetMatcherConfig: 68,\r\n /**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\r\n */\r\n RestartAssetOracle: 69,\r\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\r\n /**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n */\r\n TransferPortfolioOwnership: 72,\r\n /**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n */\r\n SetNftProgramId: 73,\r\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\r\n /**\r\n * CreateLpVault (tag 74).\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\r\n */\r\n CreateLpVault: 74,\r\n /**\r\n * DepositToLpVault (tag 75).\r\n * Wire: tag(1) + amount(u128) = 17 bytes.\r\n */\r\n DepositToLpVault: 75,\r\n /**\r\n * RequestRedeemLpShares (tag 76).\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n */\r\n RequestRedeemLpShares: 76,\r\n /**\r\n * ExecuteRedemption (tag 77).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n ExecuteRedemption: 77,\r\n /**\r\n * LpVaultCrankFees (tag 78).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n LpVaultCrankFees: 78,\r\n /**\r\n * SetLpVaultPaused (tag 79).\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n */\r\n SetLpVaultPaused: 79,\r\n /**\r\n * CloseLpVault (tag 80).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n CloseLpVault: 80,\r\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\r\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\r\n LpVaultDeposit: 75,\r\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\r\n LpVaultWithdraw: 76,\r\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\r\n /** @deprecated v12.x tag 14. Removed in v17. */\r\n UpdateConfig: 14,\r\n /** @deprecated v12.x tag 15. Removed in v17. */\r\n SetMaintenanceFee: 15,\r\n /** @deprecated v12.x tag 16. Removed in v17. */\r\n SetOraclePriceCap: 16,\r\n /** @deprecated v12.x tag 17. Removed in v17. */\r\n AdminForceClose: 17,\r\n /** @deprecated v12.x tag 18. Removed in v17. */\r\n UpdateRiskParams: 18,\r\n /** @deprecated v12.x tag 20. Removed in v17. */\r\n SetPythOracle: 20,\r\n /** @deprecated v12.x tag 21. Removed in v17. */\r\n RenounceAdmin: 21,\r\n /** @deprecated v12.x tag 22. Removed in v17. */\r\n SetInsuranceWithdrawPolicy: 22,\r\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\r\n WithdrawInsuranceLimited: 23,\r\n /** @deprecated v12.x tag 25. Removed in v17. */\r\n FundMarketInsurance: 25,\r\n /** @deprecated v12.x tag 26. Removed in v17. */\r\n SetInsuranceIsolation: 26,\r\n /** @deprecated v12.x tag 27. Removed in v17. */\r\n DepositFeeCredits: 27,\r\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\r\n ResolvePermissionless: 29,\r\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\r\n ForceCloseResolved: 30,\r\n /** @deprecated v12.x tag 33. Removed in v17. */\r\n UpdateInsurancePolicy: 33,\r\n /** @deprecated v12.x tag 36. Removed in v12.17. */\r\n UnresolveMarket: 36,\r\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\r\n ChallengeSettlement: 43,\r\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\r\n ResolveDispute: 44,\r\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\r\n DepositLpCollateral: 45,\r\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\r\n WithdrawLpCollateral: 46,\r\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\r\n SetOffsetPair: 54,\r\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\r\n AttestCrossMargin: 55,\r\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\r\n PauseMarket: 56,\r\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\r\n UnpauseMarket: 58,\r\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\r\n MintPositionNft: 64,\r\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\r\n TransferPositionOwnership: 65,\r\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\r\n BurnPositionNft: 66,\r\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\r\n SetPendingSettlement: 67,\r\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\r\n ClearPendingSettlement: 68,\r\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\r\n TransferOwnershipCpi: 69,\r\n /** @deprecated v12.x tag 70. Not in v17. */\r\n SetWalletCap: 70,\r\n /** @deprecated v12.x tag 71. Not in v17. */\r\n SetOiImbalanceHardBlock: 71,\r\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\r\n RescueOrphanVault: 72,\r\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\r\n CloseOrphanSlab: 73,\r\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\r\n SetDexPool: 74,\r\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\r\n InitMatcherCtxV12: 75,\r\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\r\n SetMaxPnlCap: 78,\r\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\r\n SetOiCapMultiplier: 79,\r\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\r\n SetDisputeParams: 80,\r\n /** @deprecated v12.x tag 81. Not in v17. */\r\n SetLpCollateralParams: 81,\r\n /** @deprecated v12.x tag 82. Not in v17. */\r\n AcceptAdmin: 82,\r\n /**\r\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\r\n *\r\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\r\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\r\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\r\n * skew_spread_mult_bps(u16) = 70 bytes total.\r\n *\r\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\r\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\r\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\r\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\r\n *\r\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\r\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\r\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\r\n * free tag 83 for this instruction rather than the reverse.\r\n */\r\n InitMatcherCtx: 83,\r\n /**\r\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\r\n *\r\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\r\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\r\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\r\n *\r\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\r\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\r\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\r\n */\r\n WithdrawProtocolFee: 84,\r\n /**\r\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\r\n * cfg.protocol_fee_authority.\r\n *\r\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\r\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\r\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\r\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\r\n *\r\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\r\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\r\n */\r\n SetProtocolFeeAuthority: 85,\r\n /**\r\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\r\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\r\n *\r\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\r\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\r\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\r\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\r\n * FeeSplitFloorViolation.\r\n *\r\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\r\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\r\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\r\n * `encodeStakeAdminUpdateFeeSplit`.\r\n */\r\n UpdateFeeSplit: 86,\r\n /**\r\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\r\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\r\n * vault and into the bound stake pool's vault, where percolator-stake's\r\n * AccrueFees measures it as surplus and distributes it to stakers.\r\n *\r\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\r\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\r\n *\r\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\r\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\r\n * id. The only thing a caller decides is *when* the push happens.\r\n *\r\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\r\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\r\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\r\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\r\n * ResolveMarket, not after.\r\n */\r\n WithdrawInsuranceReserveToStake: 87,\r\n /**\r\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\r\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\r\n * argument with no setter anywhere in the dispatch table and was therefore\r\n * frozen for the life of the market.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\r\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\r\n * (v16_program.rs tag-88 arm), matching both the storage type\r\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\r\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\r\n * rejects the whole instruction with InvalidInstructionData.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\r\n */\r\n UpdateMaintenanceFeePerSlot: 88,\r\n /**\r\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\r\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\r\n * bucket to `Expired`/`Impaired` so settlement against that domain can\r\n * proceed again.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\r\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\r\n *\r\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\r\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\r\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\r\n * horizon defers the lapse, it does not avoid it. See\r\n * {@link encodeExpireBackingBucket} for the full keeper contract.\r\n */\r\n ExpireBackingBucket: 89,\r\n /**\r\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\r\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\r\n * Pays the market creator's accrued trade-fee share out of the vault and\r\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\r\n * EXACTLY `amount`.\r\n *\r\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\r\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\r\n * tag 84).\r\n *\r\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\r\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\r\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\r\n * config and pass that to drain it.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\r\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\r\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\r\n * alone, so this deliberate divergence is what lets the creator still claim\r\n * after staking (and stops the pool PDA claiming creator revenue).\r\n *\r\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\r\n * saturated — there is no partial fill. Nothing is debited on failure.\r\n */\r\n WithdrawCreatorFee: 90,\r\n /**\r\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\r\n * between the two domains of the LP vault's asset, carrying ledger principal\r\n * in lockstep. No tokens move: `header.vault` is untouched.\r\n *\r\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\r\n * gains from the OPPOSITE domain, so without this the pot the house actually\r\n * needs can never be refilled (spec.md L410 requires refill be source-domain\r\n * local).\r\n */\r\n RebalanceLpVaultBacking: 91,\r\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\r\n ReclaimEmptyAccount: 85,\r\n /** @deprecated v12.x tag 86. Not in v17. */\r\n SettleAccount: 86,\r\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\r\n UpdateMarkPrice: 90,\r\n /** @deprecated v12.x tag 91. Not in v17. */\r\n AuditCrank: 91,\r\n /** @deprecated v12.x tag 92. Not in v17. */\r\n AdvanceOraclePhase: 92,\r\n /** @deprecated v12.x tag 93. Not in v17. */\r\n SlashCreationDeposit: 93,\r\n /** @deprecated v12.x tag 94. Not in v17. */\r\n InitSharedVault: 94,\r\n /** @deprecated v12.x tag 95. Not in v17. */\r\n AllocateMarket: 95,\r\n /** @deprecated v12.x tag 96. Not in v17. */\r\n QueueWithdrawalSV: 96,\r\n /** @deprecated v12.x tag 97. Not in v17. */\r\n ClaimEpochWithdrawal: 97,\r\n /** @deprecated v12.x tag 98. Not in v17. */\r\n AdvanceEpoch: 98,\r\n /** @deprecated v12.x tag 99. Not in v17. */\r\n ReclaimSlabRent: 99,\r\n /** @deprecated v12.x tag 100. Not in v17. */\r\n CloseStaleSlabs: 100,\r\n /** @deprecated v12.x tag 101. Not in v17. */\r\n ExecuteAdl: 101,\r\n /** @deprecated v12.x tag 102. Not in v17. */\r\n QueueWithdrawal: 102,\r\n /** @deprecated v12.x tag 103. Not in v17. */\r\n ClaimQueuedWithdrawal: 103,\r\n /** @deprecated v12.x tag 104. Not in v17. */\r\n CancelQueuedWithdrawal: 104,\r\n /** @deprecated v12.x tag 105. Not in v17. */\r\n TradeCpiV: 105,\r\n} as const;\r\nObject.freeze(IX_TAG);\r\n\r\n/**\r\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\r\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\r\n *\r\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\r\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\r\n */\r\nexport const EXPECTED_SLAB_VERSION = 16;\r\n\r\n/**\r\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\r\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\r\n throw new Error(\r\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\r\n );\r\n}\r\n\r\n/**\r\n * InitMarket instruction data — v17 wire format.\r\n *\r\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\r\n *\r\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\r\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\r\n * provided as account metas or configured separately via ConfigureHybridOracle /\r\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\r\n *\r\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\r\n * is completely rejected by the v17 program — the first field read is now\r\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\r\n * a u16 portfolio count, producing invalid config or rejection at every call.\r\n *\r\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\r\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\r\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\r\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\r\n */\r\n/**\r\n * Optional 66-byte extended tail for InitMarket (S-4).\r\n *\r\n * When present and any field is non-zero the encoder appends a 66-byte block\r\n * in the exact order that the program reads it (percolator.rs:1516-1545):\r\n * insurance_withdraw_max_bps u16 (2 bytes)\r\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\r\n * permissionless_resolve_stale_slots u64 (8 bytes)\r\n * funding_horizon_slots u64 (8 bytes)\r\n * funding_k_bps u64 (8 bytes)\r\n * funding_max_premium_bps i64 (8 bytes)\r\n * funding_max_bps_per_slot i64 (8 bytes)\r\n * mark_min_fee u64 (8 bytes)\r\n * force_close_delay_slots u64 (8 bytes)\r\n * total = 2 + 8*8 = 66 bytes\r\n *\r\n * When absent (or all fields are zero) the encoder omits the tail and the\r\n * program treats all extended fields as their default zero values. This\r\n * preserves full backward compatibility with existing 344-byte payloads.\r\n */\r\nexport interface InitMarketExtendedTail {\r\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\r\n insuranceWithdrawMaxBps: number;\r\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\r\n insuranceWithdrawCooldownSlots: bigint | string;\r\n /** Slots after which an unresolved market may be permissionlessly resolved. */\r\n permissionlessResolveStaleSlots: bigint | string;\r\n /** Funding rate horizon in slots (custom_funding_k denominator). */\r\n fundingHorizonSlots: bigint | string;\r\n /** Funding rate K parameter in bps (0 = disabled). */\r\n fundingKBps: bigint | string;\r\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\r\n fundingMaxPremiumBps: bigint | string;\r\n /** Maximum funding rate change per slot in bps (i64). */\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\r\n markMinFee: bigint | string;\r\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\r\n forceCloseDelaySlots: bigint | string;\r\n /**\r\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\r\n *\r\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\r\n * the wrapper applies its deployment default\r\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\r\n * emits a 74-byte v2 tail with this value appended after\r\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\r\n * `InvalidConfigParam`; the engine then re-validates the solvency\r\n * envelope at `init_in_place`.\r\n *\r\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\r\n */\r\n maxPriceMoveBpsPerSlot?: bigint | string;\r\n}\r\n\r\nexport interface InitMarketArgs {\r\n admin: PublicKey | string;\r\n collateralMint: PublicKey | string;\r\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\r\n maxStalenessSecs: bigint | string;\r\n confFilterBps: number;\r\n invert: number;\r\n unitScale: number;\r\n initialMarkPriceE6: bigint | string;\r\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\r\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n maxInsuranceFloor?: bigint | string;\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n minOraclePriceCap?: bigint | string;\r\n // RiskParams block (16 fields, read by read_risk_params on-chain)\r\n /**\r\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\r\n * when hMin/hMax are not provided.\r\n */\r\n warmupPeriodSlots?: bigint | string;\r\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMin?: bigint | string;\r\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMax?: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n initialMarginBps: bigint | string;\r\n tradingFeeBps: bigint | string;\r\n maxAccounts: bigint | string;\r\n newAccountFee: bigint | string;\r\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\r\n maintenanceFeePerSlot: bigint | string;\r\n maxCrankStalenessSlots: bigint | string;\r\n liquidationFeeBps: bigint | string;\r\n liquidationFeeCap: bigint | string;\r\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\r\n minLiquidationAbs: bigint | string;\r\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\r\n minInitialDeposit?: bigint | string;\r\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\r\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\r\n /**\r\n * Optional 66-byte extended tail (S-4).\r\n * When present and any field is non-zero, appended after the 344-byte base payload.\r\n * When absent (or all zeros), the base 344-byte payload is sent and the program\r\n * uses default zero values for all extended fields.\r\n * @see InitMarketExtendedTail\r\n */\r\n extendedTail?: InitMarketExtendedTail;\r\n}\r\n\r\n/**\r\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\r\n *\r\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\r\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\r\n * Retained as a utility for off-chain feed ID validation.\r\n */\r\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function encodeFeedId(feedId: string): Uint8Array {\r\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\r\n if (!HEX_RE.test(hex)) {\r\n throw new Error(\r\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\r\n );\r\n }\r\n const bytes = new Uint8Array(32);\r\n for (let i = 0; i < 64; i += 2) {\r\n const byte = parseInt(hex.substring(i, i + 2), 16);\r\n if (Number.isNaN(byte)) {\r\n throw new Error(\r\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\r\n );\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\r\n * (10_000_000_000_000_000 — effectively unlimited).\r\n *\r\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\r\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\r\n * engine returns `RecoveryRequired` and refuses further liquidation until\r\n * the insurance fund covers the residual. Production markets MUST use this\r\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\r\n * limit is intended AND the insurance fund is sized accordingly.\r\n *\r\n * @example\r\n * ```ts\r\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\r\n * const data = encodeInitMarket({\r\n * ...otherParams,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\r\n\r\n// v17 wire layout (v16_program.rs decode arm at tag 0):\r\n// tag(1) +\r\n// max_portfolio_assets(u16=2) +\r\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\r\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\r\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\r\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\r\n// liquidation_fee_bps(u64=8) +\r\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\r\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\r\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\r\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\r\n// max_bankrupt_close_lifetime_slots(u64=8) +\r\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\r\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\r\nconst INIT_MARKET_V17_LEN = 219;\r\n\r\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\r\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\r\n// with no optional tail — all parameters are required fields in the main body.\r\n\r\n/**\r\n * InitMarket v17 argument interface.\r\n *\r\n * admin and collateralMint are passed as account metas (accounts[0] and\r\n * accounts[2] respectively), NOT in instruction data.\r\n *\r\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\r\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\r\n * after the market is created.\r\n *\r\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\r\n * max_portfolio_assets, h_min, h_max, initial_price,\r\n * min_nonzero_mm_req, min_nonzero_im_req,\r\n * maintenance_margin_bps, initial_margin_bps,\r\n * max_trading_fee_bps, trade_fee_base_bps,\r\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\r\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\r\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\r\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\r\n * max_bankrupt_close_lifetime_slots,\r\n * public_b_chunk_atoms, maintenance_fee_per_slot.\r\n */\r\nexport interface InitMarketV17Args {\r\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\r\n maxPortfolioAssets: number;\r\n /** Minimum funding horizon in slots (u64). */\r\n hMin: bigint | string;\r\n /** Maximum funding horizon in slots (u64). */\r\n hMax: bigint | string;\r\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\r\n initialPrice: bigint | string;\r\n /** Minimum non-zero maintenance margin requirement (u128). */\r\n minNonzeroMmReq: bigint | string;\r\n /** Minimum non-zero initial margin requirement (u128). */\r\n minNonzeroImReq: bigint | string;\r\n /** Maintenance margin ratio in bps (u64). */\r\n maintenanceMarginBps: bigint | string;\r\n /** Initial margin ratio in bps (u64). */\r\n initialMarginBps: bigint | string;\r\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\r\n maxTradingFeeBps: bigint | string;\r\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\r\n tradeFeeBaseBps: bigint | string;\r\n /** Liquidation fee in bps (u64). */\r\n liquidationFeeBps: bigint | string;\r\n /** Liquidation fee cap in absolute units (u128). */\r\n liquidationFeeCap: bigint | string;\r\n /** Minimum liquidation size in absolute units (u128). */\r\n minLiquidationAbs: bigint | string;\r\n /** Maximum price movement per slot in bps (u64). */\r\n maxPriceMoveBpsPerSlot: bigint | string;\r\n /** Maximum accrual delta-time in slots (u64). */\r\n maxAccrualDtSlots: bigint | string;\r\n /** Maximum absolute funding rate in e9 per slot (u64). */\r\n maxAbsFundingE9PerSlot: bigint | string;\r\n /** Minimum funding lifetime in slots (u64). */\r\n minFundingLifetimeSlots: bigint | string;\r\n /** Maximum account-B settlement chunks per crank (u64). */\r\n maxAccountBSettlementChunks: bigint | string;\r\n /** Maximum bankrupt-close chunks per crank (u64). */\r\n maxBankruptCloseChunks: bigint | string;\r\n /** Maximum bankrupt-close lifetime in slots (u64). */\r\n maxBankruptCloseLifetimeSlots: bigint | string;\r\n /**\r\n * Public-B chunk size in atoms (u128).\r\n *\r\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\r\n * the engine returns `RecoveryRequired` when the bankrupt position's\r\n * liability exceeds this limit and insurance is insufficient to cover it.\r\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\r\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\r\n * and a funded insurance pool.\r\n */\r\n publicBChunkAtoms: bigint | string;\r\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\n/**\r\n * Encode InitMarket instruction data (v17 wire format).\r\n *\r\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\r\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\r\n *\r\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\r\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\r\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\r\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\r\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\r\n *\r\n * @param args v17 market parameters (InitMarketV17Args)\r\n * @returns 227-byte Uint8Array\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMarket({\r\n * maxPortfolioAssets: 256,\r\n * hMin: 1000n,\r\n * hMax: 100000n,\r\n * initialPrice: 50_000_000_000n,\r\n * minNonzeroMmReq: 1_000_000n,\r\n * minNonzeroImReq: 2_000_000n,\r\n * maintenanceMarginBps: 500n,\r\n * initialMarginBps: 1000n,\r\n * maxTradingFeeBps: 100n,\r\n * tradeFeeBaseBps: 30n,\r\n * liquidationFeeBps: 100n,\r\n * liquidationFeeCap: 10_000_000n,\r\n * minLiquidationAbs: 1_000_000n,\r\n * maxPriceMoveBpsPerSlot: 4n,\r\n * maxAccrualDtSlots: 600n,\r\n * maxAbsFundingE9PerSlot: 1000n,\r\n * minFundingLifetimeSlots: 50n,\r\n * maxAccountBSettlementChunks: 10n,\r\n * maxBankruptCloseChunks: 10n,\r\n * maxBankruptCloseLifetimeSlots: 500n,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\r\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\r\n const isV17Args = 'maxPortfolioAssets' in args;\r\n\r\n let maxPortfolioAssets: number;\r\n let hMin: bigint | string;\r\n let hMax: bigint | string;\r\n let initialPrice: bigint | string;\r\n let minNonzeroMmReq: bigint | string;\r\n let minNonzeroImReq: bigint | string;\r\n let maintenanceMarginBps: bigint | string;\r\n let initialMarginBps: bigint | string;\r\n let maxTradingFeeBps: bigint | string;\r\n let tradeFeeBaseBps: bigint | string;\r\n let liquidationFeeBps: bigint | string;\r\n let liquidationFeeCap: bigint | string;\r\n let minLiquidationAbs: bigint | string;\r\n let maxPriceMoveBpsPerSlot: bigint | string;\r\n let maxAccrualDtSlots: bigint | string;\r\n let maxAbsFundingE9PerSlot: bigint | string;\r\n let minFundingLifetimeSlots: bigint | string;\r\n let maxAccountBSettlementChunks: bigint | string;\r\n let maxBankruptCloseChunks: bigint | string;\r\n let maxBankruptCloseLifetimeSlots: bigint | string;\r\n let publicBChunkAtoms: bigint | string;\r\n let maintenanceFeePerSlot: bigint | string;\r\n\r\n if (isV17Args) {\r\n const v = args as InitMarketV17Args;\r\n maxPortfolioAssets = v.maxPortfolioAssets;\r\n hMin = v.hMin;\r\n hMax = v.hMax;\r\n initialPrice = v.initialPrice;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n maxTradingFeeBps = v.maxTradingFeeBps;\r\n tradeFeeBaseBps = v.tradeFeeBaseBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\r\n maxAccrualDtSlots = v.maxAccrualDtSlots;\r\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\r\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\r\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\r\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\r\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\r\n publicBChunkAtoms = v.publicBChunkAtoms;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n } else {\r\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\r\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\r\n // invert, unitScale, extendedTail) are silently ignored.\r\n const v = args as InitMarketArgs;\r\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\r\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\r\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\r\n hMin = resolvedHMin;\r\n hMax = resolvedHMax;\r\n initialPrice = v.initialMarkPriceE6;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\r\n maxTradingFeeBps = v.tradingFeeBps;\r\n tradeFeeBaseBps = v.tradingFeeBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\r\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\r\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\r\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\r\n minFundingLifetimeSlots = 0n;\r\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\r\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\r\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\r\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\r\n // them to functional values instead so v12-initialized markets stay recoverable; callers\r\n // wanting explicit control should migrate to InitMarketV17Args.\r\n maxAccountBSettlementChunks = 10n;\r\n maxBankruptCloseChunks = 10n;\r\n maxBankruptCloseLifetimeSlots = 500n;\r\n publicBChunkAtoms = 1_000_000n;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n }\r\n\r\n const data = concatBytes(\r\n encU8(IX_TAG.InitMarket),\r\n encU16(maxPortfolioAssets),\r\n encU64(hMin),\r\n encU64(hMax),\r\n encU64(initialPrice),\r\n encU128(minNonzeroMmReq),\r\n encU128(minNonzeroImReq),\r\n encU64(maintenanceMarginBps),\r\n encU64(initialMarginBps),\r\n encU64(maxTradingFeeBps),\r\n encU64(tradeFeeBaseBps),\r\n encU64(liquidationFeeBps),\r\n encU128(liquidationFeeCap),\r\n encU128(minLiquidationAbs),\r\n encU64(maxPriceMoveBpsPerSlot),\r\n encU64(maxAccrualDtSlots),\r\n encU64(maxAbsFundingE9PerSlot),\r\n encU64(minFundingLifetimeSlots),\r\n encU64(maxAccountBSettlementChunks),\r\n encU64(maxBankruptCloseChunks),\r\n encU64(maxBankruptCloseLifetimeSlots),\r\n encU128(publicBChunkAtoms),\r\n encU128(maintenanceFeePerSlot),\r\n );\r\n\r\n if (data.length !== INIT_MARKET_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n return data;\r\n}\r\n\r\n/**\r\n * InitPortfolio / InitUser instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\r\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\r\n * Sending extra bytes causes garbage reads in downstream decoder arms.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitUser();\r\n * ```\r\n */\r\nexport interface InitUserArgs {\r\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\r\n feePayment?: bigint | string;\r\n}\r\n\r\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.InitPortfolio]);\r\n}\r\n\r\n/**\r\n * InitLP (tag 2) — REMOVED in v17.\r\n *\r\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\r\n */\r\nexport interface InitLPArgs {\r\n matcherProgram: PublicKey | string;\r\n matcherContext: PublicKey | string;\r\n feePayment: bigint | string;\r\n}\r\n\r\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\r\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\r\n}\r\n\r\n/**\r\n * DepositCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\r\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\r\n *\r\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface DepositCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\r\n *\r\n * @param amount Collateral to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\r\n * ```\r\n */\r\nexport interface WithdrawCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) action byte values.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\r\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\r\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\r\n */\r\nexport const CrankAction = {\r\n FeeSweep: 0,\r\n Liquidate: 1,\r\n} as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) instruction args.\r\n *\r\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\r\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\r\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\r\n * and the fee rate is always read from config inside\r\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\r\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\r\n * while still making forward progress. Any client still encoding the old\r\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\r\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\r\n * side, not a runtime check.\r\n *\r\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\r\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\r\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\r\n * `read_u64`/`read_i128`/`push_*` call sequence.\r\n *\r\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\r\n * The program hard-rejects any nonzero value with InvalidInstructionData.\r\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\r\n * produces a truncated instruction (missing 16 bytes).\r\n *\r\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\r\n * @param assetIndex Asset/domain index to operate on.\r\n * @param nowSlot Current slot (for crank freshness check).\r\n * @param recoveryReason Recovery reason byte (0 for normal operations).\r\n *\r\n * @example\r\n * ```ts\r\n * // Simple fee-sweep crank\r\n * const data = encodePermissionlessCrank({\r\n * action: CrankAction.FeeSweep,\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * recoveryReason: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface PermissionlessCrankArgs {\r\n action: number;\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n recoveryReason: number;\r\n}\r\n\r\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.PermissionlessCrank),\r\n encU8(args.action),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\r\n encU8(args.recoveryReason),\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\r\n * Use encodePermissionlessCrank() instead.\r\n *\r\n * Retained for source-compat only. Will throw to prevent silent misuse.\r\n */\r\nexport interface KeeperCrankArgs {\r\n callerIdx: number;\r\n candidates?: unknown[];\r\n}\r\n\r\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\r\n throw new Error(\r\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\r\n \"Use encodePermissionlessCrank() instead.\"\r\n );\r\n}\r\n\r\n/**\r\n * TradeNoCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\r\n * v17 has asset_index+size_q+exec_price+fee_bps.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\r\n * @param execPrice Execution price in e6 units.\r\n * @param feeBps Fee in basis points.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeNoCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * execPrice: 50_000_000_000n,\r\n * feeBps: 30n,\r\n * });\r\n * ```\r\n */\r\nexport interface TradeNoCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeNoCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.execPrice),\r\n encU64(args.feeBps),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\r\n *\r\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\r\n */\r\nexport interface LiquidateAtOracleArgs {\r\n targetIdx: number;\r\n}\r\n\r\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LiquidateAtOracle\",\r\n IX_TAG.LiquidateAtOracle,\r\n \"PermissionlessCrank (tag 5)\",\r\n );\r\n}\r\n\r\n/**\r\n * ClosePortfolio / CloseAccount instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\r\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\r\n * bytes from the old userIdx field cause InvalidInstructionData.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseAccount();\r\n * ```\r\n */\r\nexport interface CloseAccountArgs {\r\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\r\n userIdx?: number;\r\n}\r\n\r\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.ClosePortfolio]);\r\n}\r\n\r\n/**\r\n * TopUpInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\r\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\r\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\r\n *\r\n * @param amount Amount to top up the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\r\n * ```\r\n */\r\nexport interface TopUpInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * TopUpBackingBucket instruction data (tag 24).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\r\n * = 27 bytes.\r\n *\r\n * Deposits `amount` quote atoms of external collateral into a source domain's\r\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\r\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\r\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\r\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\r\n *\r\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\r\n * SHORT domain is `2*i + 1`.\r\n *\r\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\r\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\r\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\r\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\r\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\r\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\r\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\r\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\r\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\r\n * every later automatic loss-reserve requests the SAME existing expiry and\r\n * hits the harmless no-op arm instead of the LockActive trap.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\r\n * nonzero \"dust\" amount is sufficient — there is no\r\n * minimum floor enforced by the engine.\r\n * @param expirySlot Requested fresh-expiry slot (u64). Use\r\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\r\n *\r\n * @example\r\n * ```ts\r\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\r\n * const data = encodeTopUpBackingBucket({\r\n * domain: 0,\r\n * amount: 10_000n, // 0.01 Sim-USDC dust\r\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\r\n * });\r\n * ```\r\n */\r\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\r\n\r\nexport interface TopUpBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n expirySlot: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TopUpBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n encU64(args.expirySlot),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucket instruction data (tag 50).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\r\n * back to the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\r\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\r\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\r\n *\r\n * Together with TopUpBackingBucket (24, deposit) and\r\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\r\n * LP-provider backing-bucket loop.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateBackingFeePolicy instruction data (tag 51).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * THE switch that turns on LP-vault yield for a domain: sets the\r\n * backing-trade fee charged on that domain's fills, of which\r\n * `insurance_share_bps` is diverted to the insurance budget and the\r\n * remainder accrues to the domain's backing-bucket providers as\r\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\r\n * currently has this at 0 — which is why LP APY is 0%.\r\n *\r\n * Gated by the asset's `insurance_authority` (v16_program.rs\r\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\r\n * the market creator can call it even after the launch flow rotates\r\n * marketauth to the stake-pool PDA. Market must be Live.\r\n *\r\n * Handler-side validation (reverts InvalidInstruction otherwise):\r\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\r\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\r\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\r\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\r\n * of the fee (the rest goes to backing providers).\r\n */\r\nexport interface UpdateBackingFeePolicyArgs {\r\n domain: number;\r\n feeBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateBackingFeePolicy),\r\n encU16(args.domain),\r\n encU16(args.feeBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings instruction data (tag 52).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\r\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\r\n * the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket_earnings` → same\r\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\r\n * per-domain ledger account is REQUIRED (account [2]).\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketEarningsArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucketEarnings(\r\n args: WithdrawBackingBucketEarningsArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * TradeCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\r\n * v17 has asset_index+size_q+fee_bps+limit_price.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed).\r\n * @param feeBps Fee in basis points.\r\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\r\n * Buys: reject if exec_price > limit_price.\r\n * Sells: reject if exec_price < limit_price.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * feeBps: 30n,\r\n * limitPrice: 51_000_000_000n, // max price for a buy\r\n * });\r\n * ```\r\n */\r\nexport interface TradeCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n /** Limit price in e6 units. 0 = no limit. */\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.feeBps),\r\n encU64(args.limitPrice),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\r\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\r\n */\r\nexport interface TradeCpiV2Args {\r\n lpIdx: number;\r\n userIdx: number;\r\n size: bigint | string;\r\n bump: number;\r\n}\r\n\r\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\r\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\r\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\r\n */\r\nexport interface UnresolveMarketArgs {\r\n confirmation: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\r\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\r\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetRiskThresholdArgs {\r\n newThreshold: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\r\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * UpdateAdmin (tag 12) — REMOVED in v17.\r\n *\r\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\r\n */\r\nexport interface UpdateAdminArgs {\r\n newAdmin: PublicKey | string;\r\n}\r\n\r\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\r\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateAdmin\",\r\n IX_TAG.UpdateAdmin,\r\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\r\n );\r\n}\r\n\r\n/**\r\n * CloseSlab instruction data (1 byte)\r\n */\r\nexport function encodeCloseSlab(): Uint8Array {\r\n return encU8(IX_TAG.CloseSlab);\r\n}\r\n\r\n/**\r\n * UpdateConfig instruction data.\r\n *\r\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\r\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\r\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\r\n * src/percolator.rs:2027-2041 (handle_update_config decode).\r\n */\r\nexport interface UpdateConfigArgs {\r\n fundingHorizonSlots: bigint | string;\r\n fundingKBps: bigint | string;\r\n fundingMaxPremiumBps: bigint | string;\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /**\r\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\r\n * Wrapper field added at src/percolator.rs:2031.\r\n */\r\n tvlInsuranceCapMult?: number;\r\n}\r\n\r\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\r\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\r\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetMaintenanceFeeArgs {\r\n newFee: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\r\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * SetOraclePriceCap instruction data (9 bytes)\r\n * Set oracle price circuit breaker cap (admin only).\r\n *\r\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\r\n * 1_000_000 = 100% max move per slot.\r\n *\r\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\r\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\r\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\r\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\r\n *\r\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\r\n */\r\nexport interface SetOraclePriceCapArgs {\r\n maxChangeE2bps: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\r\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\r\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\r\n}\r\n\r\n/**\r\n * ResolveMode constants — retained for source compatibility with v12.x callers.\r\n *\r\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\r\n * no longer encoded into the instruction data. They may be used in logging or\r\n * off-chain logic but must not be passed to encodeResolveMarket.\r\n */\r\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\r\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\r\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\r\n\r\n/**\r\n * ResolveMarket instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\r\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\r\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\r\n * next read in a subsequent call, corrupting the instruction stream.\r\n *\r\n * The `mode` argument is accepted for source compatibility but is silently ignored.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeResolveMarket();\r\n * ```\r\n */\r\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\r\n return new Uint8Array([IX_TAG.ResolveMarket]);\r\n}\r\n\r\n/**\r\n * WithdrawInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\r\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\r\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\r\n * 1-byte payload fails on devnet/mainnet.\r\n *\r\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\r\n *\r\n * @param amount Amount to withdraw from the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * AdminForceClose instruction data (3 bytes)\r\n * Force-close any position at oracle price (admin only, skips margin checks).\r\n */\r\nexport interface AdminForceCloseArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\r\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\r\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\r\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\r\n * Use encodeSetInsuranceWithdrawPolicy instead.\r\n */\r\nexport interface UpdateRiskParamsArgs {\r\n initialMarginBps: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n tradingFeeBps?: bigint | string;\r\n}\r\n\r\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\r\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateRiskParams\",\r\n IX_TAG.UpdateRiskParams,\r\n \"encodeSetInsuranceWithdrawPolicy()\",\r\n );\r\n}\r\n\r\n/**\r\n * On-chain confirmation code for RenounceAdmin (must match program constant).\r\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\r\n */\r\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\r\n\r\n/**\r\n * On-chain confirmation code for UnresolveMarket (must match program constant).\r\n */\r\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\r\n\r\n/**\r\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\r\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\r\n * Use encodeWithdrawInsuranceLimited instead.\r\n */\r\nexport function encodeRenounceAdmin(): Uint8Array {\r\n return removedInstruction(\r\n \"RenounceAdmin\",\r\n IX_TAG.RenounceAdmin,\r\n \"encodeWithdrawInsuranceLimited()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\r\n * withdraw proportional collateral.\r\n *\r\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\r\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\r\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\r\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\r\n *\r\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\r\n *\r\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\r\n * [0] withdrawer signer\r\n * [1] slab writable\r\n * [2] withdrawerAta writable\r\n * [3] vault writable\r\n * [4] tokenProgram\r\n * [5] lpVaultMint writable\r\n * [6] withdrawerLpAta writable\r\n * [7] vaultAuthority\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\r\n *\r\n * @param lpAmount - Amount of LP vault tokens to burn.\r\n *\r\n * @example\r\n * ```ts\r\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\r\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\r\n *\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\r\n *\r\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\r\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\r\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\r\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\r\n * });\r\n * ```\r\n */\r\nexport interface LpVaultWithdrawArgs {\r\n /** Amount of LP vault tokens to burn. */\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\r\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\r\n */\r\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\r\n IX_TAG.LpVaultWithdraw,\r\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\r\n */\r\nexport function encodePauseMarket(): Uint8Array {\r\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\r\n */\r\nexport function encodeUnpauseMarket(): Uint8Array {\r\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-117: Pyth Oracle CPI Instructions\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetPythOracleArgs {\r\n feedId: Uint8Array;\r\n maxStalenessSecs: bigint;\r\n confFilterBps: number;\r\n}\r\n\r\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\r\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\r\n void args;\r\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\r\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\r\n *\r\n * @param feedId 32-byte Pyth feed ID\r\n * @param shardId Shard index (default 0 for mainnet/devnet)\r\n */\r\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\r\n\r\nexport async function derivePythPriceUpdateAccount(\r\n feedId: Uint8Array,\r\n shardId = 0,\r\n): Promise {\r\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\r\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\r\n }\r\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\r\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\r\n }\r\n const { PublicKey } = await import('@solana/web3.js');\r\n const shardBuf = new Uint8Array(2);\r\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\r\n const [pda] = PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\r\n );\r\n return pda.toBase58();\r\n}\r\n\r\n// SetPythOracle tag (32) is already defined in IX_TAG above.\r\n\r\n// PERC-118: Mark Price EMA Instructions\r\n// ============================================================================\r\n\r\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\r\n\r\n/**\r\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport function encodeUpdateMarkPrice(): Uint8Array {\r\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\r\n}\r\n\r\n/**\r\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\r\n */\r\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\r\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\r\n\r\n/**\r\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\r\n */\r\nexport function computeEmaMarkPrice(\r\n markPrevE6: bigint,\r\n oracleE6: bigint,\r\n dtSlots: bigint,\r\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\r\n capE2bps = 0n,\r\n): bigint {\r\n if (oracleE6 === 0n) return markPrevE6;\r\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\r\n\r\n let oracleClamped = oracleE6;\r\n if (capE2bps > 0n) {\r\n // Avoid overflow: divide early to reduce intermediate product\r\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\r\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\r\n const hi = markPrevE6 + maxDelta;\r\n if (oracleClamped < lo) oracleClamped = lo;\r\n if (oracleClamped > hi) oracleClamped = hi;\r\n }\r\n\r\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\r\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\r\n\r\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\r\n}\r\n\r\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\r\n// ============================================================================\r\n\r\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\r\n\r\n/**\r\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\r\n *\r\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\r\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\r\n * to authority_price_e6 on the slab.\r\n *\r\n * This is the core mechanism for permissionless token markets — no Pyth or\r\n * Chainlink feed is needed. The DEX AMM IS the oracle.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\r\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\r\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\r\n */\r\nexport function encodeUpdateHyperpMark(): Uint8Array {\r\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\r\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\r\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\r\n return removedInstruction(\r\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\r\n 34,\r\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-306: Per-Market Insurance Isolation\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\r\n */\r\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\r\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\r\n}\r\n\r\n/**\r\n * Set insurance isolation BPS for a market.\r\n * Accounts: [admin(signer), slab(writable)]\r\n */\r\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\r\n void args;\r\n return removedInstruction(\r\n \"SetInsuranceIsolation\",\r\n IX_TAG.SetInsuranceIsolation,\r\n \"encodeFundMarketInsurance()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\r\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\r\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\r\n// ============================================================================\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\r\n *\r\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\r\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\r\n *\r\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\r\n * ```\r\n */\r\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\r\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n/**\r\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\r\n *\r\n * Burns LP tokens and releases one tranche of SOL to the user.\r\n * Call once per epoch until epochs_remaining == 0.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\r\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\r\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\r\n */\r\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\r\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\r\n *\r\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\r\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\r\n * Use only to abandon a partial withdrawal.\r\n *\r\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\r\n */\r\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\r\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\r\n *\r\n * Permissionless. Surgically closes or reduces `targetIdx` position when\r\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\r\n * the incentive is unblocking the market for normal trading.\r\n *\r\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\r\n *\r\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\r\n *\r\n * @param targetIdx - Account index of the position to deleverage.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteAdl({ targetIdx: 5 });\r\n * ```\r\n */\r\nexport interface ExecuteAdlArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\r\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\r\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\r\n *\r\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\r\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\r\n * whose size does not match any current valid tier.\r\n *\r\n * Accounts: [dest(signer,writable), slab(writable)]\r\n */\r\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\r\nexport function encodeCloseStaleSlabs(): Uint8Array {\r\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\r\n}\r\n\r\n/**\r\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\r\n *\r\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\r\n * The slab account must sign (proves the caller holds the slab keypair).\r\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\r\n *\r\n * Accounts: [dest(signer,writable), slab(signer,writable)]\r\n */\r\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\r\nexport function encodeReclaimSlabRent(): Uint8Array {\r\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\r\n *\r\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\r\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\r\n * prevent DoS from transient failures).\r\n *\r\n * Accounts: [slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeAuditCrank();\r\n * ```\r\n */\r\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\r\nexport function encodeAuditCrank(): Uint8Array {\r\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// SMART PRICE ROUTER — quote computation for LP selection\r\n// ============================================================================\r\n\r\n/**\r\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\r\n */\r\nexport interface VammMatcherParams {\r\n mode: number; // 0 = Passive, 1 = vAMM\r\n tradingFeeBps: number;\r\n baseSpreadBps: number;\r\n maxTotalBps: number;\r\n impactKBps: number;\r\n liquidityNotionalE6: bigint;\r\n}\r\n\r\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\r\nexport const VAMM_MAGIC = 0x504552434d415443n;\r\n/** Alias matching the Rust constant name for parity tests */\r\nexport const MATCHER_MAGIC = VAMM_MAGIC;\r\n\r\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\r\nexport const CTX_RETURN_OFFSET = 0;\r\n/** Byte length of the MatcherReturn section of the context account */\r\nexport const MATCHER_RETURN_LEN = 64;\r\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\r\nexport const CTX_VAMM_OFFSET = 64;\r\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\r\nexport const CTX_VAMM_LEN = 256;\r\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\r\nexport const MATCHER_CONTEXT_LEN = 320;\r\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\r\nexport const MATCHER_CALL_LEN = 67;\r\n/**\r\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\r\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\r\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\r\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\r\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\r\n */\r\nexport const INIT_CTX_LEN = 78;\r\n\r\nconst BPS_DENOM = 10_000n;\r\n\r\n/**\r\n * Compute execution price for a given LP quote.\r\n * For buys (isLong=true): price above oracle.\r\n * For sells (isLong=false): price below oracle.\r\n */\r\nexport function computeVammQuote(\r\n params: VammMatcherParams,\r\n oraclePriceE6: bigint,\r\n tradeSize: bigint,\r\n isLong: boolean,\r\n): bigint {\r\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\r\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\r\n\r\n // Impact for vAMM mode\r\n let impactBps = 0n;\r\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\r\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\r\n }\r\n\r\n // Total = base_spread + trading_fee + impact, capped at max_total\r\n const maxTotal = BigInt(params.maxTotalBps);\r\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\r\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\r\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\r\n let totalBps = baseFee + clampedImpact;\r\n if (totalBps > maxTotal) totalBps = maxTotal;\r\n\r\n if (isLong) {\r\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\r\n } else {\r\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\r\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\r\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless crank)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\r\n *\r\n * Checks if a market should transition from Phase 0→1→2 based on\r\n * time elapsed and cumulative volume. Anyone can call this.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n */\r\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\r\nexport function encodeAdvanceOraclePhase(): Uint8Array {\r\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\r\n}\r\n\r\n/** Oracle phase constants matching on-chain values */\r\nexport const ORACLE_PHASE_NASCENT = 0;\r\nexport const ORACLE_PHASE_GROWING = 1;\r\nexport const ORACLE_PHASE_MATURE = 2;\r\n\r\n/** Phase transition thresholds (must match program constants) */\r\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\r\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\r\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\r\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\r\n\r\n/**\r\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\r\n *\r\n * @returns [newPhase, shouldTransition]\r\n */\r\nexport function checkPhaseTransition(\r\n currentSlot: bigint,\r\n marketCreatedSlot: bigint,\r\n oraclePhase: number,\r\n cumulativeVolumeE6: bigint,\r\n phase2DeltaSlots: number,\r\n hasMatureOracle: boolean,\r\n): [number, boolean] {\r\n switch (oraclePhase) {\r\n case 0: {\r\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\r\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\r\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\r\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\r\n if (timeReady || volumeReady) {\r\n return [ORACLE_PHASE_GROWING, true];\r\n }\r\n return [ORACLE_PHASE_NASCENT, false];\r\n }\r\n case 1: {\r\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\r\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\r\n const elapsedSincePhase2 = currentSlot - phase2Start;\r\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\r\n return [ORACLE_PHASE_MATURE, true];\r\n }\r\n return [ORACLE_PHASE_GROWING, false];\r\n }\r\n default:\r\n return [ORACLE_PHASE_MATURE, false];\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-629: Dynamic Creation Deposit\r\n// ============================================================================\r\n\r\n/**\r\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\r\n * after the spam grace period has elapsed (PERC-629).\r\n *\r\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\r\n * handler in the on-chain program. Sending this instruction will fail with\r\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [] Slab\r\n * 2. [writable] Creator history PDA\r\n * 3. [writable] Insurance vault\r\n * 4. [writable] Treasury\r\n * 5. [] System program\r\n *\r\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\r\n */\r\nexport function encodeSlashCreationDeposit(): Uint8Array {\r\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\r\n// ============================================================================\r\n\r\n/**\r\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\r\n *\r\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [writable] Shared vault PDA\r\n * 2. [] System program\r\n */\r\nexport interface InitSharedVaultArgs {\r\n epochDurationSlots: bigint | string;\r\n maxMarketExposureBps: number;\r\n}\r\n\r\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\r\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\r\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\r\n}\r\n\r\n/**\r\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\r\n * to a market (PERC-628).\r\n *\r\n * Instruction data: tag(1) + amount(16) = 17 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [] Slab\r\n * 2. [writable] Shared vault PDA\r\n * 3. [writable] Market alloc PDA\r\n * 4. [] System program\r\n */\r\nexport interface AllocateMarketArgs {\r\n amount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\r\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\r\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\r\n}\r\n\r\n/**\r\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\r\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\r\n *\r\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] System program\r\n */\r\nexport interface QueueWithdrawalSVArgs {\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\r\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\r\n}\r\n\r\n/**\r\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\r\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] Slab\r\n * 4. [writable] Vault\r\n * 5. [writable] User ATA\r\n * 6. [] Vault authority\r\n * 7. [] Token program\r\n */\r\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\r\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\r\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [writable] Shared vault PDA\r\n */\r\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\r\nexport function encodeAdvanceEpoch(): Uint8Array {\r\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\r\n}\r\n\r\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\r\n\r\n// PERC-8110 ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\r\n *\r\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\r\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\r\n *\r\n * - `threshold_bps = 0`: hard block disabled.\r\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\r\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\r\n *\r\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\r\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\r\n * });\r\n * ```\r\n */\r\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\r\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-608 — Position NFT instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\r\n *\r\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\r\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\r\n *\r\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\r\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\r\n * program creates it, so the ATA can't be created in a preceding instruction.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts (11):\r\n * 0. [signer, writable] payer\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\r\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\r\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\r\n * 5. [signer] owner (must match engine account owner)\r\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\r\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\r\n * 8. [] system_program\r\n * 9. [] rent sysvar\r\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\r\n */\r\nexport interface MintPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\r\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\r\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\r\n */\r\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\r\n IX_TAG.MintPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\r\n *\r\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\r\n * engine account's owner field. Requires `pending_settlement == 0`.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] current_owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA\r\n * 3. [writable] nft_mint PDA\r\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\r\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\r\n * 6. [] new_owner\r\n * 7. [] token_2022_program\r\n */\r\nexport interface TransferPositionOwnershipArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\r\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\r\n */\r\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\r\n IX_TAG.TransferPositionOwnership,\r\n \"encodeTransferPortfolioOwnership() (tag 72)\",\r\n );\r\n}\r\n\r\n/**\r\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\r\n *\r\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\r\n * Can only be called after the position is fully closed (size == 0).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (closed — rent to owner)\r\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\r\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\r\n * 5. [] vault_authority PDA\r\n * 6. [] token_2022_program\r\n */\r\nexport interface BurnPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\r\n * NFT burn is handled by the standalone percolator-nft program in v17.\r\n */\r\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\r\n IX_TAG.BurnPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin before performing a funding settlement transfer.\r\n * Blocks NFT transfers until ClearPendingSettlement is called.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface SetPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\r\n */\r\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\r\n IX_TAG.SetPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface ClearPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\r\n */\r\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\r\n IX_TAG.ClearPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\r\n *\r\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\r\n * Updates the engine account's owner field to the new_owner public key.\r\n * NOT intended for direct external use — always called via Token-2022 CPI.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] nft TransferHook program (CPI caller)\r\n * 1. [writable] slab\r\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\r\n */\r\nexport interface TransferOwnershipCpiArgs {\r\n userIdx: number;\r\n newOwner: PublicKey | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\r\n */\r\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\r\n IX_TAG.TransferOwnershipCpi,\r\n \"percolator-nft transfer hook\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-8111 — SetWalletCap (tag 70)\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\r\n *\r\n * Limits the maximum absolute position size any single wallet may hold on this market.\r\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\r\n *\r\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\r\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\r\n * Phase 1 launch value: 1_000_000_000n ($1,000).\r\n *\r\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\r\n * (error code 58) is returned.\r\n *\r\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * // Set $1K per-wallet cap\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\r\n * });\r\n *\r\n * // Disable cap\r\n * const disableIx = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\r\n * });\r\n * ```\r\n */\r\nexport interface SetWalletCapArgs {\r\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\r\n capE6: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\r\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\r\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\r\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\r\n *\r\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\r\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\r\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\r\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\r\n * handler reads the LP portfolio's stored matcher config and verifies that:\r\n * cfg.matcher_program == matcherProg\r\n * cfg.matcher_context == matcherCtx\r\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\r\n *\r\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\r\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\r\n * check on the deployed binary. No client-side signer of the delegate is needed.\r\n *\r\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\r\n * [0] lp_owner signer (LP portfolio owner)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\r\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\r\n * [4] matcher_prog read-only, executable (the matcher program)\r\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\r\n *\r\n * @param args.kind 0=Passive, 1=vAMM\r\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\r\n * @param args.baseSpreadBps Base spread in bps (u32)\r\n * @param args.maxTotalBps Max total spread in bps (u32)\r\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\r\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\r\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\r\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\r\n *\r\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\r\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\r\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\r\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\r\n * this tag free.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMatcherCtx({\r\n * kind: 0, // Passive\r\n * tradingFeeBps: 30,\r\n * baseSpreadBps: 50,\r\n * maxTotalBps: 200,\r\n * impactKBps: 0,\r\n * liquidityNotionalE6: 0n,\r\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\r\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\r\n * feeToInsuranceBps: 0,\r\n * skewSpreadMultBps: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface InitMatcherCtxArgs {\r\n /**\r\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\r\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\r\n */\r\n lpIdx?: number;\r\n /** Matcher kind: 0=Passive, 1=vAMM. */\r\n kind: number;\r\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\r\n tradingFeeBps: number;\r\n /** Base spread in bps (u32). */\r\n baseSpreadBps: number;\r\n /** Max total spread in bps (u32). */\r\n maxTotalBps: number;\r\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\r\n impactKBps: number;\r\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\r\n liquidityNotionalE6: bigint | string;\r\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\r\n maxFillAbs: bigint | string;\r\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\r\n maxInventoryAbs: bigint | string;\r\n /** Fraction of fees routed to insurance fund in bps (u16). */\r\n feeToInsuranceBps: number;\r\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\r\n skewSpreadMultBps: number;\r\n}\r\n\r\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\r\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\r\n\r\n/**\r\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\r\n *\r\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\r\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\r\n *\r\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\r\n * @returns 70-byte Uint8Array\r\n */\r\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(83), // IX_TAG.InitMatcherCtx = 83\r\n encU8(args.kind),\r\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\r\n encU128(args.liquidityNotionalE6), // u128 LE\r\n encU128(args.maxFillAbs), // u128 LE\r\n encU128(args.maxInventoryAbs), // u128 LE\r\n encU16(args.feeToInsuranceBps), // u16 LE\r\n encU16(args.skewSpreadMultBps), // u16 LE\r\n );\r\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n// ============================================================================\r\n// Missing encoders — corrected tag mappings (tags 22-74)\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\r\n */\r\nexport interface SetInsuranceWithdrawPolicyArgs {\r\n authority: PublicKey | string;\r\n minWithdrawBase: bigint | string;\r\n maxWithdrawBps: number;\r\n cooldownSlots: bigint | string;\r\n}\r\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\r\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\r\n */\r\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\r\n */\r\nexport function encodeResolvePermissionless(): Uint8Array {\r\n return removedInstruction(\r\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\r\n IX_TAG.ResolvePermissionless,\r\n \"encodeResolveStalePermissionless()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\r\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\r\n return removedInstruction(\r\n \"ForceCloseResolved\",\r\n IX_TAG.ForceCloseResolved,\r\n \"encodeCloseResolved() for v17\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeCreateLpVault (v12 format)\",\r\n IX_TAG.CreateLpVault,\r\n \"encodeCreateLpVaultV17()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeLpVaultDeposit (v12 format)\",\r\n IX_TAG.LpVaultDeposit,\r\n \"encodeDepositToLpVault()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\r\n */\r\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"ChallengeSettlement\",\r\n IX_TAG.ChallengeSettlement,\r\n undefined,\r\n );\r\n}\r\n\r\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\r\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\r\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\r\n}\r\n\r\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\r\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\r\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\r\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\r\n}\r\n\r\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\r\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\r\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\r\n}\r\n\r\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\r\nexport function encodeRescueOrphanVault(): Uint8Array {\r\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\r\n}\r\n\r\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\r\nexport function encodeCloseOrphanSlab(): Uint8Array {\r\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\r\n}\r\n\r\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\r\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\r\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeCreateInsuranceMint(): Uint8Array {\r\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n// ============================================================================\r\n// Phase B admin setters (tags 78-81) — added 2026-04-17\r\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\r\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport interface SetMaxPnlCapArgs {\r\n cap: bigint | string;\r\n}\r\n\r\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\r\n IX_TAG.SetMaxPnlCap,\r\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\r\n */\r\nexport interface SetOiCapMultiplierArgs {\r\n packed: bigint | string;\r\n}\r\n\r\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\r\n IX_TAG.SetOiCapMultiplier,\r\n \"encodeSetLpVaultPaused() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\r\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\r\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\r\n }\r\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\r\n }\r\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\r\n */\r\nexport interface SetDisputeParamsArgs {\r\n windowSlots: bigint | string;\r\n bondAmount: bigint | string;\r\n}\r\n\r\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\r\n IX_TAG.SetDisputeParams,\r\n \"encodeCloseLpVault() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\r\n */\r\nexport interface SetLpCollateralParamsArgs {\r\n enabled: number;\r\n ltvBps: number;\r\n}\r\n\r\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\r\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\r\n */\r\nexport function encodeAcceptAdmin(): Uint8Array {\r\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\r\n}\r\n\r\n// ============================================================================\r\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\r\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\r\n */\r\nexport interface ReclaimEmptyAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\r\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\r\n */\r\nexport interface SettleAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\r\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\r\n */\r\nexport interface DepositFeeCreditsArgs {\r\n userIdx: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\r\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\r\n}\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\r\n * Owner only.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\r\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\r\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\r\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\r\n * are identified by account key alone.\r\n *\r\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\r\n *\r\n * @param amount Amount of released PnL to convert (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface ConvertReleasedPnlArgs {\r\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ConvertReleasedPnl),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\r\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\r\n *\r\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\r\n *\r\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\r\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\r\n * Burning marketauth to zero is rejected on-chain.\r\n *\r\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\r\n * ```\r\n */\r\nexport interface UpdateAuthorityArgs {\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAuthority),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — UpdateAssetAuthority (tag 65)\r\n// ============================================================================\r\n\r\n/**\r\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\r\n *\r\n * Exact mapping from v16_program.rs lines 5246-5250:\r\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\r\n * ASSET_AUTH_INSURANCE = 1 → Insurance\r\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\r\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\r\n * ASSET_AUTH_ORACLE = 4 → Oracle\r\n *\r\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\r\n * slot. Wrong values silently corrupt authority state:\r\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\r\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\r\n * corrupting the market-level admin key instead.\r\n *\r\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\r\n * the stake vault PDA into the asset_admin authority slot.\r\n */\r\nexport const ASSET_AUTH_KIND = {\r\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\r\n AssetAdmin: 0,\r\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\r\n Insurance: 1,\r\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\r\n InsuranceOperator: 2,\r\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\r\n BackingBucket: 3,\r\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\r\n Oracle: 4,\r\n} as const;\r\nObject.freeze(ASSET_AUTH_KIND);\r\n\r\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\r\n\r\n/**\r\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * Gated by the asset's own asset_admin (can rotate any) or by the current\r\n * holder of that authority (self-rotation). Isolated to the given asset_index.\r\n *\r\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\r\n * @param kind ASSET_AUTH_KIND.* constant.\r\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\r\n *\r\n * @example\r\n * ```ts\r\n * // Rotate insurance authority for asset 0\r\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\r\n * const data = encodeUpdateAssetAuthority({\r\n * assetIndex: 0,\r\n * kind: ASSET_AUTH_KIND.Insurance,\r\n * newPubkey: newInsuranceKey,\r\n * });\r\n * ```\r\n */\r\nexport interface UpdateAssetAuthorityArgs {\r\n assetIndex: number;\r\n kind: AssetAuthKind;\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAssetAuthority),\r\n encU16(args.assetIndex),\r\n encU8(args.kind),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\r\n// ============================================================================\r\n\r\n/**\r\n * One leg of a BatchTradeNoCpi instruction.\r\n */\r\nexport interface BatchTradeNoCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\n/**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\r\n *\r\n * @param legs Array of up to 255 trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeNoCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\r\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\r\n * ]});\r\n * ```\r\n */\r\nexport interface BatchTradeNoCpiArgs {\r\n legs: BatchTradeNoCpiLeg[];\r\n}\r\n\r\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\r\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\r\n if (feeBps > 10_000n) {\r\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\r\n }\r\n}\r\n\r\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeNoCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.execPrice));\r\n parts.push(encU64(leg.feeBps));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n/**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\r\n *\r\n * @param legs Array of up to 255 CPI trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\r\n * ]});\r\n * ```\r\n */\r\n\r\nexport interface BatchTradeCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport interface BatchTradeCpiArgs {\r\n legs: BatchTradeCpiLeg[];\r\n}\r\n\r\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.feeBps));\r\n parts.push(encU64(leg.limitPrice));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — SetMatcherConfig (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n *\r\n * @param enabled 1 = enabled, 0 = disabled.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetMatcherConfig({ enabled: 1 });\r\n * ```\r\n */\r\nexport interface SetMatcherConfigArgs {\r\n enabled: number;\r\n}\r\n\r\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\r\n if (args.enabled !== 0 && args.enabled !== 1) {\r\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\r\n }\r\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — RestartAssetOracle (tag 69)\r\n// ============================================================================\r\n\r\n/**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\r\n *\r\n * Used to un-stick a stale or hung oracle. Anyone can call this.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param nowSlot Current slot.\r\n * @param initialPrice Initial mark price in e6 units.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRestartAssetOracle({\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * initialPrice: 50_000_000_000n,\r\n * });\r\n * ```\r\n */\r\nexport interface RestartAssetOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialPrice: bigint | string;\r\n}\r\n\r\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RestartAssetOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialPrice),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\r\n *\r\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\r\n * asset_index is u16 (domain u8→u16 migration in v17).\r\n *\r\n * @param assetIndex Asset/domain index (u16, not u8).\r\n * @param amount Amount to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceAssetArgs {\r\n assetIndex: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawInsuranceAsset),\r\n encU16(args.assetIndex),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — LP-vault renumbered tags (74-80)\r\n// ============================================================================\r\n\r\n/**\r\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\r\n *\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\r\n *\r\n * @param feeShareBps LP vault fee share in bps (0-10000).\r\n * @param redemptionCooldownSlots Slots between redemption requests.\r\n * @param oiReservationThresholdBps OI reservation threshold in bps.\r\n * @param domain Asset/domain index (u16 in v17).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCreateLpVault({\r\n * feeShareBps: 5000,\r\n * redemptionCooldownSlots: 21600n,\r\n * oiReservationThresholdBps: 8000,\r\n * domain: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface CreateLpVaultArgs {\r\n feeShareBps: number;\r\n redemptionCooldownSlots: bigint | string;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n}\r\n\r\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.CreateLpVault),\r\n encU16(args.feeShareBps),\r\n encU64(args.redemptionCooldownSlots),\r\n encU16(args.oiReservationThresholdBps),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\r\n *\r\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\r\n *\r\n * `domain` selects which pot of the vault's asset receives the backing and MUST\r\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\r\n * NAV across both pots, so the depositor is indifferent to the choice; routing\r\n * exists so new money can reach whichever pot the house is drawing on.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\r\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\r\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\r\n * and mint the depositor free shares at existing holders' expense.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\r\n * ```\r\n */\r\nexport function encodeDepositToLpVault(args: {\r\n amount: bigint | string;\r\n domain: number;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositToLpVault),\r\n encU128(args.amount),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\r\n *\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\r\n * v17 uses shares u128 and a two-step request/execute redemption flow.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\r\n * ```\r\n */\r\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\r\n}\r\n\r\n/**\r\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\r\n * available-principal stay COMBINED across both pots, so this does not change\r\n * what the redeemer is owed — only where the atoms come from. A redemption draws\r\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\r\n * cover it; rebalance (tag 91) first.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteRedemption({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\r\n * choice cannot dilute; routing exists so fees can become backing in the pot\r\n * that needs it. The target ledger is created on first use.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\r\n * index 5 is the system program (needed to create a missing target ledger).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeLpVaultCrankFees({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\r\n * the LP vault's asset.\r\n *\r\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\r\n *\r\n * Permissionless: both pots belong to the same vault, so the move cannot extract\r\n * value, and the source-side gate refuses anything that would leave the source\r\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\r\n * open interest, already consumed, or impaired stays put.\r\n *\r\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\r\n * systemProgram]. The destination ledger is created on first arrival.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRebalanceLpVaultBacking({\r\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeRebalanceLpVaultBacking(args: {\r\n fromDomain: number;\r\n toDomain: number;\r\n amount: bigint | string;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RebalanceLpVaultBacking),\r\n encU16(args.fromDomain),\r\n encU16(args.toDomain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\r\n *\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n *\r\n * @param paused 1 = paused, 0 = active.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetLpVaultPaused({ paused: 1 });\r\n * ```\r\n */\r\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\r\n}\r\n\r\n/**\r\n * CloseLpVault (tag 80) — close an empty LP vault.\r\n *\r\n * Wire: tag(1) = 1 byte.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseLpVault();\r\n * ```\r\n */\r\nexport function encodeCloseLpVault(): Uint8Array {\r\n return encU8(IX_TAG.CloseLpVault);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NFT / B-3 (tags 72/73) — kept from v16\r\n// ============================================================================\r\n\r\n/**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n *\r\n * @param newOwner New owner pubkey.\r\n * @param assetIndex Asset/domain index.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTransferPortfolioOwnership({\r\n * newOwner: newOwnerKey,\r\n * assetIndex: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface TransferPortfolioOwnershipArgs {\r\n newOwner: PublicKey | string;\r\n assetIndex: number;\r\n}\r\n\r\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TransferPortfolioOwnership),\r\n encPubkey(args.newOwner),\r\n encU16(args.assetIndex),\r\n );\r\n}\r\n\r\n/**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n *\r\n * @param nftProgramId Pubkey of the percolator-nft program.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\r\n * ```\r\n */\r\nexport interface SetNftProgramIdArgs {\r\n nftProgramId: PublicKey | string;\r\n}\r\n\r\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetNftProgramId),\r\n encPubkey(args.nftProgramId),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\r\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\r\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\r\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\r\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\r\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\r\n *\r\n * Constraints (from v16_program.rs:10419-10435):\r\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\r\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\r\n * - hybrid_soft_stale_slots > 0\r\n * - invert ∈ {0, 1}\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\r\n * @param oracleLegCount Number of active oracle legs (1–3).\r\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\r\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\r\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\r\n * @param markMinFee Minimum fee charged per mark-price update.\r\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\r\n * @param unitScale Unit scaling factor (u32).\r\n * @param confFilterBps Confidence filter in basis points (u16).\r\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureHybridOracle({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * nowUnixTs: 1700000000n,\r\n * oracleLegCount: 1,\r\n * oracleLegFlags: 0,\r\n * maxStalenessSecs: 60n,\r\n * hybridSoftStaleSlots: 100n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * invert: 0,\r\n * unitScale: 1000000,\r\n * confFilterBps: 200,\r\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\r\n * });\r\n * assert(data.length === 156);\r\n * ```\r\n */\r\nexport interface ConfigureHybridOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n nowUnixTs: bigint | string;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n maxStalenessSecs: bigint | string;\r\n hybridSoftStaleSlots: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\r\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\r\n}\r\n\r\nconst ORACLE_LEG_CAP = 3;\r\n\r\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\r\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\r\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\r\n }\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureHybridOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI64(args.nowUnixTs),\r\n encU8(args.oracleLegCount),\r\n encU8(args.oracleLegFlags),\r\n encU64(args.maxStalenessSecs),\r\n encU64(args.hybridSoftStaleSlots),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n encU8(args.invert),\r\n encU32(args.unitScale),\r\n encU16(args.confFilterBps),\r\n encPubkey(args.oracleLegFeeds[0]),\r\n encPubkey(args.oracleLegFeeds[1]),\r\n encPubkey(args.oracleLegFeeds[2]),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\r\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10558-10563):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - mark_ewma_halflife_slots > 0\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\r\n * @param markMinFee Minimum fee charged per mark-price update (u64).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureEwmaMark({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * initialMarkE6: 50000000000n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * });\r\n * assert(data.length === 35);\r\n * ```\r\n */\r\nexport interface ConfigureEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n}\r\n\r\nfunction requirePositiveU64(value: bigint | string, field: string): void {\r\n const n = typeof value === \"string\" ? BigInt(value) : value;\r\n if (n <= 0n) {\r\n throw new Error(`${field} must be > 0`);\r\n }\r\n}\r\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n );\r\n}\r\n\r\n/**\r\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10771):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10665):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface ConfigureAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n}\r\n\r\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n );\r\n}\r\n\r\n/**\r\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10847):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\r\n// ============================================================================\r\n\r\n/**\r\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\r\n * to initialize a passive LP matcher context.\r\n *\r\n * This is NOT a wrapper instruction. Program = matcher program address.\r\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\r\n *\r\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\r\n * [0] = 2 (opcode: passive-LP init)\r\n * [1] = 0 (reserved)\r\n * [2..10] = 0 (8 bytes reserved)\r\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\r\n * [14..34] = 0 (20 bytes reserved)\r\n * [34..50] = max_fill_abs (u128 LE)\r\n * [50..66] = 0 (16 bytes reserved)\r\n * Total = 66 bytes\r\n *\r\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\r\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\r\n *\r\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\r\n * assert(data.length === 66);\r\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\r\n * ```\r\n */\r\nexport interface MatcherInitPassiveArgs {\r\n maxFillAbs: bigint | string;\r\n}\r\n\r\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\r\n const buf = new Uint8Array(66);\r\n buf[0] = 2;\r\n buf[1] = 0;\r\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\r\n const u32Bytes = encU32(100);\r\n buf.set(u32Bytes, 10);\r\n // [34..50] = max_fill_abs u128 LE\r\n const u128Bytes = encU128(args.maxFillAbs);\r\n buf.set(u128Bytes, 34);\r\n return buf;\r\n}\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\r\n// handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\r\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\r\n//\r\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\r\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\r\n// all — sending this encoded data to it would be rejected or misinterpreted.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee instruction data (tag 84).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\r\n * WrapperConfigV17) to an external token account. Signer-gated on\r\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\r\n * clamped to what's actually available on-chain (engine surplus, vault\r\n * balance) and only the actually-transferred amount is marked withdrawn —\r\n * this never errors solely because the ledger raced ahead of availability.\r\n *\r\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\r\n * currently-available capacity.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\r\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawProtocolFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawProtocolFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetProtocolFeeAuthority instruction data (tag 85).\r\n *\r\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\r\n *\r\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\r\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\r\n * marketauth/insurance_authority/any creator-facing gate) — see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\r\n * a keeper script iterates markets for a mass rotation.\r\n *\r\n * @param newAuthority New protocol-fee-authority pubkey.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\r\n * ```\r\n */\r\nexport interface SetProtocolFeeAuthorityArgs {\r\n newAuthority: PublicKey;\r\n}\r\n\r\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetProtocolFeeAuthority),\r\n encPubkey(args.newAuthority),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\r\n *\r\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\r\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\r\n * three stored shares below, which are bps *of T* and must sum to exactly\r\n * `FEE_SHARE_TOTAL_BPS`.\r\n *\r\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\r\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\r\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\r\n * above its ceiling necessarily drags another leg under its floor.\r\n *\r\n * Defaults are written unconditionally at InitMarket and are never instruction\r\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\r\n * legs correctly from its first trade.\r\n */\r\nexport const FEE_SPLIT = {\r\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\r\n PROTOCOL_FEE_BPS: 2000,\r\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\r\n FEE_SHARE_TOTAL_BPS: 8000,\r\n DEFAULT_CREATOR_SHARE_BPS: 1600,\r\n DEFAULT_LP_SHARE_BPS: 4800,\r\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\r\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\r\n MAX_CREATOR_SHARE_BPS: 3600,\r\n /** LP floor, bps of T (40% of the post-protocol remainder). */\r\n MIN_LP_SHARE_BPS: 3200,\r\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\r\n MIN_INSURANCE_SHARE_BPS: 1200,\r\n} as const;\r\nObject.freeze(FEE_SPLIT);\r\n\r\n/**\r\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\r\n * the split would be accepted on-chain, otherwise a human-readable reason.\r\n *\r\n * Provided so a wizard/UI can reject a bad split before paying for a\r\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\r\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\r\n * floors), so this is a convenience, never the security boundary.\r\n *\r\n * @param args The three candidate shares, in bps of T.\r\n * @returns `null` if valid, else a string describing the first violation.\r\n *\r\n * @example\r\n * ```ts\r\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\r\n * // => null (these are the on-chain defaults)\r\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\r\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\r\n * ```\r\n */\r\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\r\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\r\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\r\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\r\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\r\n }\r\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\r\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\r\n }\r\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\r\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\r\n }\r\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\r\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * UpdateFeeSplit instruction data (tag 86).\r\n *\r\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\r\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\r\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\r\n * {@link validateFeeSplit} to check before sending.\r\n *\r\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\r\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\r\n * top-level transaction and this tag is reachable only via the stake program's\r\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\r\n *\r\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\r\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\r\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Restore the on-chain defaults explicitly.\r\n * const data = encodeUpdateFeeSplit({\r\n * creatorShareBps: 1600,\r\n * lpShareBps: 4800,\r\n * insuranceShareBps: 1600,\r\n * });\r\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateFeeSplitArgs {\r\n creatorShareBps: number;\r\n lpShareBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateFeeSplit),\r\n encU16(args.creatorShareBps),\r\n encU16(args.lpShareBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\r\n *\r\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\r\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\r\n * clamped on-chain to engine-available surplus, and the destination is derived\r\n * rather than passed.\r\n *\r\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\r\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\r\n * PINNED stake program id, so there is nothing for a caller to redirect.\r\n *\r\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\r\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\r\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\r\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\r\n * resolution.\r\n *\r\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\r\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\r\n * stake deployment.\r\n *\r\n * @returns 1-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceReserveToStake();\r\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\r\n * ```\r\n */\r\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\r\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\r\n}\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\r\n *\r\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\r\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\r\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\r\n * wrapper rejects the instruction outright.\r\n *\r\n * Gated on `cfg.marketauth`. The wrapper range-checks against\r\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\r\n * exceeded — the same bound InitMarket applies.\r\n *\r\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\r\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\r\n * (maintenance fee disabled).\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\r\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateMaintenanceFeePerSlotArgs {\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateMaintenanceFeePerSlot(\r\n args: UpdateMaintenanceFeePerSlotArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\r\n encU128(args.maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateTradeFeePolicy instruction data (tag 55).\r\n *\r\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\r\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\r\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\r\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\r\n * (stake tag 28).\r\n *\r\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\r\n * with `read_u128`.\r\n *\r\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\r\n * which left stake tag 28's CPI target unrepresentable from the SDK.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\r\n * ```\r\n */\r\nexport interface UpdateTradeFeePolicyArgs {\r\n tradeFeeBaseBps: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateTradeFeePolicy),\r\n encU64(args.tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * ExpireBackingBucket instruction data (tag 89).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\r\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\r\n * domain: read_u16(&mut rest)? }`) followed by the shared\r\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\r\n *\r\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\r\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\r\n * authority to hold.\r\n *\r\n * ## Why this exists\r\n *\r\n * A realized loss reserves capital as counterparty backing, which opens the\r\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\r\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\r\n * END in all three directions, permanently:\r\n *\r\n * - settling a GAIN against it -> Custom(19) EngineStale\r\n * - reserving a further LOSS -> Custom(21) EngineLockActive\r\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\r\n *\r\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\r\n * no call site that reached the engine's own escape hatch\r\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\r\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\r\n * good. Tag 89 IS that missing call site.\r\n *\r\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\r\n *\r\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\r\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\r\n * once when the bucket opens and is never extended. Seeding a long horizon\r\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\r\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\r\n * incident-response tool: a keeper should scan live markets for domains whose\r\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\r\n * nobody cranks it, the first lapse silently bricks the domain and the failure\r\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\r\n * settlement.\r\n *\r\n * ## Safety\r\n *\r\n * Permissionless is not an authority hole. The engine refuses the transition\r\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\r\n * is read from the runtime `Clock` (via\r\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\r\n * — so no caller can force an early forfeiture. Moves no tokens.\r\n *\r\n * Expiry forfeits the lapsed principal to the junior pool. That is the\r\n * engine's documented expiry semantics, not a haircut invented by this\r\n * instruction; the alternative is the account never settling at all.\r\n *\r\n * ## Failure modes\r\n *\r\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\r\n * resolved/wound-down path reaches the transition through the engine's own\r\n * resolved-close sweep, so re-entering it from outside is refused.\r\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\r\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\r\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\r\n * speculatively on a healthy domain is safe (it just reverts).\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short), u16. Must be\r\n * `< 2 * max_market_slots`.\r\n * @returns 3-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\r\n * const data = encodeExpireBackingBucket({ domain: 0 });\r\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\r\n * // beyond the fee payer.\r\n * ```\r\n */\r\nexport interface ExpireBackingBucketArgs {\r\n domain: number;\r\n}\r\n\r\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ExpireBackingBucket),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n//\r\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\r\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\r\n// 576-byte config — see solana/slab.ts).\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee instruction data (tag 90).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\r\n * percolator-prog `src/v16_program.rs`:\r\n *\r\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\r\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\r\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\r\n * -> total length is EXACTLY 17; any trailing byte is rejected\r\n * encode arm: out.push(90); push_u128(&mut out, amount)\r\n *\r\n * Pays the market creator's accrued trade-fee share out of the market vault to\r\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\r\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\r\n * backstop): before this change the creator leg was credited INTO the backstop,\r\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\r\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\r\n * counter.\r\n *\r\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\r\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\r\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\r\n * `parseWrapperConfigV17` and pass that exact value.\r\n *\r\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\r\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\r\n * the whole instruction fails closed (EngineLockActive); retry with less.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\r\n * `cfg.marketauth`), so claiming still works on a staked market where\r\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\r\n *\r\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\r\n * u64, so anything above u64::MAX is an over-claim).\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketAccount.data);\r\n * // Drain the full claimable balance:\r\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\r\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawCreatorFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCreatorFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n","import {\r\n PublicKey,\r\n AccountMeta,\r\n SYSVAR_CLOCK_PUBKEY,\r\n SYSVAR_RENT_PUBKEY,\r\n SystemProgram,\r\n} from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Account spec for building instruction account metas.\r\n * Each instruction has a fixed ordering that matches the Rust processor.\r\n */\r\nexport interface AccountSpec {\r\n name: string;\r\n signer: boolean;\r\n writable: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// ACCOUNT ORDERINGS - Single source of truth\r\n// ============================================================================\r\n\r\n/**\r\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\r\n */\r\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"mint\", signer: false, writable: false },\r\n { name: \"vault\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"dummyAta\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * InitPortfolio (tag 2): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\r\n * [0] owner signer, writable (portfolio owner; pays for alloc)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n *\r\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\r\n * InitPortfolio does not transfer collateral and does not read the clock.\r\n */\r\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * InitLP: 6 accounts\r\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\r\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\r\n * [0] user signer, writable (LP owner; pays fee)\r\n * [1] slab writable\r\n * [2] userAta writable (collateral source for fee)\r\n * [3] vault writable (collateral destination)\r\n * [4] tokenProgram read-only\r\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\r\n */\r\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Deposit (tag 3): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] sourceToken writable (owner's collateral ATA)\r\n * [4] vaultToken writable (program vault token account)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\r\n */\r\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Withdraw (tag 4): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] destToken writable (owner's collateral ATA — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs token CPI)\r\n * [6] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\r\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\r\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\r\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\r\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\r\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\r\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\r\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\r\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\r\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\r\n */\r\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\r\n { name: \"nftRegistry\", signer: false, writable: false },\r\n { name: \"positionNft\", signer: false, writable: false },\r\n { name: \"signerNftAta\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\r\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\r\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\r\n */\r\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\r\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\r\n}\r\n\r\n/**\r\n * KeeperCrank: 4 accounts\r\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\r\n */\r\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\r\n * [0] owner signer, writable (keeper key; receives liquidation reward)\r\n * [1] market writable (the market-group slab)\r\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\r\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\r\n *\r\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\r\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\r\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\r\n * the same program and have a different key from accounts[2].\r\n *\r\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\r\n * including oracle tail and optional keeper portfolio.\r\n */\r\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * RestartAssetOracle (tag 69): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\r\n * [0] authority signer (asset_admin for the target asset_index)\r\n * [1] market writable (the market-group slab)\r\n *\r\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\r\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\r\n * Permissionless in the sense that any holder of asset_admin can call it.\r\n */\r\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n\r\n/**\r\n * TradeNoCpi (tag 9): 5 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\r\n * [0] signerA signer, writable (party A — portfolio owner)\r\n * [1] signerB signer, writable (party B — portfolio owner)\r\n * [2] market writable (market-group slab; program-owned)\r\n * [3] accountA writable (portfolio A; program-owned)\r\n * [4] accountB writable (portfolio B; program-owned)\r\n *\r\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\r\n * signerB replaces lp (both portfolios must have live owner signers).\r\n */\r\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: true },\r\n { name: \"signerB\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LiquidateAtOracle: 4 accounts\r\n * Note: account[0] is unused but must be present\r\n */\r\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\r\n { name: \"unused\", signer: false, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClosePortfolio (tag 8): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\r\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\r\n *\r\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\r\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\r\n * portfolio and closes the account back to the market slab.\r\n */\r\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\r\n * [0] signer signer, writable (insurance authority for asset 0)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\r\n *\r\n * v12 stale accounts removed: clock sysvar (was at [5]).\r\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\r\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\r\n * per-authority deposit principals; omit for simple vault top-ups.\r\n */\r\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\r\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\r\n * omit for a simple top-up with no ledger tracking)\r\n *\r\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\r\n */\r\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority-OWNED token account — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\r\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\r\n * so it stays callable by the creator wallet after the\r\n * launch flow rotates marketauth to the stake-pool PDA)\r\n * [1] market writable (market-group slab; program-owned)\r\n */\r\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\r\n * unlike tag 50 where it is an optional tail)\r\n * [3] destToken writable (authority-OWNED token account — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [6] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\r\n * [0] signerA signer (party A — portfolio owner)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] accountA writable (portfolio A; program-owned)\r\n * [3] accountB writable (portfolio B; program-owned)\r\n * [4] matcherProg read-only, executable (matcher program)\r\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\r\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\r\n * [7+] tail additional accounts forwarded to matcher CPI\r\n *\r\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\r\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\r\n * market replaces slab name.\r\n */\r\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetRiskThreshold: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAdmin: 2 accounts\r\n */\r\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * AcceptAdmin: 2 accounts (tag 82)\r\n * Second half of two-step admin transfer. The proposed new admin must sign to\r\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\r\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\r\n * [1] slab writable\r\n */\r\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\r\n { name: \"pendingAdmin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CloseSlab: 6 accounts\r\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\r\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\r\n * [0] dest signer, writable (receives rent + drained vault tokens)\r\n * [1] slab writable\r\n * [2] vault writable (token account — drained)\r\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\r\n * [4] destAta writable (dest's token ATA receiving drained tokens)\r\n * [5] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"destAta\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\r\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\r\n * 3-account form: [admin(s+w), slab(w), clock].\r\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\r\n * needs to re-read price during config commit). Default to the 3-account form;\r\n * callers that need oracle re-reads should append the oracle account themselves.\r\n */\r\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetMaintenanceFee: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetOraclePriceCap: 3 accounts.\r\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\r\n * Layout: [admin(s+w), slab(w), clock].\r\n */\r\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ResolveMarket (tag 19): 2 accounts.\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\r\n * `handle_resolve_market` at src/v16_program.rs:12269:\r\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\r\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\r\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\r\n * clock account, and never touches an oracle account at all.\r\n *\r\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\r\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\r\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\r\n * also admin-gated, market-level, no token movement — which is\r\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\r\n * when the program does not require it only widens the account's write lock.\r\n */\r\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\r\n * [0] authority signer, writable (insurance authority)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority's collateral ATA — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\r\n *\r\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\r\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\r\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\r\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\r\n * the handler does a same-instruction accrue_market_to against the fresh\r\n * oracle price to prevent withdrawals against overstated insurance.\r\n * On resolved markets the oracle is frozen — 7 accounts suffice.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"authorityAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\r\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UnpauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\r\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\r\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\r\n// (set_insurance_withdraw_policy), 6876 (update_authority).\r\n// ============================================================================\r\n\r\n/**\r\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10470.\r\n */\r\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SettleAccount (tag 26): 3 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10503.\r\n */\r\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\r\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\r\n * Owner only. No token movement (internal PnL-bucket conversion within the\r\n * same portfolio).\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\r\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\r\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\r\n * at src/v16_program.rs:17469, which reads:\r\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\r\n * [1] market writable — `expect_writable` + `expect_owner`\r\n * [2] portfolio writable — `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\r\n * is no clock account (the handler needs no slot) and no oracle account.\r\n *\r\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\r\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\r\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\r\n * portfolio rent — this instruction moves no lamports at all.\r\n *\r\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\r\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\r\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\r\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\r\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\r\n */\r\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\r\n * Wrapper: src/percolator.rs:9990.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\r\n * Wrapper: src/percolator.rs:6876.\r\n *\r\n * Both the current authority and the new authority must sign. For burn\r\n * (`new_pubkey == default()`) the new account is still passed but does\r\n * not need to sign per wrapper L7036 region.\r\n */\r\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"currentAuthority\", signer: true, writable: false },\r\n { name: \"newAuthority\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// ACCOUNT META BUILDERS\r\n// ============================================================================\r\n\r\n/**\r\n * Build AccountMeta array from spec and provided pubkeys.\r\n *\r\n * Accepts either:\r\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\r\n * - `Record` — named map keyed by account `name` (preferred form)\r\n *\r\n * Named-map form resolves accounts by spec name so callers don't have to\r\n * remember the positional order, and errors clearly on missing names.\r\n */\r\nexport function buildAccountMetas(\r\n spec: readonly AccountSpec[],\r\n keys: PublicKey[] | Record\r\n): AccountMeta[] {\r\n let keysArray: PublicKey[];\r\n\r\n if (Array.isArray(keys)) {\r\n keysArray = keys;\r\n } else {\r\n // Named map: resolve by spec name\r\n keysArray = spec.map((s) => {\r\n const key = (keys as Record)[s.name];\r\n if (!key) {\r\n throw new Error(\r\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\r\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\r\n );\r\n }\r\n return key;\r\n });\r\n }\r\n\r\n if (keysArray.length !== spec.length) {\r\n throw new Error(\r\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\r\n );\r\n }\r\n return spec.map((s, i) => ({\r\n pubkey: keysArray[i],\r\n isSigner: s.signer,\r\n isWritable: s.writable,\r\n }));\r\n}\r\n\r\n/**\r\n * CreateInsuranceMint: 9 accounts\r\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\r\n */\r\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"collateralMint\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"payer\", signer: true, writable: true },\r\n] as const;\r\n\r\n/**\r\n * DepositInsuranceLP: 8 accounts\r\n * Deposit collateral into insurance fund, receive LP tokens.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"depositorAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLP: 8 accounts\r\n * Burn LP tokens and withdraw proportional share of insurance fund.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\r\n *\r\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\r\n *\r\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\r\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\r\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\r\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\r\n *\r\n * Accounts:\r\n * [0] withdrawer signer, read-only\r\n * [1] slab writable\r\n * [2] withdrawerAta writable (collateral destination)\r\n * [3] vault writable (collateral source)\r\n * [4] tokenProgram read-only\r\n * [5] lpVaultMint writable (LP tokens burned from here)\r\n * [6] withdrawerLpAta writable (LP tokens source)\r\n * [7] vaultAuthority read-only (PDA that signs token transfers)\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\r\n */\r\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"creatorLockPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * FundMarketInsurance: 5 accounts (PERC-306)\r\n * Fund per-market isolated insurance balance.\r\n */\r\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceIsolation: 2 accounts (PERC-306)\r\n * Set max % of global fund this market can access.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal: 5 accounts (PERC-309)\r\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\r\n */\r\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"lpVaultState\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\r\n * Burns LP tokens and releases one epoch tranche of SOL.\r\n */\r\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\r\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\r\n */\r\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\r\n * Permissionless — surgically close/reduce the most profitable position\r\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\r\n * pass additional oracle accounts at accounts[4..].\r\n */\r\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs: 2 accounts (tag 51)\r\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\r\n */\r\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ReclaimSlabRent: 2 accounts (tag 52)\r\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\r\n */\r\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: true, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// AuditCrank (tag 53) — Permissionless invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank: 1 account (tag 53)\r\n * Permissionless. Verifies conservation invariants; pauses market on violation.\r\n */\r\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase: 1 account\r\n * Permissionless — no signer required beyond fee payer.\r\n */\r\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dexPool\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * CreateLpVault (tag 74): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\r\n * [0] admin signer, writable (marketauth — pays for PDA creation)\r\n * [1] market read-only (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\r\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\r\n * [4] systemProgram read-only (required for create_account CPI)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\r\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\r\n */\r\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositToLpVault (tag 75): 10 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\r\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] lpMint writable (LP share mint PDA)\r\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\r\n * [5] sourceToken writable (depositor's collateral ATA — source)\r\n * [6] vaultToken writable (program vault token account — destination)\r\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\r\n * [8] tokenProgram read-only\r\n * [9] systemProgram read-only (required for ledger create_account CPI)\r\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n *\r\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\r\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\r\n * and mints the depositor free shares at existing holders' expense. `ledger` at\r\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\r\n * which of the two actually receives the backing.\r\n *\r\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\r\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\r\n * ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\r\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n * [5] systemProgram read-only (required to create a missing target ledger)\r\n *\r\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\r\n * land in, and that pot's ledger is created on first use. Once deposits can be\r\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\r\n * so cranker had to become writable and the system program is now required.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\r\n *\r\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\r\n * carrying ledger principal in lockstep. No tokens move.\r\n *\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\r\n * destination ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry read-only (LpVaultRegistry PDA)\r\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\r\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\r\n * [5] systemProgram read-only\r\n */\r\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: false },\r\n { name: \"fromLedger\", signer: false, writable: true },\r\n { name: \"toLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"challenger\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"attestation\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8110: SetOiImbalanceHardBlock\r\n// ============================================================================\r\n\r\n/**\r\n * SetOiImbalanceHardBlock: 2 accounts\r\n * Sets the OI imbalance hard-block threshold (admin only)\r\n */\r\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-608: Position NFT Instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft: 10 accounts\r\n * Creates a Token-2022 position NFT for an open position.\r\n */\r\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TransferPositionOwnership: 8 accounts\r\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\r\n */\r\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\r\n { name: \"currentOwner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"currentOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwner\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * BurnPositionNft: 7 accounts\r\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\r\n */\r\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetPendingSettlement: 3 accounts\r\n * Keeper/admin sets pending_settlement flag before funding transfer.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ClearPendingSettlement: 3 accounts\r\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"nftProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8111: SetWalletCap\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap: 2 accounts\r\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\r\n */\r\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-SetDexPool: SetDexPool (tag 74)\r\n// ============================================================================\r\n\r\n/**\r\n * SetDexPool: 3 accounts\r\n * Admin pins the approved DEX pool address for a HYPERP market.\r\n * After this call, UpdateHyperpMark rejects any pool that does not match.\r\n */\r\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"poolAccount\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// InitMatcherCtx (tag 83) — v17 wire\r\n//\r\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\r\n// 83. The protocol-fee instructions below were renumbered to 84/85\r\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\r\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\r\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\r\n * [0] lpOwner signer (LP portfolio owner wallet)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\r\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\r\n * [4] matcherProg read-only, executable (the external matcher program)\r\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\r\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\r\n * calling the matcher CPI.\r\n *\r\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\r\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\r\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\r\n */\r\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\r\n *\r\n * Fixed accounts:\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned market account)\r\n *\r\n * Dynamic accounts [2..2+oracle_leg_count]:\r\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\r\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\r\n *\r\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\r\n] as const;\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\r\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushEwmaMark (tag 36): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\r\n */\r\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushAuthMark (tag 63): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\r\n */\r\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK B — SetMatcherConfig account spec (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\r\n * 6 accounts when enabling (enabled=1).\r\n *\r\n * [0] lpOwner signer (portfolio owner)\r\n * [1] market read-only (program-owned; owner-check only)\r\n * [2] lpPortfolio writable (program-owned portfolio)\r\n * [3] matcherProg read-only, executable (required when enabled=1 only)\r\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\r\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\r\n *\r\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\r\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\r\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\r\n */\r\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: true },\r\n // When enabled=1, also pass:\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee (tag 84): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\r\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\r\n * in the instruction data means \"withdraw all currently-available capacity\".\r\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\r\n * domain budgets; the protocol's claim is a separate, non-domain balance).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\r\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\r\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\r\n * seeds [program_id])\r\n * [2] market writable (program-owned market-group slab)\r\n *\r\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\r\n * authority — NOT marketauth, NOT insurance_authority, NOT any\r\n * creator-facing gate. No global fan-out: call once per market.\r\n */\r\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"upgradeAuthority\", signer: true, writable: false },\r\n { name: \"programData\", signer: false, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateFeeSplit (tag 86): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\r\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors the neighbouring marketauth-gated single-field setters\r\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\r\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\r\n *\r\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\r\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\r\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\r\n */\r\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_withdraw_insurance_reserve_to_stake):\r\n * [0] cranker signer (permissionless — any signer, pays fees only)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\r\n * wrapper's PINNED stake program id; its owner is\r\n * asserted BEFORE any byte is read — the forgery gate)\r\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\r\n * [4] vaultToken writable (this market's collateral vault token acct)\r\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\r\n * [6] tokenProgram read-only\r\n *\r\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\r\n * destination; percolator-stake's own AccrueFees is what later credits it.\r\n *\r\n * Failure codes are deliberately distinct so a keeper can tell the cases\r\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\r\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\r\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\r\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"stakePool\", signer: false, writable: false },\r\n { name: \"stakeVault\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\r\n * [0] admin signer (must match cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * ⚠ The instruction payload is a u128, not a u64. See\r\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\r\n */\r\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\r\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\r\n * cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\r\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\r\n * than by StakeInitPool; proxy is stake tag 28.\r\n *\r\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\r\n * the authority normally also being the fee payer. The program itself only\r\n * calls `expect_signer(authority)` — it never writes to this account.\r\n */\r\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\r\n * [0] market writable (program-owned market-group slab)\r\n *\r\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\r\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\r\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\r\n * instruction moves no tokens. The transaction still needs a fee payer, but\r\n * that signer is not an account of this instruction and is not checked against\r\n * anything.\r\n *\r\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\r\n * only by an authority that may be a cold key or a stake-pool PDA. The\r\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\r\n * against the runtime `Clock`), not an authority check. See\r\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\r\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\r\n * Custom(19) bucket not `Fresh`-and-lapsed.\r\n */\r\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee (tag 90): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\r\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\r\n * only the authority the program checks [0] against differs:\r\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account, owned by [0])\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\r\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\r\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\r\n * reflects the authority normally also being the transaction fee payer; the\r\n * program itself only calls expect_signer on it.\r\n *\r\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\r\n * does NOT accept marketauth as an alternate the way\r\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\r\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\r\n * pool claim the creator's revenue. It also means claiming keeps working after\r\n * StakeInitPool, since staking never rotates insurance_operator.\r\n *\r\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\r\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\r\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\r\n * from the loss backstop, so backstop gating does not apply).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\r\n// ============================================================================\r\n\r\nexport const WELL_KNOWN = {\r\n tokenProgram: TOKEN_PROGRAM_ID,\r\n clock: SYSVAR_CLOCK_PUBKEY,\r\n rent: SYSVAR_RENT_PUBKEY,\r\n systemProgram: SystemProgram.programId,\r\n} as const;\r\n","/**\r\n * Percolator v17 program error definitions.\r\n *\r\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\r\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\r\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\r\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\r\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\r\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\r\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\r\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\r\n *\r\n * Ordinals 0-61 read directly off the PercolatorError enum in\r\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\r\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\r\n * tentative\" TODO here is resolved.\r\n *\r\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\r\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Errors 0-29 have completely different names and semantics from v12.\r\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\r\n * - Errors 42-46 are NFT/B-3 (new in v17).\r\n * - v12.x errors 28-65 are entirely removed.\r\n */\r\nexport interface ErrorInfo {\r\n name: string;\r\n hint: string;\r\n}\r\n\r\nexport const PERCOLATOR_ERRORS: Record = {\r\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\r\n 0: {\r\n name: \"InvalidMagic\",\r\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\r\n },\r\n 1: {\r\n name: \"InvalidVersion\",\r\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\r\n },\r\n 2: {\r\n name: \"AlreadyInitialized\",\r\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\r\n },\r\n 3: {\r\n name: \"NotInitialized\",\r\n hint: \"Account is not initialized. Run InitMarket first.\",\r\n },\r\n 4: {\r\n name: \"InvalidAccountKind\",\r\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\r\n },\r\n 5: {\r\n name: \"InvalidAccountLen\",\r\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\r\n },\r\n 6: {\r\n name: \"ExpectedSigner\",\r\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\r\n },\r\n 7: {\r\n name: \"ExpectedWritable\",\r\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\r\n },\r\n 8: {\r\n name: \"Unauthorized\",\r\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\r\n },\r\n 9: {\r\n name: \"InvalidInstruction\",\r\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\r\n },\r\n 10: {\r\n name: \"InvalidMint\",\r\n hint: \"Token mint does not match the market's collateral mint.\",\r\n },\r\n 11: {\r\n name: \"InvalidTokenAccount\",\r\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\r\n },\r\n 12: {\r\n name: \"InvalidVaultAccount\",\r\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\r\n },\r\n 13: {\r\n name: \"InvalidTokenProgram\",\r\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\r\n },\r\n 14: {\r\n name: \"EngineInvalidConfig\",\r\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\r\n },\r\n 15: {\r\n name: \"EngineArithmeticOverflow\",\r\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\r\n },\r\n 16: {\r\n name: \"EngineProvenanceMismatch\",\r\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\r\n },\r\n 17: {\r\n name: \"EngineHiddenLeg\",\r\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\r\n },\r\n 18: {\r\n name: \"EngineInvalidLeg\",\r\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\r\n },\r\n 19: {\r\n name: \"EngineStale\",\r\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\r\n },\r\n 20: {\r\n name: \"EngineBStale\",\r\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\r\n },\r\n 21: {\r\n name: \"EngineLockActive\",\r\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\r\n },\r\n 22: {\r\n name: \"EngineNonProgress\",\r\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\r\n },\r\n 23: {\r\n name: \"EngineRecoveryRequired\",\r\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\r\n },\r\n 24: {\r\n name: \"EngineCounterOverflow\",\r\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\r\n },\r\n 25: {\r\n name: \"EngineCounterUnderflow\",\r\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\r\n },\r\n 26: {\r\n name: \"OracleInvalid\",\r\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\r\n },\r\n 27: {\r\n name: \"OracleStale\",\r\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\r\n },\r\n 28: {\r\n name: \"OracleConfTooWide\",\r\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\r\n },\r\n 29: {\r\n name: \"InvalidOracleKey\",\r\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\r\n },\r\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\r\n 30: {\r\n name: \"LpVaultAlreadyExists\",\r\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\r\n },\r\n 31: {\r\n name: \"LpVaultNotFound\",\r\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\r\n },\r\n 32: {\r\n name: \"LpVaultPaused\",\r\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\r\n },\r\n 33: {\r\n name: \"LpVaultSharesOutstanding\",\r\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\r\n },\r\n 34: {\r\n name: \"LpVaultZeroAmount\",\r\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\r\n },\r\n 35: {\r\n name: \"LpVaultInsufficientShares\",\r\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\r\n },\r\n 36: {\r\n name: \"LpVaultCooldownActive\",\r\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\r\n },\r\n 37: {\r\n name: \"LpVaultOiReservationViolated\",\r\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\r\n },\r\n 38: {\r\n name: \"LpVaultNoFeesToCrank\",\r\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\r\n },\r\n 39: {\r\n name: \"LpVaultSupplyMismatch\",\r\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\r\n },\r\n 40: {\r\n name: \"LpVaultAuthorityMismatch\",\r\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\r\n },\r\n 41: {\r\n name: \"LpVaultZeroSharesMinted\",\r\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\r\n },\r\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\r\n 42: {\r\n name: \"NftRegistryNotFound\",\r\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\r\n },\r\n 43: {\r\n name: \"NftPortfolioNotTransferable\",\r\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\r\n },\r\n 44: {\r\n name: \"NftTransferSelfOrZero\",\r\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\r\n },\r\n 45: {\r\n name: \"NftInvalidMintAuthority\",\r\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\r\n },\r\n 46: {\r\n name: \"NftPortfolioProvenance\",\r\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\r\n },\r\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\r\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\r\n 47: {\r\n name: \"InsuranceWithdrawCooldownActive\",\r\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\r\n },\r\n 48: {\r\n name: \"InsuranceWithdrawCeilingExceeded\",\r\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\r\n },\r\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\r\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\r\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\r\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\r\n // initial-margin failure, previously collapsed into the opaque\r\n // EngineInvalidConfig=14.\r\n 49: {\r\n name: \"EngineInsufficientInitialMargin\",\r\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\r\n },\r\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\r\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\r\n 50: {\r\n name: \"LpVaultDepositBelowMinimumLiquidity\",\r\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\r\n },\r\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\r\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\r\n // a3cb4390).\r\n //\r\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\r\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\r\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\r\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\r\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\r\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\r\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\r\n // EXACTLY and with no tolerance, against the bps floors below.\r\n 51: {\r\n name: \"FeeSplitFloorViolation\",\r\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\r\n },\r\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variants appended after\r\n // FeeSplitFloorViolation=51 on percolator-prog\r\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\r\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\r\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\r\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\r\n 52: {\r\n name: \"FeeSplitSumInvalid\",\r\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\r\n },\r\n 53: {\r\n name: \"NoInsuranceReserveToClaim\",\r\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\r\n },\r\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\r\n // Source: v16_program.rs, same branch. These seven previously ALL returned\r\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\r\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\r\n // destination-resolution now has its own code.\r\n //\r\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\r\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\r\n // removed. That variant existed only on an unmerged branch and was NEVER\r\n // deployed, so no on-chain consumer has ever observed the old meaning.\r\n 54: {\r\n name: \"StakePoolNotBound\",\r\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\r\n },\r\n 55: {\r\n name: \"StakePoolOwnerMismatch\",\r\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\r\n },\r\n 56: {\r\n name: \"StakePoolAuthorityMismatch\",\r\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\r\n },\r\n 57: {\r\n name: \"StakePoolMarketMismatch\",\r\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\r\n },\r\n 58: {\r\n name: \"StakePoolWrapperMismatch\",\r\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\r\n },\r\n 59: {\r\n name: \"StakePoolModeMismatch\",\r\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\r\n },\r\n 60: {\r\n name: \"StakeProgramNotPinned\",\r\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\r\n },\r\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\r\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n 61: {\r\n name: \"AssetSlotAlreadyConfigured\",\r\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\r\n },\r\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\r\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\r\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\r\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\r\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\r\n // wrapper this code is unreachable.\r\n 62: {\r\n name: \"CreatorFeeOverClaim\",\r\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\r\n },\r\n\r\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\r\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\r\n // slot 490057417, verified byte-identical.\r\n 63: {\r\n name: \"LpVaultBackingBucketNotEmpty\",\r\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\r\n },\r\n};\r\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\r\nObject.freeze(PERCOLATOR_ERRORS);\r\n\r\n/**\r\n * Decode a custom program error code to its info.\r\n *\r\n * @param code Custom error code from `custom program error: 0x`.\r\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\r\n */\r\nexport function decodeError(code: number): ErrorInfo | undefined {\r\n return PERCOLATOR_ERRORS[code];\r\n}\r\n\r\n/**\r\n * Get error name from code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\r\n */\r\nexport function getErrorName(code: number): string {\r\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\r\n}\r\n\r\n/**\r\n * Get actionable hint for error code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Actionable hint string, or undefined if not recognized.\r\n */\r\nexport function getErrorHint(code: number): string | undefined {\r\n return PERCOLATOR_ERRORS[code]?.hint;\r\n}\r\n\r\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\r\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\r\n\r\n/**\r\n * Parse a custom program error from transaction logs.\r\n *\r\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\r\n * Returns null if no custom error is found.\r\n *\r\n * @param logs Array of transaction log strings from the RPC response.\r\n * @returns Parsed error with code, name, and hint — or null if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\r\n * if (err) console.error(`${err.name}: ${err.hint}`);\r\n * ```\r\n */\r\nexport function parseErrorFromLogs(logs: string[]): {\r\n code: number;\r\n name: string;\r\n hint?: string;\r\n} | null {\r\n if (!Array.isArray(logs)) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\r\n \"i\",\r\n );\r\n for (const log of logs) {\r\n if (typeof log !== \"string\") {\r\n continue;\r\n }\r\n const match = log.match(re);\r\n if (match) {\r\n const code = parseInt(match[1], 16);\r\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\r\n continue;\r\n }\r\n const info = decodeError(code);\r\n return {\r\n code,\r\n name: info?.name ?? `Unknown(${code})`,\r\n hint: info?.hint,\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Standalone percolator-nft program SDK module.\r\n *\r\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\r\n * separate from the main Percolator program. It handles:\r\n * - MintPositionNft (tag 0)\r\n * - BurnPositionNft (tag 1)\r\n * - SettleFunding (tag 2)\r\n * - GetPositionValue (tag 3)\r\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\r\n * - EmergencyBurn (tag 5)\r\n * - RepairExtraMetas (tag 6)\r\n * - ReconcileBurnedNft (tag 7)\r\n *\r\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\r\n * PositionNft state : [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n * Mint authority : [\"mint_authority\"]\r\n *\r\n * NOTE: the PositionNft seed is keyed on `market_id`, NOT `asset_index` — see\r\n * #108 and `deriveNftPda` below. This header claimed `asset_index_u16_LE` until\r\n * 2026-08-31; the code was always correct.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\r\nimport { safeEnv } from \"../config/program-ids.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Program ID\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Allowlist of known NFT program addresses. */\r\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\r\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\r\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\r\n]);\r\n\r\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\r\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\r\n throw new Error(\r\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\r\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\r\n `Pass the programId argument explicitly to bypass env resolution.`,\r\n );\r\n}\r\n\r\n/**\r\n * The standalone percolator-nft program (TransferHook + mint authority).\r\n *\r\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\r\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\r\n * address while every other id in the SDK is devnet, so any consumer importing it built\r\n * transactions against a program that does not exist on devnet and failed late with\r\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\r\n * constant to work around it.\r\n */\r\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\r\n\r\nexport function getNftProgramId(): PublicKey {\r\n return NFT_PROGRAM_ID;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const NFT_IX_TAG = {\r\n MintPositionNft: 0,\r\n BurnPositionNft: 1,\r\n SettleFunding: 2,\r\n GetPositionValue: 3,\r\n ExecuteTransferHook: 4,\r\n EmergencyBurn: 5,\r\n RepairExtraMetas: 6,\r\n ReconcileBurnedNft: 7,\r\n} as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction encoders\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\r\nexport function encodeNftMint(assetIndex: number): Uint8Array {\r\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\r\n const buf = new Uint8Array(3);\r\n buf[0] = NFT_IX_TAG.MintPositionNft;\r\n buf.set(assetIndexBuf, 1);\r\n return buf;\r\n}\r\n\r\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\r\nexport function encodeNftBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\r\n}\r\n\r\n/** Encode SettleFunding (tag 2). Data: tag(1). */\r\nexport function encodeNftSettleFunding(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\r\n}\r\n\r\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\r\nexport function encodeNftEmergencyBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\r\n}\r\n\r\n/**\r\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\r\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\r\n * released) back to the recorded last holder, then closes the PositionNft PDA.\r\n */\r\nexport function encodeNftReconcile(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account meta templates\r\n// ---------------------------------------------------------------------------\r\n\r\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\r\n\r\n/**\r\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\r\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\r\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\r\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\r\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\r\n * `isSigner: undefined` and `isWritable: undefined` for every account\r\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\r\n * both to falsy, so EVERY account in the built instruction ends up\r\n * non-signer/read-only. The NFT program's own writable/signer checks then\r\n * reject the transaction (confirmed live against the deployed NFT program:\r\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\r\n * CPI — matching its `if !nft_pda.is_writable { return\r\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\r\n *\r\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\r\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\r\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\r\n * these arrays and working — the only prior working reference\r\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\r\n * bypassing the mismatch entirely.\r\n */\r\nexport function buildNftAccountMetas(\r\n spec: readonly AccountMeta[],\r\n keys: readonly PublicKey[],\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n if (keys.length !== spec.length) {\r\n throw new Error(\r\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\r\n );\r\n }\r\n return spec.map((code, i) => ({\r\n pubkey: keys[i],\r\n isSigner: code === \"s\" || code === \"sw\",\r\n isWritable: code === \"w\" || code === \"sw\",\r\n }));\r\n}\r\n\r\n/**\r\n * Account metas for MintPositionNft (tag 0). 12 accounts.\r\n *\r\n * 0. [signer, writable] payer / position owner\r\n * 1. [writable] PositionNft PDA (created)\r\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\r\n * 3. [writable] Owner's NFT ATA (created)\r\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [] Associated token account program\r\n * 8. [] System program\r\n * 9. [writable] ExtraAccountMetaList PDA\r\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\r\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\r\n *\r\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\r\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\r\n * writable and #10/#11 are required.\r\n */\r\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\r\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint,\r\n * PositionNft PDA and ExtraAccountMetaList rent)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint (supply → 0)\r\n * 3. [writable] Holder's NFT ATA (closed)\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n *\r\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\r\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\r\n */\r\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint\r\n * 3. [writable] Holder's NFT ATA\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n */\r\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for ReconcileBurnedNft (tag 7, #138). 9 accounts. Permissionless.\r\n *\r\n * 0. [writable] PositionNft PDA (closed)\r\n * 1. [writable] NFT mint (Token-2022 — supply must be 0; closed, #182)\r\n * 2. [writable] Portfolio account (escrow released to the last holder)\r\n * 3. [] Mint authority PDA (unwrap + mint-close CPI signer)\r\n * 4. [] Per-market NftRegistry PDA\r\n * 5. [] Percolator wrapper program (unwrap CPI target)\r\n * 6. [writable] Recorded last-holder wallet (escrow + all rent recipient)\r\n * 7. [writable] ExtraAccountMetaList PDA (closed, #182)\r\n * 8. [] Token-2022 program (mint-close CPI target, #182)\r\n *\r\n * dcccrypto/percolator-nft#182: Reconcile previously abandoned the NFT mint and\r\n * the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable,\r\n * because it closes the PositionNft PDA and every path that could later reclaim\r\n * those two requires it to still be live. Accounts 7 and 8 are REQUIRED rather\r\n * than optional: Reconcile is permissionless, irreversible and runs at most\r\n * once, so an opt-in could be defeated permanently by whoever called first.\r\n *\r\n * Forward-compatible with the currently deployed programs: their handler pulls\r\n * seven accounts off an iterator and never checks `accounts.len()`, so the two\r\n * extra metas are simply unread, and it never checks `nft_mint.is_writable`.\r\n * A nine-account call therefore behaves identically on both, which is why this\r\n * can ship ahead of the program change rather than behind it.\r\n */\r\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\r\n \"w\", \"w\", \"w\", \"r\", \"r\", \"r\", \"w\", \"w\", \"r\",\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// PDA derivation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\nfunction u16Buf(value: number, label: string): Uint8Array {\r\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\r\n throw new Error(`${label} must be a u16`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, true);\r\n return buf;\r\n}\r\n\r\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\r\n const v = typeof value === \"bigint\" ? value : BigInt(value);\r\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\r\n throw new Error(`${label} must be a u64`);\r\n }\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, v, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive the PositionNft state PDA.\r\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n *\r\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\r\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\r\n * engine reuses across close/re-open of the same asset and which therefore\r\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\r\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\r\n * NFT's stored `marketIdAtMint` for any later op.\r\n */\r\nexport function deriveNftPda(\r\n portfolioAccount: PublicKey,\r\n marketId: bigint | number,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\r\n programId,\r\n );\r\n}\r\n\r\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\r\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\r\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\r\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\r\n\r\n/**\r\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\r\n */\r\nexport function deriveNftMint(\r\n _portfolioAccount: PublicKey,\r\n _assetIndex: number,\r\n _programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\r\n}\r\n\r\n/**\r\n * Derive the program-wide mint authority PDA.\r\n * Seeds: [\"mint_authority\"]\r\n */\r\nexport function deriveMintAuthority(\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"mint_authority\")],\r\n programId,\r\n );\r\n}\r\n\r\n/**\r\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\r\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\r\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\r\n * close it and refund its rent to the holder.\r\n */\r\nexport function deriveExtraAccountMetas(\r\n nftMint: PublicKey,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\r\n programId,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account parser\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\r\n *\r\n * [0..8] magic u64 (\"PERCNFT\\0\")\r\n * [8] version u8\r\n * [9] bump u8\r\n * [10..42] portfolio_account [u8; 32]\r\n * [42..74] nft_mint [u8; 32]\r\n * [74..78] asset_index u32 LE\r\n * [78] side_at_mint u8\r\n * [79..95] basis_pos_q_at_mint i128\r\n * [95..111] f_snap_at_mint i128\r\n * [111..119] market_id_at_mint u64\r\n * [119..127] epoch_snap_at_mint u64\r\n * [127..159] position_owner_at_mint [u8; 32]\r\n * [159..167] minted_at i64\r\n * [167..199] _reserved\r\n */\r\nexport const POSITION_NFT_STATE_LEN = 199;\r\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\r\nconst POSITION_NFT_VERSION = 2;\r\n\r\nexport interface PositionNftState {\r\n version: number;\r\n bump: number;\r\n portfolioAccount: PublicKey;\r\n nftMint: PublicKey;\r\n assetIndex: number;\r\n sideAtMint: number;\r\n basisPosQAtMint: bigint;\r\n fSnapAtMint: bigint;\r\n marketIdAtMint: bigint;\r\n epochSnapAtMint: bigint;\r\n positionOwnerAtMint: PublicKey;\r\n /** Backward-compatible alias for positionOwnerAtMint. */\r\n positionOwner: PublicKey;\r\n mintedAt: bigint;\r\n}\r\n\r\n/**\r\n * Read a little-endian signed i128 from a DataView at `offset`.\r\n *\r\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\r\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\r\n * value is set the result is negative and two's-complement sign extension is\r\n * applied explicitly.\r\n *\r\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\r\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\r\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\r\n * shifted high half collapses the sign bit into all high bits and corrupts the\r\n * result.\r\n *\r\n * @param view DataView wrapping the raw account bytes\r\n * @param offset Byte offset of the i128 field (little-endian)\r\n * @returns Signed BigInt in the range [-2^127, 2^127)\r\n */\r\nfunction readI128FromView(view: DataView, offset: number): bigint {\r\n const lo = view.getBigUint64(offset, true);\r\n const hi = view.getBigUint64(offset + 8, true);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Parse a PositionNft account from raw bytes.\r\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\r\n */\r\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\r\n if (data.length < POSITION_NFT_STATE_LEN) {\r\n throw new Error(\r\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\r\n );\r\n }\r\n\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n const magic = view.getBigUint64(0, true);\r\n if (magic !== POSITION_NFT_MAGIC) {\r\n throw new Error(\"PositionNft account has invalid magic\");\r\n }\r\n if (data[8] !== POSITION_NFT_VERSION) {\r\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\r\n }\r\n\r\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\r\n\r\n return {\r\n version: data[8],\r\n bump: data[9],\r\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\r\n nftMint: new PublicKey(data.subarray(42, 74)),\r\n assetIndex: view.getUint32(74, true),\r\n sideAtMint: data[78],\r\n basisPosQAtMint: readI128FromView(view, 79),\r\n fSnapAtMint: readI128FromView(view, 95),\r\n marketIdAtMint: view.getBigUint64(111, true),\r\n epochSnapAtMint: view.getBigUint64(119, true),\r\n positionOwnerAtMint,\r\n positionOwner: positionOwnerAtMint,\r\n mintedAt: view.getBigInt64(159, true),\r\n };\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\n/**\r\n * Read an environment variable safely. Returns `undefined` in browser\r\n * environments where `process` is not defined, avoiding a\r\n * `ReferenceError` crash at import time.\r\n */\r\nexport function safeEnv(key: string): string | undefined {\r\n try {\r\n return typeof process !== \"undefined\" && process?.env\r\n ? process.env[key]\r\n : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Centralized PROGRAM_ID configuration\r\n * \r\n * Default to environment variable, then fall back to network-specific defaults.\r\n * This prevents hard-coded program IDs scattered across the codebase.\r\n */\r\n\r\nexport const PROGRAM_IDS = {\r\n devnet: {\r\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\r\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\r\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n },\r\n mainnet: {\r\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\r\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\r\n },\r\n} as const;\r\nObject.freeze(PROGRAM_IDS.devnet);\r\nObject.freeze(PROGRAM_IDS.mainnet);\r\nObject.freeze(PROGRAM_IDS);\r\n\r\n/**\r\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\r\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\r\n * and upgraded in place at the same address).\r\n *\r\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\r\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\r\n * markets — they were not migrated in place, so anything still pointed at them\r\n * (e.g. the percolator-launch playground config, which hardcodes its own program\r\n * ID rather than reading this module) keeps working against the old markets until\r\n * it is explicitly cut over to this fresh triple. That playground cutover is a\r\n * separate, later step — NOT performed by this change.\r\n */\r\nexport const PROGRAM_IDS_V17 = {\r\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\r\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\r\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\r\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\r\n} as const;\r\nObject.freeze(PROGRAM_IDS_V17);\r\n\r\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\r\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\r\n\r\nexport type Network = \"devnet\" | \"mainnet\";\r\n\r\n/** Allowlist of legitimate percolator program addresses (all networks). */\r\nconst KNOWN_PROGRAM_IDS = new Set([\r\n PROGRAM_IDS.devnet.percolator,\r\n PROGRAM_IDS.mainnet.percolator,\r\n PROGRAM_IDS_V17.percolator,\r\n]);\r\n\r\n/** Allowlist of legitimate matcher program addresses (all networks). */\r\nconst KNOWN_MATCHER_IDS = new Set([\r\n PROGRAM_IDS.devnet.matcher,\r\n PROGRAM_IDS.mainnet.matcher,\r\n]);\r\n\r\n/**\r\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\r\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\r\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\r\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\r\n * during pre-deploy / devnet testing — which the allowlist alone would break.\r\n */\r\nfunction programOverrideOptIn(): boolean {\r\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\r\n}\r\n\r\n/**\r\n * Get the Percolator program ID for the current network\r\n * \r\n * Priority:\r\n * 1. PROGRAM_ID env var (explicit override)\r\n * 2. Network-specific default (NETWORK env var)\r\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\r\n */\r\nexport function getProgramId(network?: Network): PublicKey {\r\n // #249: an explicit `network` argument is authoritative and must NOT be silently\r\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\r\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\r\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\r\n if (network === undefined) {\r\n const override = safeEnv(\"PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\r\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].percolator;\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the Matcher program ID for the current network\r\n */\r\nexport function getMatcherProgramId(network?: Network): PublicKey {\r\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\r\n if (network === undefined) {\r\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\r\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].matcher;\r\n\r\n if (!programId) {\r\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\r\n }\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the current network from environment.\r\n *\r\n * SECURITY (PERC-697): Removed silent mainnet default.\r\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\r\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\r\n *\r\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\r\n * Production deployments always set NETWORK explicitly via Railway/env.\r\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\r\n * enforces FORCE_MAINNET=1.\r\n */\r\nexport function getCurrentNetwork(): Network {\r\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\r\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\r\n return \"mainnet\";\r\n }\r\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\r\n return \"devnet\";\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\n\r\n// =============================================================================\r\n// Browser-compatible read helpers using DataView\r\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\r\n// =============================================================================\r\n\r\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\n/** Read a single unsigned byte at `off`. */\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n if (off >= data.length) {\r\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\r\n }\r\n return data[off];\r\n}\r\n/** Read a little-endian u16 at `off`. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\n/** Read a little-endian u32 at `off`. */\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint32(off, true);\r\n}\r\n/** Read a little-endian u64 at `off` as a BigInt. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\n/** Read a little-endian signed i64 at `off` as a BigInt. */\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\n\r\n// =============================================================================\r\n// Helper: read signed/unsigned i128 from buffer\r\n// =============================================================================\r\n\r\n/**\r\n * Read a little-endian signed i128 at `offset`.\r\n * Composed from two u64 halves; sign-extends if the high bit is set.\r\n */\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// =============================================================================\r\n// Slab Layout Version Detection\r\n// =============================================================================\r\n// The deployed devnet program uses a different struct layout (V0) than the SDK\r\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\r\n// struct changes that have NOT been deployed to devnet yet.\r\n//\r\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\r\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\r\n// - RiskParams: 56 bytes (basic fields only)\r\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\r\n// - No partial liquidation field in Account (240 bytes)\r\n//\r\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\r\n// - InsuranceFund: expanded with isolation fields (72 bytes)\r\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\r\n// - Has mark_price, long_oi/short_oi, emergency fields\r\n// - Account has last_partial_liquidation_slot (248 bytes)\r\n// =============================================================================\r\n\r\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\r\n\r\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\r\nexport const SLAB_MAGIC = MAGIC;\r\n\r\n// Flag bits in header._padding[0] at offset 13\r\nconst FLAG_RESOLVED = 1 << 0;\r\n\r\n/**\r\n * Full slab layout descriptor. Returned by detectSlabLayout().\r\n * All engine field offsets are relative to engineOff.\r\n */\r\nexport interface SlabLayout {\r\n version: 0 | 1 | 2;\r\n headerLen: number;\r\n configOffset: number;\r\n configLen: number;\r\n reservedOff: number; // offset of _reserved in header\r\n engineOff: number;\r\n accountSize: number;\r\n maxAccounts: number;\r\n bitmapWords: number;\r\n accountsOff: number; // absolute offset of accounts array in slab\r\n\r\n // Engine field offsets (relative to engineOff)\r\n engineInsuranceOff: number;\r\n engineParamsOff: number;\r\n paramsSize: number;\r\n engineCurrentSlotOff: number;\r\n engineFundingIndexOff: number;\r\n engineLastFundingSlotOff: number;\r\n engineFundingRateBpsOff: number;\r\n engineMarkPriceOff: number; // -1 if not present (V0)\r\n engineLastCrankSlotOff: number;\r\n engineMaxCrankStalenessOff: number;\r\n engineTotalOiOff: number;\r\n engineLongOiOff: number; // -1 if not present (V0)\r\n engineShortOiOff: number; // -1 if not present (V0)\r\n engineCTotOff: number;\r\n enginePnlPosTotOff: number;\r\n engineLiqCursorOff: number;\r\n engineGcCursorOff: number;\r\n engineLastSweepStartOff: number;\r\n engineLastSweepCompleteOff: number;\r\n engineCrankCursorOff: number;\r\n engineSweepStartIdxOff: number;\r\n engineLifetimeLiquidationsOff: number;\r\n engineLifetimeForceClosesOff: number;\r\n engineNetLpPosOff: number;\r\n engineLpSumAbsOff: number;\r\n engineLpMaxAbsOff: number;\r\n engineLpMaxAbsSweepOff: number;\r\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\r\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\r\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\r\n engineBitmapOff: number; // relative to engineOff\r\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\r\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\r\n\r\n // Insurance fund layout\r\n hasInsuranceIsolation: boolean;\r\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\r\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\r\n\r\n // Optional fallback for engines without a stored mark_price field (v12.17+):\r\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\r\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\r\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\r\n // predate v12.17 and already expose a real engine.mark_price.\r\n configMarkEwmaOff?: number;\r\n}\r\n\r\n// ---- V0 layout constants (deployed devnet program) ----\r\nconst V0_HEADER_LEN = 72;\r\nconst V0_CONFIG_LEN = 408;\r\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\r\nconst V0_ACCOUNT_SIZE = 240;\r\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\r\n\r\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\r\n// V0 RiskParams: 56 bytes → runtime state at 104\r\nconst V0_ENGINE_PARAMS_OFF = 48;\r\nconst V0_PARAMS_SIZE = 56;\r\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\r\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\r\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\r\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\r\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\r\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\r\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\r\nconst V0_ENGINE_C_TOT_OFF = 176;\r\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\r\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\r\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\r\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\r\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\r\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\r\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\r\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\r\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\r\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\r\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\r\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\r\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\r\nconst V0_ENGINE_BITMAP_OFF = 320;\r\n\r\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\r\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\r\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\r\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\r\nconst V1_HEADER_LEN = 104;\r\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\r\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\r\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\r\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\r\nconst V1_ENGINE_OFF_LEGACY = 640;\r\nconst V1_ACCOUNT_SIZE = 248;\r\nconst V1_RESERVED_OFF = 80;\r\n\r\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\r\n// V1 RiskParams: 288 bytes → runtime state at 360\r\nconst V1_ENGINE_PARAMS_OFF = 72;\r\nconst V1_PARAMS_SIZE = 288;\r\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\r\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\r\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\r\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\r\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\r\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\r\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\r\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\r\nconst V1_ENGINE_LONG_OI_OFF = 456;\r\nconst V1_ENGINE_SHORT_OI_OFF = 472;\r\nconst V1_ENGINE_C_TOT_OFF = 488;\r\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\r\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\r\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\r\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\r\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\r\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\r\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\r\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\r\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\r\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\r\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\r\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\r\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\r\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\r\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\r\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\r\nconst V1_ENGINE_BITMAP_OFF = 656;\r\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\r\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\r\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\r\n// These corrected values must be used for actual byte-level parsing.\r\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\r\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\r\n\r\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\r\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\r\n// Key differences:\r\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\r\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\r\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\r\n// - Bitmap at engine+624 (not 656)\r\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\r\nconst V1D_CONFIG_LEN = 320;\r\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\r\nconst V1D_ACCOUNT_SIZE = 248;\r\n\r\n// V1D engine field offsets (relative to engineOff):\r\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\r\nconst V1D_ENGINE_INSURANCE_OFF = 16;\r\nconst V1D_ENGINE_PARAMS_OFF = 96;\r\nconst V1D_PARAMS_SIZE = 288;\r\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\r\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\r\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\r\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\r\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\r\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\r\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\r\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\r\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\r\nconst V1D_ENGINE_LONG_OI_OFF = 480;\r\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\r\nconst V1D_ENGINE_C_TOT_OFF = 512;\r\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\r\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\r\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\r\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\r\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\r\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\r\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\r\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\r\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\r\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\r\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\r\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\r\nconst V1D_ENGINE_BITMAP_OFF = 624;\r\n\r\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\r\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\r\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\r\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\r\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\r\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\r\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\r\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\r\nconst V2_HEADER_LEN = 104;\r\nconst V2_CONFIG_LEN = 496;\r\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\r\nconst V2_ACCOUNT_SIZE = 248;\r\nconst V2_ENGINE_BITMAP_OFF = 432;\r\n\r\n// V2 engine field offsets (relative to engineOff)\r\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\r\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\r\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\r\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\r\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\r\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\r\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\r\nconst V2_ENGINE_C_TOT_OFF = 424;\r\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\r\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\r\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\r\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\r\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\r\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\r\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\r\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\r\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\r\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\r\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\r\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\r\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\r\n\r\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\r\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\r\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\r\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\r\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\r\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\r\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\r\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\r\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\r\n//\r\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\r\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\r\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\r\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\r\n// Prior value of 1006 was an arithmetic transcription error.\r\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\r\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\r\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\r\n\r\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\r\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\r\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\r\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\r\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\r\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\r\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\r\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\r\n\r\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\r\nconst V_ADL_PARAMS_SIZE = 336;\r\n\r\n// V_ADL engine field offsets (relative to engineOff=624):\r\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\r\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\r\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\r\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\r\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\r\n// PERC-8270 new fields at 472-504:\r\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\r\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\r\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\r\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\r\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\r\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\r\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\r\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\r\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\r\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\r\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\r\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\r\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\r\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\r\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\r\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\r\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\r\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\r\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\r\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\r\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\r\n// ADL side state (PERC-8268, 224 bytes):\r\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\r\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\r\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\r\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\r\n// Then LP aggregates:\r\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\r\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\r\n// emergency fields:\r\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\r\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\r\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\r\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\r\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\r\n\r\n// V_ADL account field offsets (relative to account slot start):\r\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\r\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\r\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\r\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\r\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\r\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\r\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\r\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\r\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\r\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\r\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\r\n\r\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\r\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\r\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\r\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\r\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\r\n// dynamic fee tiers, fee splits).\r\n// Engine field ordering completely reorganized from V_ADL.\r\n// All values verified by cargo build-sbf compile-time assertions.\r\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\r\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\r\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\r\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\r\n// Those fields exist in percolator-core but NOT in the deployed binary.\r\n//\r\n// HOST constants below are for aarch64 test builds (percolator-core).\r\n// SBF constants are for the actual deployed program.\r\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\r\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\r\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\r\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\r\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\r\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\r\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\r\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\r\nconst V12_1_ENGINE_PARAMS_OFF = 96;\r\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\r\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\r\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\r\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\r\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\r\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\r\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\r\nconst V12_1_SBF_OFF_C_TOT = 248;\r\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\r\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\r\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\r\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\r\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\r\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\r\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\r\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\r\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\r\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\r\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\r\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\r\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\r\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\r\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\r\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\r\n// Bitmap (used field): 584\r\n// Fields NOT present in deployed program (return -1):\r\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\r\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\r\n//\r\n// HOST engine field offsets (percolator-core, for test builds):\r\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\r\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\r\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\r\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\r\nconst V12_1_ENGINE_C_TOT_OFF = 480;\r\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\r\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\r\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\r\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\r\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\r\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\r\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\r\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\r\n// HOST-only fields (percolator-core has these, deployed percolator does not):\r\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\r\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\r\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\r\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\r\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\r\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\r\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\r\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\r\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\r\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\r\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\r\n// V12_1 account field offsets (relative to account slot start):\r\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\r\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\r\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\r\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\r\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\r\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\r\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\r\n\r\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\r\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\r\n// SBF layout (u128 align=8):\r\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\r\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\r\n// → fees_earned_total(@272) = 288 bytes\r\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\r\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\r\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\r\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\r\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\r\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\r\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\r\n\r\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\r\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\r\n// explicitly sized, no pointer-derived alignment differences).\r\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\r\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\r\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\r\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\r\n// overflow_newest_present(u8@4384).\r\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\r\n// Field max_accounts moved to offset 24, insurance_floor at 144.\r\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\r\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\r\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\r\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\r\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\r\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\r\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\r\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\r\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\r\n\r\n// V12_15 account field offsets (relative to account slot start):\r\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\r\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\r\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\r\nconst V12_15_ACCT_PNL_OFF = 32; // i128\r\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\r\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\r\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\r\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\r\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\r\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\r\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\r\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\r\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\r\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\r\n\r\n// V12_15 RiskParams offsets (relative to params base):\r\n// sizeof(RiskParams) = 192\r\nconst V12_15_PARAMS_SIZE = 192;\r\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\r\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\r\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\r\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\r\n\r\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\r\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\r\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\r\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\r\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\r\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\r\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\r\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\r\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\r\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\r\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\r\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\r\nconst V12_15_ENGINE_BITMAP_OFF = 862;\r\n\r\n// V12_15 size map for layout detection\r\nconst V12_15_SIZES = new Map();\r\n\r\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\r\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\r\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\r\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\r\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\r\n// pending_present/remaining_q/horizon/created_slot.\r\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\r\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\r\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\r\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\r\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\r\n\r\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\r\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\r\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\r\n// _new_fields_pad, pending_admin[32]).\r\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\r\n// size_of::() = 512 (both native and SBF — u128 fields happen\r\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\r\n\r\n// Native (i128 align=16)\r\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\r\nconst V12_17_ACCOUNT_SIZE = 368;\r\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\r\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\r\nconst V12_17_RISK_BUF_LEN = 160;\r\n// Per-account generation table appended after RISK_BUF in percolator-prog.\r\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\r\nconst V12_17_GEN_TABLE_ENTRY = 8;\r\n\r\n// SBF (i128 align=8)\r\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\r\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\r\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\r\n\r\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\r\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\r\nconst V12_17_ACCT_KIND_OFF = 16; // u8\r\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\r\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\r\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\r\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\r\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\r\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\r\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\r\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\r\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\r\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\r\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\r\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\r\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\r\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\r\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\r\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\r\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\r\n\r\n// V12_17 RiskEngine field offsets (native, relative to engine start)\r\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\r\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\r\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\r\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\r\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\r\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\r\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\r\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\r\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\r\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\r\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\r\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\r\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\r\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\r\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\r\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\r\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\r\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\r\n\r\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\r\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\r\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\r\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\r\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\r\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\r\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\r\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\r\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\r\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\r\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\r\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\r\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\r\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_17 size map for layout detection\r\nconst V12_17_SIZES = new Map();\r\n\r\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\r\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\r\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\r\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\r\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\r\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\r\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\r\nconst V1M_ACCOUNT_SIZE = 248;\r\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\r\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\r\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\r\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\r\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\r\n\r\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\r\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\r\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\r\n// min_nonzero_im_req(u128=16) = +48 total\r\nconst V1M_PARAMS_SIZE = 336;\r\n\r\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\r\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\r\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\r\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\r\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\r\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\r\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\r\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\r\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\r\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\r\nconst V1M_ENGINE_LONG_OI_OFF = 504;\r\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\r\nconst V1M_ENGINE_C_TOT_OFF = 536;\r\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\r\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\r\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\r\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\r\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\r\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\r\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\r\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\r\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\r\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\r\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\r\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\r\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\r\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\r\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\r\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\r\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\r\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\r\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\r\n// which is invalid for a [u64; N] array under #[repr(C)].\r\nconst V1M_ENGINE_BITMAP_OFF = 720;\r\n\r\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\r\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\r\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\r\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\r\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\r\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\r\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\r\n// New runtime fields inserted between fundingRateBps and markPrice:\r\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\r\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\r\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\r\n// +504: lastCrankSlot, +512: maxCrankStaleness\r\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\r\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\r\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\r\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\r\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\r\n\r\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\r\n// (used by reinit-slab and other scripts). These refer to V1 layout.\r\nexport const ENGINE_OFF = V1_ENGINE_OFF;\r\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\r\n\r\n// ---- Known slab sizes per version and tier ----\r\n\r\n/**\r\n * Compute the total byte size of a slab given its layout parameters.\r\n * Used to pre-populate the known-size lookup maps at module load time.\r\n */\r\nfunction computeSlabSize(\r\n engineOff: number,\r\n bitmapOff: number,\r\n accountSize: number,\r\n maxAccounts: number,\r\n // postBitmap bytes immediately after the free-slot bitmap:\r\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\r\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\r\n postBitmap = 18,\r\n): number {\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return engineOff + accountsOff + maxAccounts * accountSize;\r\n}\r\n\r\nconst TIERS = [64, 256, 1024, 4096] as const;\r\n\r\n// Pre-compute known slab sizes for fast lookup\r\nconst V0_SIZES = new Map();\r\nconst V1_SIZES = new Map();\r\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\r\nconst V1_SIZES_LEGACY = new Map();\r\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\r\nconst V1D_SIZES = new Map();\r\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\r\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\r\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\r\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\r\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\r\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\r\nconst V2_SIZES = new Map();\r\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\r\nconst V1M_SIZES = new Map();\r\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\nconst V_ADL_SIZES = new Map();\r\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\r\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n// No disambiguation probe required — size-based detection works correctly.\r\nconst V1M2_SIZES = new Map();\r\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\r\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\r\nconst V_SETDEXPOOL_SIZES = new Map();\r\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\r\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\r\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\r\nconst V12_1_SIZES = new Map();\r\nconst V1D_SIZES_LEGACY = new Map();\r\nfor (const n of TIERS) {\r\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\r\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\r\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\r\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\r\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\r\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\r\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\r\n // Disambiguation requires peeking at the version field in the slab header.\r\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\r\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\r\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\r\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\r\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\r\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\r\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\r\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\r\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\r\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\r\n // e.g. n=4096 → 1288336 bytes.\r\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\r\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\r\n // Register BOTH host-computed and SBF-empirical sizes for detection.\r\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\r\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\r\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\r\n}\r\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\r\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\r\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\r\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\r\n\r\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\r\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\r\n// SBF: Account align=8 → accountsOff alignment is 8.\r\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\r\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\r\nconst V12_17_TIERS = [256, 1024, 4096] as const;\r\nfor (const n of V12_17_TIERS) {\r\n const bitmapWords = Math.ceil(n / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = n * 2;\r\n\r\n // Native (i128 align=16, Account align=16)\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(nativeSize, n);\r\n\r\n // SBF (i128 align=8, Account align=8)\r\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\r\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(sbfSize, n);\r\n}\r\n\r\n// ---- V12_19 layout constants ----\r\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\r\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\r\n// below comes from a Rust compile-error message that revealed the real SBF\r\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\r\n//\r\n// V12_19 vs V12_17 SBF differences:\r\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\r\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\r\n// - ENGINE_OFF: 584 -> 616\r\n// - ACCOUNT_SIZE: 352 -> 360\r\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\r\n// - RiskEngine grew substantially; accounts now inline within engine struct.\r\nconst V12_19_HEADER_LEN_SBF = 136;\r\nconst V12_19_CONFIG_LEN = 480;\r\nconst V12_19_ENGINE_OFF_SBF = 616;\r\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\r\nconst V12_19_SBF_RISK_BUF_LEN = 160;\r\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\r\n\r\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\r\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\r\n// MAX_ACCOUNTS; small (256) shown here.\r\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\r\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\r\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\r\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\r\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\r\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\r\n\r\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\r\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\r\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\r\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\r\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\r\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\r\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\r\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\r\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\r\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\r\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\r\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\r\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\r\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\r\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\r\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\r\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\r\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\r\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\r\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\r\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\r\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\r\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\r\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\r\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\r\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\r\n\r\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\r\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\r\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\r\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\r\n// + (8-byte align pad) + N*360 (accounts).\r\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\r\n// (mainnet probe-confirmed), medium=376432, large=1495024.\r\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\r\nconst V12_19_SIZES = new Map([\r\n [26872, 64], // --features micro (derived)\r\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\r\n [376432, 1024], // --features medium (derived)\r\n [1495024, 4096], // default features / large (derived)\r\n]);\r\n\r\n/**\r\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\r\n *\r\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\r\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\r\n * 736 area to same offset but the post-bitmap region now contains both\r\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\r\n * before the inline accounts.\r\n *\r\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\r\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\r\n * linearly with MAX_ACCOUNTS.\r\n */\r\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\r\n // Compute layout-dependent offsets for this tier.\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\r\n const freeHeadOff = numUsedOff + 2; // after num_used u16\r\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\r\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\r\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\r\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\r\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\r\n\r\n // Inherit Account-internal field offsets from V12_17 (they're the same since\r\n // the Account struct definition is identical between v12.17 and v12.19;\r\n // the +8 byte size diff is from trailing padding, not field reordering).\r\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\r\n\r\n return {\r\n ...base,\r\n headerLen: V12_19_HEADER_LEN_SBF,\r\n configLen: V12_19_CONFIG_LEN,\r\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\r\n engineOff: V12_19_ENGINE_OFF_SBF,\r\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\r\n accountsOff,\r\n bitmapWords,\r\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\r\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\r\n // V12_19-specific engine field offsets (probe-confirmed):\r\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\r\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\r\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\r\n // last_market_slot replaces V12_17 last_crank_slot semantics.\r\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\r\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\r\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\r\n };\r\n}\r\n\r\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\r\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\r\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\r\n// Bitmap at engine+584 (used field in RiskEngine).\r\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\r\nconst V12_1_SBF_ENGINE_OFF = 616;\r\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\r\n V12_1_SIZES.set(total, n);\r\n}\r\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\r\nconst V12_1_EP_SIZES = new Map();\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\r\n V12_1_EP_SIZES.set(total, n);\r\n}\r\n\r\n/**\r\n * V2 slab tier sizes (small and large) for discovery.\r\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\r\n */\r\nexport const SLAB_TIERS_V2 = Object.freeze({\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\r\n} as const);\r\n\r\n/**\r\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\r\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\r\n */\r\nexport const SLAB_TIERS_V1M: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M);\r\n\r\n/**\r\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\r\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\r\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\r\n */\r\nexport const SLAB_TIERS_V1M2: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M2);\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\r\n */\r\nexport const SLAB_TIERS_V_ADL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_ADL);\r\n\r\n/**\r\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\r\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\r\n */\r\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\r\n const isV0 = version === 0;\r\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\r\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\r\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\r\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\r\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\r\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\r\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\r\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\r\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\r\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\r\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version,\r\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\r\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\r\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\r\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: actualBitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: !isV0,\r\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\r\n * Uses correct field offsets derived from on-chain probing.\r\n *\r\n * @param maxAccounts - Number of account slots in the slab\r\n * @param postBitmap - Bytes after the bitmap before next_free array.\r\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\r\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\r\n */\r\n/**\r\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\r\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\r\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\r\n */\r\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\r\n const engineOff = V1D_ENGINE_OFF;\r\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\r\n const accountSize = V1D_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1D_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\r\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\r\n paramsSize: V1D_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: -1, // not present in deployed V1\r\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\r\n engineEmergencyOiModeOff: -1, // not present in deployed V1\r\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\r\n engineLastBreakerSlotOff: -1, // not present in deployed V1\r\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\r\n postBitmap,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\r\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V2 (BPF intermediate layout).\r\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\r\n */\r\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\r\n const engineOff = V2_ENGINE_OFF;\r\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\r\n const accountSize = V2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V2_HEADER_LEN,\r\n configOffset: V2_HEADER_LEN,\r\n configLen: V2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\r\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\r\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: -1, // V2 has no mark_price\r\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: -1, // V2 has no long_oi\r\n engineShortOiOff: -1, // V2 has no short_oi\r\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\r\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\r\n * and trade_twap runtime fields push the bitmap to offset 726.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\r\n */\r\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M_ENGINE_OFF;\r\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\r\n paramsSize: V1M_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\r\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\r\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\r\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\r\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\r\n */\r\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M2_ENGINE_OFF;\r\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\r\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n *\r\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\r\n * large (4096 accounts): 1288320 bytes\r\n * medium (1024 accounts): 323320 bytes\r\n * small (256 accounts): 82064 bytes\r\n */\r\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\r\n const engineOff = V_ADL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_ADL_CONFIG_LEN, // 520\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\r\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\r\n * e.g. large (4096 accts) = 1288336 bytes.\r\n */\r\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\r\n\r\n/**\r\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\r\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\r\n * Verified by cargo build-sbf compile-time assertions.\r\n */\r\nexport const SLAB_TIERS_V12_1: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_1);\r\n\r\n/**\r\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\r\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\r\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\r\n * Account layout completely redesigned with reserve cohort arrays.\r\n */\r\nexport const SLAB_TIERS_V12_15: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_15);\r\n\r\n/**\r\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\r\n * Uses SBF sizes (on-chain layout) for the dataSize values.\r\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\r\n * RISK_BUF_LEN=160 appended after engine.\r\n * Supported tiers: small(256), medium(1024), large(4096).\r\n */\r\nexport const SLAB_TIERS_V12_17: Record = {};\r\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\r\n const accountsOff = Math.ceil(preAcc / 8) * 8;\r\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_17);\r\n\r\n/**\r\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\r\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\r\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\r\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\r\n * fall through to the memcmp fallback path with no layout hint.\r\n *\r\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\r\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\r\n * exports consumed by discovery.ts.\r\n */\r\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\r\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\r\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\r\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\r\n});\r\n\r\n/**\r\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\r\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\r\n * All engine and account field offsets are identical to V_ADL.\r\n */\r\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\r\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\r\n paramsSize: V_ADL_PARAMS_SIZE,\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF vs host detection via size comparison.\r\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\r\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\r\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\r\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\r\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\r\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\r\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: isSbf ? 544 : 576,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\r\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\r\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\r\n // Fields that don't exist in the deployed program are set to -1 on SBF.\r\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\r\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\r\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\r\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\r\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\r\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\r\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\r\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\r\n\r\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\r\n // No isolated_balance or insurance_isolation_bps fields.\r\n hasInsuranceIsolation: !isSbf,\r\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\r\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\r\n */\r\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\r\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\r\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\r\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: 72,\r\n configOffset: 72,\r\n configLen: 544,\r\n reservedOff: 80, // V1_RESERVED_OFF\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\r\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\r\n // Engine offsets identical to V12_1 SBF\r\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\r\n engineFundingIndexOff: -1,\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\r\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\r\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\r\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\r\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\r\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\r\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\r\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\r\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\r\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\r\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\r\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\r\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\r\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\r\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\r\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\r\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\r\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\r\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\r\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\r\n *\r\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\r\n */\r\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\r\n const isSbf = dataLen === 237512;\r\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\r\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\r\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\r\n // SBF small has different bitmap/accounts offsets due to u128 align=8\r\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: 552, // SBF CONFIG_LEN for v12.15\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\r\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\r\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\r\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\r\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\r\n engineMarkPriceOff: -1, // not present in v12.15\r\n engineLastCrankSlotOff: -1, // not yet mapped\r\n engineMaxCrankStalenessOff: -1, // not yet mapped\r\n engineTotalOiOff: -1, // not present in v12.15 engine\r\n engineLongOiOff: -1, // not present in v12.15 engine\r\n engineShortOiOff: -1, // not present in v12.15 engine\r\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\r\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\r\n engineLiqCursorOff: -1, // not yet mapped\r\n engineGcCursorOff: -1, // not yet mapped\r\n engineLastSweepStartOff: -1, // not yet mapped\r\n engineLastSweepCompleteOff: -1, // not yet mapped\r\n engineCrankCursorOff: -1, // not yet mapped\r\n engineSweepStartIdxOff: -1, // not yet mapped\r\n engineLifetimeLiquidationsOff: -1, // not yet mapped\r\n engineLifetimeForceClosesOff: -1, // not present in v12.15\r\n engineNetLpPosOff: -1, // not present in v12.15\r\n engineLpSumAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\r\n engineEmergencyOiModeOff: -1, // not present in v12.15\r\n engineEmergencyStartSlotOff: -1, // not present in v12.15\r\n engineLastBreakerSlotOff: -1, // not present in v12.15\r\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\r\n postBitmap,\r\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\r\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\r\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\r\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\r\n * RISK_BUF_LEN=160 appended after engine.\r\n */\r\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\r\n // Detect SBF vs native from account size and engine offset.\r\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\r\n const isSbf = (() => {\r\n // Compute expected native size for this tier\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\r\n return dataLen !== nativeSize;\r\n })();\r\n\r\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\r\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\r\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const acctAlign = isSbf ? 8 : 16;\r\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\r\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\r\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\r\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\r\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\r\n configLen: 512,\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : 192,\r\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\r\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\r\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: -1,\r\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\r\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\r\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: -1, // removed in v12.17\r\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: -1,\r\n engineLastSweepCompleteOff: -1,\r\n engineCrankCursorOff: -1,\r\n engineSweepStartIdxOff: -1,\r\n engineLifetimeLiquidationsOff: -1,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap,\r\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n\r\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\r\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\r\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\r\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\r\n // so absolute offset in the slab is 72 + 304 = 376.\r\n configMarkEwmaOff: V0_HEADER_LEN + 304,\r\n };\r\n}\r\n\r\n/**\r\n * Detect the slab layout version from the raw account data length.\r\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\r\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\r\n *\r\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\r\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\r\n * V2 slabs have version===2 at offset 8 (u32 LE).\r\n *\r\n * @param dataLen - The slab account data length in bytes\r\n * @param data - Optional raw slab data for version-field disambiguation\r\n */\r\n/**\r\n * Assert that a built SlabLayout is internally consistent.\r\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\r\n * Used by layout builders to catch offset arithmetic bugs early.\r\n *\r\n * @param layout - Layout descriptor to validate.\r\n * @param dataLen - Actual byte length of the slab data buffer.\r\n * @returns The validated layout (identity function for chaining).\r\n */\r\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\r\n if (layout.accountsOff > dataLen) {\r\n throw new Error(\r\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\r\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\r\n );\r\n }\r\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\r\n if (bitmapEnd > dataLen) {\r\n throw new Error(\r\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\r\n );\r\n }\r\n return layout;\r\n}\r\n\r\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\r\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\r\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\r\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\r\n // deployed program only emits v12.19 going forward, so this priority\r\n // is correct for live mainnet reads.\r\n const v1219n = V12_19_SIZES.get(dataLen);\r\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\r\n\r\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\r\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\r\n const v1217n = V12_17_SIZES.get(dataLen);\r\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\r\n\r\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\r\n // Vastly larger account size — no collision with any earlier layout possible.\r\n const v1215n = V12_15_SIZES.get(dataLen);\r\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\r\n\r\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\r\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\r\n const v121epn = V12_1_EP_SIZES.get(dataLen);\r\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\r\n\r\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\r\n const v121n = V12_1_SIZES.get(dataLen);\r\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\r\n\r\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\r\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\r\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\r\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\r\n\r\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\r\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\r\n // works directly — no data-probe disambiguation required.\r\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n const v1m2n = V1M2_SIZES.get(dataLen);\r\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\r\n\r\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\r\n const vadln = V_ADL_SIZES.get(dataLen);\r\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\r\n\r\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\r\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\r\n const v1mn = V1M_SIZES.get(dataLen);\r\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\r\n\r\n // Check V0 sizes (deployed devnet V0 program)\r\n const v0n = V0_SIZES.get(dataLen);\r\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\r\n\r\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\r\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\r\n // When data is available, peek at the version field to disambiguate.\r\n const v1dn = V1D_SIZES.get(dataLen);\r\n if (v1dn !== undefined) {\r\n if (data && data.length >= 12) {\r\n const version = readU32LE(data, 8);\r\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\r\n }\r\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\r\n }\r\n\r\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\r\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\r\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\r\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\r\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\r\n\r\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\r\n const v1n = V1_SIZES.get(dataLen);\r\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\r\n\r\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\r\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\r\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\r\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\r\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\r\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Legacy detectLayout for backward compat.\r\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\r\n *\r\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\r\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\r\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\r\n */\r\nexport function detectLayout(dataLen: number) {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return null;\r\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\r\n}\r\n\r\n// =============================================================================\r\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\r\n// =============================================================================\r\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\r\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\r\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\r\nconst PARAMS_TRADING_FEE_OFF = 24;\r\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\r\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\r\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\r\n// riskReductionThreshold and liquidationBufferBps fields).\r\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\r\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\r\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\r\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\r\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\r\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\r\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\r\n\r\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\r\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\r\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\r\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\r\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\r\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\r\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\r\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\r\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\r\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\r\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\r\n\r\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\r\n// InitMarket wire payload for policy fields such as new_account_fee and\r\n// insurance_floor, but those fields are not stored inside engine RiskParams.\r\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\r\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\r\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\r\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\r\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\r\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\r\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\r\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\r\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\r\nconst V12_19_PARAMS_H_MIN_OFF = 104;\r\nconst V12_19_PARAMS_H_MAX_OFF = 112;\r\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\r\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\r\n\r\n// =============================================================================\r\n// Account Layout (240/248 bytes)\r\n// The first 240 bytes are identical in V0 and V1.\r\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\r\n// =============================================================================\r\nconst ACCT_ACCOUNT_ID_OFF = 0;\r\nconst ACCT_CAPITAL_OFF = 8;\r\nconst ACCT_KIND_OFF = 24;\r\nconst ACCT_PNL_OFF = 32;\r\nconst ACCT_RESERVED_PNL_OFF = 48;\r\nconst ACCT_WARMUP_STARTED_OFF = 56;\r\nconst ACCT_WARMUP_SLOPE_OFF = 64;\r\nconst ACCT_POSITION_SIZE_OFF = 80;\r\nconst ACCT_ENTRY_PRICE_OFF = 96;\r\nconst ACCT_FUNDING_INDEX_OFF = 104;\r\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\r\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\r\nconst ACCT_OWNER_OFF = 184;\r\nconst ACCT_FEE_CREDITS_OFF = 216;\r\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\r\n\r\n// =============================================================================\r\n// Interfaces\r\n// =============================================================================\r\n\r\nexport interface SlabHeader {\r\n magic: bigint;\r\n version: number;\r\n bump: number;\r\n flags: number;\r\n resolved: boolean;\r\n paused: boolean;\r\n admin: PublicKey;\r\n nonce: bigint;\r\n lastThrUpdateSlot: bigint;\r\n}\r\n\r\nexport interface MarketConfig {\r\n collateralMint: PublicKey;\r\n vaultPubkey: PublicKey;\r\n indexFeedId: PublicKey;\r\n maxStalenessSlots: bigint;\r\n confFilterBps: number;\r\n vaultAuthorityBump: number;\r\n invert: number;\r\n unitScale: number;\r\n fundingHorizonSlots: bigint;\r\n fundingKBps: bigint;\r\n fundingInvScaleNotionalE6: bigint;\r\n fundingMaxPremiumBps: bigint;\r\n fundingMaxBpsPerSlot: bigint;\r\n threshFloor: bigint;\r\n threshRiskBps: bigint;\r\n threshUpdateIntervalSlots: bigint;\r\n threshStepBps: bigint;\r\n threshAlphaBps: bigint;\r\n threshMin: bigint;\r\n threshMax: bigint;\r\n threshMinStep: bigint;\r\n oracleAuthority: PublicKey;\r\n authorityPriceE6: bigint;\r\n authorityTimestamp: bigint;\r\n oraclePriceCapE2bps: bigint;\r\n lastEffectivePriceE6: bigint;\r\n oiCapMultiplierBps: bigint;\r\n maxPnlCap: bigint;\r\n adaptiveFundingEnabled: boolean;\r\n adaptiveScaleBps: number;\r\n adaptiveMaxFundingBps: bigint;\r\n marketCreatedSlot: bigint;\r\n oiRampSlots: bigint;\r\n /**\r\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\r\n * Do not use for market-resolution logic until a parser is wired.\r\n */\r\n resolvedSlot: bigint;\r\n insuranceIsolationBps: number;\r\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\r\n oraclePhase: number;\r\n /** PERC-622: Cumulative trade volume in e6 format */\r\n cumulativeVolumeE6: bigint;\r\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\r\n phase2DeltaSlots: number;\r\n /**\r\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\r\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\r\n * SetDexPool has never been called (all-zero pubkey).\r\n * Non-null means the program will reject any UpdateHyperpMark that passes\r\n * a different pool account.\r\n */\r\n dexPool: PublicKey | null;\r\n}\r\n\r\nexport interface InsuranceFund {\r\n balance: bigint;\r\n feeRevenue: bigint;\r\n isolatedBalance: bigint;\r\n isolationBps: number;\r\n}\r\n\r\nexport interface RiskParams {\r\n /**\r\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\r\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\r\n */\r\n warmupPeriodSlots: bigint;\r\n maintenanceMarginBps: bigint;\r\n initialMarginBps: bigint;\r\n tradingFeeBps: bigint;\r\n maxAccounts: bigint;\r\n newAccountFee: bigint;\r\n riskReductionThreshold: bigint;\r\n maintenanceFeePerSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n liquidationFeeBps: bigint;\r\n liquidationFeeCap: bigint;\r\n liquidationBufferBps: bigint;\r\n minLiquidationAbs: bigint;\r\n /** Minimum initial deposit to open an account (V12_1+ only) */\r\n minInitialDeposit: bigint;\r\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\r\n minNonzeroMmReq: bigint;\r\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\r\n minNonzeroImReq: bigint;\r\n /** Insurance fund floor (V12_1+ only) */\r\n insuranceFloor: bigint;\r\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\r\n hMin: bigint;\r\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\r\n hMax: bigint;\r\n}\r\n\r\nexport interface EngineState {\r\n vault: bigint;\r\n insuranceFund: InsuranceFund;\r\n currentSlot: bigint;\r\n fundingIndexQpbE6: bigint;\r\n lastFundingSlot: bigint;\r\n /**\r\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\r\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\r\n */\r\n fundingRateBpsPerSlotLast: bigint;\r\n /**\r\n * Funding rate in e9 units (i128). v12.15+ only.\r\n * 0n on pre-v12.15 slabs.\r\n */\r\n fundingRateE9: bigint;\r\n /**\r\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\r\n */\r\n marketMode: 0 | 1 | null;\r\n lastCrankSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n totalOpenInterest: bigint;\r\n longOi: bigint;\r\n shortOi: bigint;\r\n cTot: bigint;\r\n pnlPosTot: bigint;\r\n /**\r\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\r\n */\r\n pnlMaturedPosTot: bigint;\r\n liqCursor: number;\r\n gcCursor: number;\r\n lastSweepStartSlot: bigint;\r\n lastSweepCompleteSlot: bigint;\r\n crankCursor: number;\r\n sweepStartIdx: number;\r\n lifetimeLiquidations: bigint;\r\n lifetimeForceCloses: bigint;\r\n netLpPos: bigint;\r\n lpSumAbs: bigint;\r\n lpMaxAbs: bigint;\r\n lpMaxAbsSweep: bigint;\r\n emergencyOiMode: boolean;\r\n emergencyStartSlot: bigint;\r\n lastBreakerSlot: bigint;\r\n numUsedAccounts: number;\r\n nextAccountId: bigint;\r\n markPriceE6: bigint;\r\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\r\n oraclePriceE6: bigint;\r\n\r\n // ---- V12_17 engine fields ----\r\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\r\n fLongNum: bigint;\r\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\r\n fShortNum: bigint;\r\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\r\n negPnlAccountCount: bigint;\r\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\r\n fundPxLast: bigint;\r\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\r\n resolvedKLongTerminalDelta: bigint;\r\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\r\n resolvedKShortTerminalDelta: bigint;\r\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\r\n resolvedLivePrice: bigint;\r\n}\r\n\r\nexport enum AccountKind {\r\n User = 0,\r\n LP = 1,\r\n}\r\n\r\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\r\nexport type ReserveCohortBytes = Uint8Array;\r\n\r\nexport interface Account {\r\n kind: AccountKind;\r\n accountId: bigint;\r\n capital: bigint;\r\n pnl: bigint;\r\n reservedPnl: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupStartedAtSlot: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupSlopePerStep: bigint;\r\n positionSize: bigint;\r\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\r\n entryPrice: bigint;\r\n fundingIndex: bigint;\r\n matcherProgram: PublicKey;\r\n matcherContext: PublicKey;\r\n owner: PublicKey;\r\n feeCredits: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n lastFeeSlot: bigint;\r\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\r\n feesEarnedTotal: bigint;\r\n /**\r\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\r\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\r\n */\r\n exactReserveCohorts: ReserveCohortBytes[] | null;\r\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\r\n exactCohortCount: number | null;\r\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowOlder: ReserveCohortBytes | null;\r\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\r\n overflowOlderPresent: boolean | null;\r\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowNewest: ReserveCohortBytes | null;\r\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\r\n overflowNewestPresent: boolean | null;\r\n\r\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\r\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\r\n fSnap: bigint;\r\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\r\n adlABasis: bigint;\r\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\r\n adlKSnap: bigint;\r\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\r\n adlEpochSnap: bigint;\r\n\r\n // Scheduled reserve bucket (older, matures linearly)\r\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\r\n schedPresent: boolean | null;\r\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\r\n schedRemainingQ: bigint | null;\r\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\r\n schedAnchorQ: bigint | null;\r\n /** Start slot for scheduled bucket. null on pre-v12.17. */\r\n schedStartSlot: bigint | null;\r\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\r\n schedHorizon: bigint | null;\r\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\r\n schedReleaseQ: bigint | null;\r\n\r\n // Pending reserve bucket (newest, does not mature while pending)\r\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\r\n pendingPresent: boolean | null;\r\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\r\n pendingRemainingQ: bigint | null;\r\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\r\n pendingHorizon: bigint | null;\r\n /** Creation slot for pending bucket. null on pre-v12.17. */\r\n pendingCreatedSlot: bigint | null;\r\n}\r\n\r\n// =============================================================================\r\n// Fetch\r\n// =============================================================================\r\n\r\nexport async function fetchSlab(\r\n connection: Connection,\r\n slabPubkey: PublicKey,\r\n expectedOwner?: PublicKey\r\n): Promise {\r\n const info = await connection.getAccountInfo(slabPubkey);\r\n if (!info) {\r\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\r\n }\r\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\r\n throw new Error(\r\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\r\n );\r\n }\r\n return new Uint8Array(info.data);\r\n}\r\n\r\n// =============================================================================\r\n// PERC-302: Market Maturity OI Ramp\r\n// =============================================================================\r\n\r\nexport const RAMP_START_BPS = 1000n;\r\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\r\n\r\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\r\n const target = config.oiCapMultiplierBps;\r\n if (target === 0n) return 0n;\r\n if (config.oiRampSlots === 0n) return target;\r\n if (target <= RAMP_START_BPS) return target;\r\n const elapsed = currentSlot > config.marketCreatedSlot\r\n ? currentSlot - config.marketCreatedSlot\r\n : 0n;\r\n if (elapsed >= config.oiRampSlots) return target;\r\n const range = target - RAMP_START_BPS;\r\n const rampAdd = (range * elapsed) / config.oiRampSlots;\r\n const result = RAMP_START_BPS + rampAdd;\r\n return result < target ? result : target;\r\n}\r\n\r\n// =============================================================================\r\n// Header helpers\r\n// =============================================================================\r\n\r\nexport function readNonce(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\r\n return readU64LE(data, roff);\r\n}\r\n\r\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\r\n return readU64LE(data, roff + 8);\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Parse slab header (first 72 bytes — layout-independent).\r\n */\r\nexport function parseHeader(data: Uint8Array): SlabHeader {\r\n if (data.length < V0_HEADER_LEN) {\r\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\r\n }\r\n\r\n const magic = readU64LE(data, 0);\r\n if (magic !== MAGIC) {\r\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\r\n }\r\n\r\n const version = readU32LE(data, 8);\r\n const bump = readU8(data, 12);\r\n const flags = readU8(data, 13);\r\n const admin = new PublicKey(data.subarray(16, 48));\r\n\r\n // Reserved field location depends on layout\r\n const layout = detectSlabLayout(data.length, data);\r\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\r\n const nonce = readU64LE(data, roff);\r\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\r\n\r\n return {\r\n magic,\r\n version,\r\n bump,\r\n flags,\r\n resolved: (flags & FLAG_RESOLVED) !== 0,\r\n paused: (flags & 0x02) !== 0,\r\n admin,\r\n nonce,\r\n lastThrUpdateSlot,\r\n };\r\n}\r\n\r\n/**\r\n * Parse market config. Layout-version aware.\r\n * For V0 slabs, fields beyond the basic config are read if present in the data,\r\n * otherwise defaults are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\n/**\r\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\r\n * SBF layout (u128 align=8, total size 512 bytes):\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_bps_per_slot i64\r\n * 144 oracle_authority [32]\r\n * 176 authority_price_e6 u64\r\n * 184 authority_timestamp i64\r\n * 192 oracle_price_cap_e2bps u64\r\n * 200 last_effective_price_e6 u64\r\n * 208 max_insurance_floor u128\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\r\n * 240 insurance_withdraw_cooldown_slots u64\r\n * 248 _iw_padding2 [u64;2]\r\n * 264 last_hyperp_index_slot u64\r\n * 272 last_mark_push_slot u128\r\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\r\n * 304 mark_ewma_e6 u64\r\n * 312 mark_ewma_last_slot u64\r\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\r\n * 336 permissionless_resolve_stale_slots u64\r\n * 344 last_good_oracle_slot u64\r\n * 352 maintenance_fee_per_slot u128\r\n * 368 last_fee_charge_slot u64 (+ 8 pad)\r\n * 384 mark_min_fee u64\r\n * 392 force_close_delay_slots u64\r\n * 400 dex_pool [32]\r\n * 432 max_pnl_cap u64\r\n * 440 last_audit_pause_slot u64\r\n * 448 oi_cap_multiplier_bps u64\r\n * 456 dispute_window_slots u64\r\n * 464 dispute_bond_amount u64\r\n * 472 lp_collateral_enabled u8\r\n * 473 _pad u8\r\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\r\n * 480 pending_admin [32]\r\n * 512 end\r\n */\r\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_17_BYTES = 512;\r\n if (data.length < configOff + MIN_V12_17_BYTES) {\r\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\r\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\r\n // currently surfaced by the MarketConfig type; read them when/if callers\r\n // need them. Only dex_pool is consumed downstream.\r\n\r\n const dexPoolBytes = data.subarray(b + 400, b + 432);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n, // removed in v12.17\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 448),\r\n maxPnlCap: readU64LE(data, b + 432),\r\n adaptiveFundingEnabled: false, // removed in v12.17\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\r\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\r\n * --features small) on 2026-04-28.\r\n *\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_e9_per_slot i64\r\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\r\n * 176 hyperp_mark_e6 u64 ← v12.19 only\r\n * 184 last_oracle_publish_time i64\r\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\r\n * 200 insurance_withdraw_max_bps u16\r\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\r\n * 204 _iw_padding [u8;4]\r\n * 208 insurance_withdraw_cooldown_slots u64\r\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 last_hyperp_index_slot u64\r\n * 240 last_mark_push_slot u128\r\n * 256 last_insurance_withdraw_slot u64\r\n * 264 _pad u64\r\n * 272 mark_ewma_e6 u64\r\n * 280 mark_ewma_last_slot u64\r\n * 288 mark_ewma_halflife_slots u64\r\n * 296 init_restart_slot u64\r\n * 304 permissionless_resolve_stale_slots u64\r\n * 312 last_good_oracle_slot u64\r\n * 320 maintenance_fee_per_slot u128\r\n * 336 fee_sweep_cursor_word u64\r\n * 344 fee_sweep_cursor_bit u64\r\n * 352 mark_min_fee u64\r\n * 360 force_close_delay_slots u64\r\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\r\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\r\n * 408 last_audit_pause_slot u64\r\n * 416 oi_cap_multiplier_bps u64\r\n * 424 dispute_window_slots u64\r\n * 432 dispute_bond_amount u64\r\n * 440 lp_collateral_enabled u8\r\n * 441 _pad u8\r\n * 442 lp_collateral_ltv_bps u16\r\n * 444 _pad [u8;4]\r\n * 448 pending_admin [32]\r\n * 480 end\r\n */\r\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_19_BYTES = 480;\r\n if (data.length < configOff + MIN_V12_19_BYTES) {\r\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\r\n\r\n const dexPoolBytes = data.subarray(b + 368, b + 400);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n,\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 416),\r\n maxPnlCap: readU64LE(data, b + 400),\r\n adaptiveFundingEnabled: false,\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseConfig: invalid slab magic');\r\n }\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\r\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\r\n\r\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\r\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\r\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_19) {\r\n return parseConfigV12_19(data, configOff);\r\n }\r\n\r\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\r\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\r\n // sequential code below covers pre-v12.17 layouts.\r\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\r\n if (isV12_17) {\r\n return parseConfigV12_17(data, configOff);\r\n }\r\n\r\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\r\n // V1 extended fields are optional and guarded by their own `remaining` checks.\r\n const MIN_CONFIG_BYTES = 376;\r\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\r\n }\r\n\r\n let off = configOff;\r\n\r\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const maxStalenessSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const confFilterBps = readU16LE(data, off);\r\n off += 2;\r\n\r\n const vaultAuthorityBump = readU8(data, off);\r\n off += 1;\r\n\r\n const invert = readU8(data, off);\r\n off += 1;\r\n\r\n const unitScale = readU32LE(data, off);\r\n off += 4;\r\n\r\n // Funding rate parameters\r\n const fundingHorizonSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingKBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\r\n off += 16;\r\n\r\n const fundingMaxPremiumBps = readI64LE(data, off);\r\n off += 8;\r\n\r\n const fundingMaxBpsPerSlot = readI64LE(data, off);\r\n off += 8;\r\n\r\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\r\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\r\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\r\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\r\n\r\n // Threshold parameters\r\n const threshFloor = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshRiskBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshUpdateIntervalSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshStepBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshAlphaBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshMin = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMax = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMinStep = readU128LE(data, off);\r\n off += 16;\r\n\r\n // Oracle authority fields\r\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const authorityPriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n const authorityTimestamp = readI64LE(data, off);\r\n off += 8;\r\n\r\n // Oracle price circuit breaker\r\n const oraclePriceCapE2bps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const lastEffectivePriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n // OI cap\r\n const oiCapMultiplierBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const maxPnlCap = readU64LE(data, off);\r\n off += 8;\r\n\r\n // Check if we have enough data for V1-only fields\r\n const remaining = configOff + configLen - off;\r\n\r\n let adaptiveFundingEnabled = false;\r\n let adaptiveScaleBps = 0;\r\n let adaptiveMaxFundingBps = 0n;\r\n let marketCreatedSlot = 0n;\r\n let oiRampSlots = 0n;\r\n let resolvedSlot = 0n;\r\n let insuranceIsolationBps = 0;\r\n let oraclePhase = 0;\r\n let cumulativeVolumeE6 = 0n;\r\n let phase2DeltaSlots = 0;\r\n\r\n if (remaining >= 40) {\r\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\r\n // market_created_slot(u64), oi_ramp_slots(u64),\r\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\r\n // _pad2(u32), adaptive_max_funding_bps(u64),\r\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\r\n marketCreatedSlot = readU64LE(data, off);\r\n off += 8;\r\n\r\n oiRampSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n adaptiveFundingEnabled = readU8(data, off) !== 0;\r\n off += 1;\r\n off += 1; // _adaptive_pad\r\n adaptiveScaleBps = readU16LE(data, off);\r\n off += 2;\r\n off += 4; // _adaptive_pad2\r\n adaptiveMaxFundingBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n if (remaining >= 42) {\r\n insuranceIsolationBps = readU16LE(data, off);\r\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\r\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\r\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\r\n if (remaining >= 56) { // 42 + 14 bytes padding\r\n const padOff = off + 2;\r\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\r\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\r\n // phase2_delta_slots is u24 LE (3 bytes)\r\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\r\n }\r\n }\r\n }\r\n\r\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\r\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\r\n // All-zero pubkey means SetDexPool was never called.\r\n let dexPool: PublicKey | null = null;\r\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\r\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\r\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\r\n // Return null if all-zero (SetDexPool never called)\r\n if (dexPoolBytes.some(b => b !== 0)) {\r\n dexPool = new PublicKey(dexPoolBytes);\r\n }\r\n }\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor,\r\n threshRiskBps,\r\n threshUpdateIntervalSlots,\r\n threshStepBps,\r\n threshAlphaBps,\r\n threshMin,\r\n threshMax,\r\n threshMinStep,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps,\r\n maxPnlCap,\r\n adaptiveFundingEnabled,\r\n adaptiveScaleBps,\r\n adaptiveMaxFundingBps,\r\n marketCreatedSlot,\r\n oiRampSlots,\r\n resolvedSlot,\r\n insuranceIsolationBps,\r\n oraclePhase,\r\n cumulativeVolumeE6,\r\n phase2DeltaSlots,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * Parse RiskParams from engine data. Layout-version aware.\r\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\r\n * not present on-chain, so defaults (0) are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\r\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\r\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\r\n const base = engineOff + paramsOff;\r\n\r\n // Validate we have enough data for the fields we'll actually read.\r\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\r\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\r\n if (data.length < base + MIN_PARAMS_BYTES) {\r\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\r\n }\r\n\r\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\r\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\r\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\r\n const isV12_19Params = layout !== null && layout !== undefined &&\r\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\r\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\r\n\r\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\r\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\r\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\r\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\r\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\r\n\r\n // Basic params present in all layouts (offsets 0-55 are identical)\r\n const result: RiskParams = {\r\n warmupPeriodSlots: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\r\n maintenanceMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\r\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\r\n initialMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 8)\r\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\r\n tradingFeeBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 16)\r\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\r\n maxAccounts: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\r\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\r\n newAccountFee: isV12_19Params\r\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\r\n : isV12_15Params\r\n ? readU128LE(data, base + 32) // offset 32 in v12.15\r\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\r\n // Extended params: defaults; overwritten below if layout supports them\r\n riskReductionThreshold: 0n,\r\n maintenanceFeePerSlot: 0n,\r\n maxCrankStalenessSlots: 0n,\r\n liquidationFeeBps: 0n,\r\n liquidationFeeCap: 0n,\r\n liquidationBufferBps: 0n,\r\n minLiquidationAbs: 0n,\r\n minInitialDeposit: 0n,\r\n minNonzeroMmReq: 0n,\r\n minNonzeroImReq: 0n,\r\n insuranceFloor: 0n,\r\n hMin: 0n,\r\n hMax: 0n,\r\n };\r\n\r\n if (isV12_19Params) {\r\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\r\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\r\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\r\n result.riskReductionThreshold = 0n;\r\n result.maintenanceFeePerSlot = 0n;\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = 0n;\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = 0n;\r\n } else if (isV12_15Params) {\r\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\r\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\r\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\r\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\r\n result.riskReductionThreshold = 0n; // removed in v12.15\r\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\r\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\r\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\r\n result.liquidationFeeBps = readU64LE(data, base + 56);\r\n result.liquidationFeeCap = readU128LE(data, base + 64);\r\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\r\n result.minLiquidationAbs = readU128LE(data, base + 80);\r\n result.minInitialDeposit = readU128LE(data, base + 96);\r\n result.minNonzeroMmReq = readU128LE(data, base + 112);\r\n result.minNonzeroImReq = readU128LE(data, base + 128);\r\n } else if (isV12_1Sbf) {\r\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\r\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n } else if (paramsSize >= 144) {\r\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\r\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\r\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\r\n */\r\nexport function parseEngine(data: Uint8Array): EngineState {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseEngine: invalid slab magic');\r\n }\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\r\n }\r\n if (data.length < layout.accountsOff) {\r\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\r\n }\r\n\r\n const base = layout.engineOff;\r\n\r\n // Detect layout versions\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\r\n\r\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\r\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\r\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\r\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_17 || isV12_19) {\r\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\r\n\r\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\r\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\r\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\r\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\r\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\r\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\r\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\r\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\r\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\r\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\r\n // resolved_k offsets: native 304/320, SBF 288/304\r\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\r\n const resolvedKLongOff = isV12_19 ? 288\r\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\r\n const resolvedKShortOff = isV12_19 ? 304\r\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\r\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\r\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\r\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\r\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\r\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\r\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\r\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\r\n\r\n const longOi = readU128LE(data, base + oiEffLongOff);\r\n const shortOi = readU128LE(data, base + oiEffShortOff);\r\n\r\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\r\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: 0n,\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + currentSlotOff),\r\n fundingIndexQpbE6: 0n, // replaced by per-side funding\r\n lastFundingSlot: 0n,\r\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\r\n fundingRateE9: 0n, // no stored funding rate in v12.17\r\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\r\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\r\n maxCrankStalenessSlots: 0n,\r\n totalOpenInterest: longOi + shortOi,\r\n longOi,\r\n shortOi,\r\n cTot: readU128LE(data, base + cTotOff),\r\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\r\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\r\n liqCursor: 0,\r\n gcCursor: readU16LE(data, base + gcCursorOff),\r\n lastSweepStartSlot: 0n,\r\n lastSweepCompleteSlot: 0n,\r\n crankCursor: 0,\r\n sweepStartIdx: 0,\r\n lifetimeLiquidations: 0n,\r\n lifetimeForceCloses: 0n,\r\n netLpPos: 0n,\r\n lpSumAbs: 0n,\r\n lpMaxAbs: 0n,\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n,\r\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\r\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\r\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\r\n\r\n // V12_17 fields\r\n fLongNum: readI128LE(data, base + fLongNumOff),\r\n fShortNum: readI128LE(data, base + fShortNumOff),\r\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\r\n fundPxLast: readU64LE(data, base + fundPxLastOff),\r\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\r\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\r\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\r\n };\r\n }\r\n\r\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\r\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\r\n const fundingRateBpsPerSlotLast = isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + layout.engineInsuranceOff),\r\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\r\n feeRevenue: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\r\n : 0n,\r\n isolatedBalance: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\r\n : 0n,\r\n isolationBps: layout.hasInsuranceIsolation\r\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\r\n : 0,\r\n },\r\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\r\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\r\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\r\n : readI128LE(data, base + layout.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\r\n fundingRateBpsPerSlotLast,\r\n fundingRateE9: isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : 0n,\r\n marketMode: isV12_15\r\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\r\n : null,\r\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\r\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\r\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\r\n totalOpenInterest: layout.engineTotalOiOff >= 0\r\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\r\n longOi: layout.engineLongOiOff >= 0\r\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\r\n shortOi: layout.engineShortOiOff >= 0\r\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\r\n cTot: readU128LE(data, base + layout.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\r\n pnlMaturedPosTot: isV12_15\r\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\r\n : 0n,\r\n liqCursor: layout.engineLiqCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\r\n gcCursor: layout.engineGcCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\r\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\r\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\r\n crankCursor: layout.engineCrankCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\r\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\r\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\r\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\r\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\r\n netLpPos: layout.engineNetLpPosOff >= 0\r\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\r\n lpSumAbs: layout.engineLpSumAbsOff >= 0\r\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\r\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\r\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\r\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\r\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\r\n : false,\r\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\r\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\r\n markPriceE6: layout.engineMarkPriceOff >= 0\r\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\r\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\r\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\r\n oraclePriceE6: isV12_15\r\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\r\n : 0n,\r\n numUsedAccounts: (() => {\r\n if (layout.postBitmap < 18) return 0;\r\n const bw = layout.bitmapWords;\r\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\r\n })(),\r\n nextAccountId: (() => {\r\n if (layout.postBitmap < 18) return 0n;\r\n const bw = layout.bitmapWords;\r\n const numUsedOff = layout.engineBitmapOff + bw * 8;\r\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\r\n })(),\r\n\r\n // V12_17 fields (not present in pre-v12.17)\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n };\r\n}\r\n\r\n/**\r\n * Read bitmap to get list of used account indices.\r\n */\r\n/**\r\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\r\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\r\n */\r\nexport function parseUsedIndices(data: Uint8Array): number[] {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n if (data.length < base + layout.bitmapWords * 8) {\r\n throw new Error(\"Slab data too short for bitmap\");\r\n }\r\n\r\n const used: number[] = [];\r\n for (let word = 0; word < layout.bitmapWords; word++) {\r\n const bits = readU64LE(data, base + word * 8);\r\n if (bits === 0n) continue;\r\n for (let bit = 0; bit < 64; bit++) {\r\n if ((bits >> BigInt(bit)) & 1n) {\r\n used.push(word * 64 + bit);\r\n }\r\n }\r\n }\r\n return used;\r\n}\r\n\r\n/**\r\n * Check if a specific account index is used.\r\n */\r\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) return false;\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n const word = Math.floor(idx / 64);\r\n const bit = idx % 64;\r\n const bits = readU64LE(data, base + word * 8);\r\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\r\n}\r\n\r\n/**\r\n * Calculate the maximum valid account index for a given slab size.\r\n */\r\nexport function maxAccountIndex(dataLen: number): number {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return 0;\r\n const accountsEnd = dataLen - layout.accountsOff;\r\n if (accountsEnd <= 0) return 0;\r\n return Math.floor(accountsEnd / layout.accountSize);\r\n}\r\n\r\n/**\r\n * Parse a single account by index.\r\n */\r\nexport function parseAccount(data: Uint8Array, idx: number): Account {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const maxIdx = maxAccountIndex(data.length);\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\r\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\r\n }\r\n\r\n const base = layout.accountsOff + idx * layout.accountSize;\r\n if (data.length < base + layout.accountSize) {\r\n throw new Error(\"Slab data too short for account\");\r\n }\r\n\r\n // Select layout-dependent account field offsets.\r\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\r\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\r\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\r\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\r\n // Pre-ADL (account_size<312): original offsets.\r\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\r\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\r\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\r\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\r\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\r\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\r\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\r\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\r\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\r\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\r\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\r\n\r\n if (isV12_17) {\r\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\r\n //\r\n // SBF vs native alignment delta:\r\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\r\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\r\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\r\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\r\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\r\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\r\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\r\n\r\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: 0n, // removed in v12.17\r\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\r\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\r\n warmupStartedAtSlot: 0n, // removed\r\n warmupSlopePerStep: 0n, // removed\r\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\r\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\r\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\r\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\r\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\r\n lastFeeSlot: 0n, // removed\r\n feesEarnedTotal: 0n, // removed in v12.17\r\n exactReserveCohorts: null, // replaced by two-bucket warmup\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // V12_17 fields\r\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\r\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\r\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\r\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\r\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\r\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\r\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\r\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\r\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\r\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\r\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\r\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\r\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\r\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\r\n };\r\n }\r\n\r\n if (isV12_15) {\r\n // V12_15 fast path: fixed offsets, all fields explicit.\r\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n // Parse the 62 reserve cohorts\r\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\r\n const exactReserveCohorts: ReserveCohortBytes[] = [];\r\n for (let i = 0; i < 62; i++) {\r\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\r\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\r\n }\r\n\r\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\r\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\r\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: 0n, // removed in v12.15\r\n warmupSlopePerStep: 0n, // removed in v12.15\r\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\r\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\r\n fundingIndex: 0n, // not present in v12.15 account struct\r\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\r\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\r\n lastFeeSlot: 0n, // removed in v12.15\r\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\r\n exactReserveCohorts,\r\n exactCohortCount: cohortCount,\r\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\r\n overflowOlderPresent,\r\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\r\n overflowNewestPresent,\r\n\r\n // v12.17 fields (not present in v12.15)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n }\r\n\r\n // Pre-v12.15 path\r\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\r\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\r\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\r\n 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));\r\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\r\n 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));\r\n 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));\r\n 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));\r\n 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));\r\n\r\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\r\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\r\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\r\n positionSize: readI128LE(data, base + positionSizeOff),\r\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\r\n // V12_1/V12_1_EP: funding_index not present in SBF layout\r\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\r\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\r\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\r\n feeCredits: readI128LE(data, base + feeCreditsOff),\r\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\r\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\r\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // v12.17 fields (not present in pre-v12.17)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\r\n//\r\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\r\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\r\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\r\n// is a full account-layout break — every v16-version market account is\r\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\r\n// =============================================================================\r\n\r\n/**\r\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\r\n * Stored at bytes [0..8] of every v17 percolator-owned account.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\n/**\r\n * v17 account version (u16 at offset 8).\r\n *\r\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\r\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\r\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\r\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\r\n */\r\nexport const V17_EXPECTED_VERSION = 17;\r\n\r\n/**\r\n * v17 account-kind byte (offset 10 of the 16-byte header).\r\n *\r\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\r\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\r\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\r\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\r\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\r\n * discovery — every other kind shares the same magic+version and would falsely\r\n * pass the looser {@link isV17Account} check (#264).\r\n */\r\nexport const V17_KIND_MARKET = 1;\r\n\r\n/** Byte offset of the v17 account-kind discriminator within the header. */\r\nexport const V17_KIND_OFF = 10;\r\n\r\n/**\r\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\r\n *\r\n * Growth history, each stage purely additive at the tail with all earlier\r\n * offsets UNCHANGED:\r\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\r\n * @432, `protocol_fee_accrued_atoms` u128 @464,\r\n * `protocol_fee_withdrawn_atoms` u128 @480.\r\n * 496 -> 576 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\r\n * @496/512/528/544, three u16 shares @560/562/564, then\r\n * `_padding_split` [u8;10] @566.\r\n *\r\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\r\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\r\n * it is u128-aligned; placing the u16 shares first would push the u128s to\r\n * offset 502 and force the compiler to insert implicit padding, failing the\r\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\r\n * padding out to the 16-byte alignment boundary.\r\n *\r\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\r\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\r\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\r\n * at line 1159.\r\n *\r\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\r\n * still carries the 496-byte layout. Reading a market created by that build\r\n * with this decoder will throw \"data too short\"; a 576-byte read against a\r\n * 496-byte account is a length error, not a silent misparse.\r\n */\r\nexport const V17_WRAPPER_CONFIG_LEN = 576;\r\n\r\n/**\r\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\r\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\r\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\r\n *\r\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\r\n * `_padding_split` tail at the only 8-aligned slot inside it, so\r\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\r\n * 592, and NO pre-existing offset moves. Growing the config instead would have\r\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\r\n * markets — a repeat of the 496→576 incident. If you ever find yourself\r\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\r\n *\r\n * Source of truth: percolator-prog `src/v16_program.rs` struct\r\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\r\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\r\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\r\n */\r\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\r\n\r\n/** v17 AssetOracleProfileV16 length (400 bytes). */\r\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\r\n\r\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\r\nexport const V17_HEADER_LEN = 16;\r\n\r\n/**\r\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\r\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\r\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\r\n * downstream offset in this file chains off it.\r\n */\r\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\r\n\r\n/**\r\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\r\n * verified against percolator-prog `cargo run --example dump_layout`.\r\n */\r\nexport const V17_MARKET_GROUP_LEN = 758;\r\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\r\n\r\n/**\r\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\r\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\r\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\r\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\r\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\r\n */\r\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\r\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\r\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\r\n }\r\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\r\n}\r\n\r\n/**\r\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\r\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\r\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\r\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\r\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\r\n */\r\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\r\n\r\n/**\r\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\r\n *\r\n * Field offsets follow SBF alignment (u128 align=8, not 16).\r\n * Full offset table (verified against v17 wrapper source v16_program.rs,\r\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\r\n * 0 marketauth [32]\r\n * 32 collateral_mint [32]\r\n * 64 secondary_collateral_mint [32]\r\n * 96 maintenance_fee_per_slot u128\r\n * 112 permissionless_market_init_fee u128\r\n * 128 trade_fee_base_bps u64\r\n * 136 permissionless_resolve_stale_slots u64\r\n * 144 force_close_delay_slots u64\r\n * 152 last_good_oracle_slot u64\r\n * 160 insurance_withdraw_deposit_remaining u128\r\n * 176 insurance_withdraw_max_bps u16\r\n * 178 liquidation_cranker_fee_share_bps u16\r\n * 180 maintenance_cranker_fee_share_bps u16\r\n * 182 backing_trade_fee_bps_long u16\r\n * 184 unit_scale u32\r\n * 188 conf_filter_bps u16\r\n * 190 backing_trade_fee_bps_short u16\r\n * 192 insurance_withdraw_deposits_only u8\r\n * 193 oracle_mode u8\r\n * 194 oracle_leg_count u8\r\n * 195 oracle_leg_flags u8\r\n * 196 invert u8\r\n * 197 _padding0 u8\r\n * 198 free_market_slot_count u16\r\n * 200 insurance_withdraw_cooldown_slots u64\r\n * 208 last_insurance_withdraw_slot u64\r\n * 216 max_staleness_secs u64\r\n * 224 hybrid_soft_stale_slots u64\r\n * 232 mark_ewma_e6 u64\r\n * 240 mark_ewma_last_slot u64\r\n * 248 mark_ewma_halflife_slots u64\r\n * 256 mark_min_fee u64\r\n * 264 oracle_target_price_e6 u64\r\n * 272 oracle_target_publish_time i64\r\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 400 oracle_leg_publish_times [i64;3] (24B)\r\n * 424 backing_trade_fee_policy_count u16\r\n * 426 backing_trade_fee_insurance_share_bps_long u16\r\n * 428 backing_trade_fee_insurance_share_bps_short u16\r\n * 430 fee_redirect_to_market_0_bps u16\r\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\r\n * 432 protocol_fee_authority [32]\r\n * 464 protocol_fee_accrued_atoms u128\r\n * 480 protocol_fee_withdrawn_atoms u128\r\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\r\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\r\n * 496 lp_fee_accrued_atoms u128\r\n * 512 lp_fee_withdrawn_atoms u128\r\n * 528 insurance_reserve_accrued_atoms u128\r\n * 544 insurance_reserve_withdrawn_atoms u128\r\n * 560 creator_share_bps u16\r\n * 562 lp_share_bps u16\r\n * 564 insurance_share_bps u16\r\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\r\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\r\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\r\n * Total: 576\r\n */\r\nexport interface WrapperConfigV17 {\r\n marketauth: PublicKey;\r\n collateralMint: PublicKey;\r\n secondaryCollateralMint: PublicKey;\r\n maintenanceFeePerSlot: bigint;\r\n permissionlessMarketInitFee: bigint;\r\n tradeFeeBps: bigint;\r\n permissionlessResolveStaleSlots: bigint;\r\n forceCloseDelaySlots: bigint;\r\n lastGoodOracleSlot: bigint;\r\n insuranceWithdrawDepositRemaining: bigint;\r\n insuranceWithdrawMaxBps: number;\r\n liquidationCrankerFeeShareBps: number;\r\n maintenanceCrankerFeeShareBps: number;\r\n backingTradeFeeBpsLong: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsShort: number;\r\n insuranceWithdrawDepositsOnly: number;\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n freeMarketSlotCount: number;\r\n insuranceWithdrawCooldownSlots: bigint;\r\n lastInsuranceWithdrawSlot: bigint;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n backingTradeFeePolicyCount: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n feeRedirectToMarket0Bps: number;\r\n /**\r\n * Destination pubkey for the protocol's accrued fee share. Set to a\r\n * hardcoded program-level constant at InitMarket; rotatable only via\r\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\r\n * by marketauth/insurance_authority/any creator-facing gate.\r\n */\r\n protocolFeeAuthority: PublicKey;\r\n /**\r\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\r\n * itself credited into any domain's insurance budget — tracks an\r\n * unbudgeted slice of header.insurance no insurance_operator can reach.\r\n */\r\n protocolFeeAccruedAtoms: bigint;\r\n /**\r\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\r\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\r\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\r\n */\r\n protocolFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\r\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\r\n * principal.\r\n *\r\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\r\n * it can be impaired by backing losses between crank and redemption.\r\n *\r\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\r\n * can never be cranked. Outstanding = accrued - withdrawn.\r\n */\r\n lpFeeAccruedAtoms: bigint;\r\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\r\n lpFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\r\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\r\n * bound stake pool's vault.\r\n *\r\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\r\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\r\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\r\n * unbudgeted by construction. Keepers should crank before resolution.\r\n */\r\n insuranceReserveAccruedAtoms: bigint;\r\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\r\n insuranceReserveWithdrawnAtoms: bigint;\r\n /**\r\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\r\n * (3600). Lands in insurance_domain_budget; claimed via\r\n * WithdrawInsuranceAsset (tag 57).\r\n */\r\n creatorShareBps: number;\r\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\r\n lpShareBps: number;\r\n /**\r\n * Insurance/staker share of T in bps. Default 1600, floor\r\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\r\n * split_trade_fee computes this leg as the remainder.\r\n */\r\n insuranceShareBps: number;\r\n /**\r\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\r\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\r\n *\r\n * This is the honest claimable balance a creator-claim UI should display.\r\n * Before the creator-fee-claim change the creator leg was credited into the\r\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\r\n * had no on-chain representation at all and a claim button was really a\r\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\r\n * alone.\r\n *\r\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\r\n * / insurance legs above, this is a single live balance: trades add to it and\r\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\r\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\r\n * claimable right now. (Forced by the 10-byte pad budget; see\r\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\r\n *\r\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\r\n * were explicit padding, so the value is well-defined rather than garbage,\r\n * and the counter simply accrues fresh after an in-place upgrade.\r\n */\r\n creatorFeeClaimableAtoms: bigint;\r\n}\r\n\r\n/**\r\n * Parse a v17 WrapperConfigV16 block from raw account data.\r\n *\r\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\r\n *\r\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\r\n * This function reads the 496-byte wrapper config block directly. It does NOT\r\n * validate the account header magic or version — callers must do that separately.\r\n *\r\n * @param data Raw bytes of the market group account.\r\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\r\n * @returns Parsed WrapperConfigV17 object.\r\n *\r\n * @example\r\n * ```ts\r\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\r\n * if (!accountInfo) throw new Error(\"account not found\");\r\n * const magic = readU64FromBytes(accountInfo.data, 0);\r\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\r\n * const config = parseWrapperConfigV17(accountInfo.data);\r\n * console.log(config.collateralMint.toBase58());\r\n * ```\r\n */\r\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\r\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = configOff;\r\n\r\n // Offsets from the WrapperConfigV16 offset table above\r\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\r\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\r\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\r\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\r\n const tradeFeeBps = readU64LE(data, b + 128);\r\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\r\n const forceCloseDelaySlots = readU64LE(data, b + 144);\r\n const lastGoodOracleSlot = readU64LE(data, b + 152);\r\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\r\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\r\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\r\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\r\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\r\n const unitScale = readU32LE(data, b + 184);\r\n const confFilterBps = readU16LE(data, b + 188);\r\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\r\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\r\n const oracleMode = readU8(data, b + 193);\r\n const oracleLegCount = readU8(data, b + 194);\r\n const oracleLegFlags = readU8(data, b + 195);\r\n const invert = readU8(data, b + 196);\r\n // _padding0 at b+197\r\n const freeMarketSlotCount = readU16LE(data, b + 198);\r\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\r\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\r\n const maxStalenessSecs = readU64LE(data, b + 216);\r\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\r\n const markEwmaE6 = readU64LE(data, b + 232);\r\n const markEwmaLastSlot = readU64LE(data, b + 240);\r\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\r\n const markMinFee = readU64LE(data, b + 256);\r\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\r\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\r\n\r\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\r\n const ORACLE_LEG_CAP = 3;\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\r\n }\r\n\r\n // oracle_leg_prices_e6: [u64;3] at b+376\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\r\n }\r\n\r\n // oracle_leg_publish_times: [i64;3] at b+400\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\r\n }\r\n\r\n // Tail policy fields at b+424\r\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\r\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\r\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\r\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\r\n\r\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\r\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\r\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\r\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\r\n\r\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\r\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\r\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\r\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\r\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\r\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\r\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\r\n const creatorShareBps = readU16LE(data, b + 560);\r\n const lpShareBps = readU16LE(data, b + 562);\r\n const insuranceShareBps = readU16LE(data, b + 564);\r\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\r\n\r\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\r\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\r\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\r\n\r\n return {\r\n marketauth,\r\n collateralMint,\r\n secondaryCollateralMint,\r\n maintenanceFeePerSlot,\r\n permissionlessMarketInitFee,\r\n tradeFeeBps,\r\n permissionlessResolveStaleSlots,\r\n forceCloseDelaySlots,\r\n lastGoodOracleSlot,\r\n insuranceWithdrawDepositRemaining,\r\n insuranceWithdrawMaxBps,\r\n liquidationCrankerFeeShareBps,\r\n maintenanceCrankerFeeShareBps,\r\n backingTradeFeeBpsLong,\r\n unitScale,\r\n confFilterBps,\r\n backingTradeFeeBpsShort,\r\n insuranceWithdrawDepositsOnly,\r\n oracleMode,\r\n oracleLegCount,\r\n oracleLegFlags,\r\n invert,\r\n freeMarketSlotCount,\r\n insuranceWithdrawCooldownSlots,\r\n lastInsuranceWithdrawSlot,\r\n maxStalenessSecs,\r\n hybridSoftStaleSlots,\r\n markEwmaE6,\r\n markEwmaLastSlot,\r\n markEwmaHalflifeSlots,\r\n markMinFee,\r\n oracleTargetPriceE6,\r\n oracleTargetPublishTime,\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n backingTradeFeePolicyCount,\r\n backingTradeFeeInsuranceShareBpsLong,\r\n backingTradeFeeInsuranceShareBpsShort,\r\n feeRedirectToMarket0Bps,\r\n protocolFeeAuthority,\r\n protocolFeeAccruedAtoms,\r\n protocolFeeWithdrawnAtoms,\r\n lpFeeAccruedAtoms,\r\n lpFeeWithdrawnAtoms,\r\n insuranceReserveAccruedAtoms,\r\n insuranceReserveWithdrawnAtoms,\r\n creatorShareBps,\r\n lpShareBps,\r\n insuranceShareBps,\r\n creatorFeeClaimableAtoms,\r\n };\r\n}\r\n\r\n/**\r\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\r\n *\r\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\r\n * 0 oracle_mode u8\r\n * 1 oracle_leg_count u8\r\n * 2 oracle_leg_flags u8\r\n * 3 invert u8\r\n * 4 unit_scale u32\r\n * 8 conf_filter_bps u16\r\n * 10 backing_trade_fee_bps_long u16\r\n * 12 backing_trade_fee_bps_short u16\r\n * 14 backing_trade_fee_insurance_share_bps_long u16\r\n * 16 backing_trade_fee_insurance_share_bps_short u16\r\n * 18 _padding0 [u8;6]\r\n * 24 insurance_authority [32]\r\n * 56 insurance_operator [32]\r\n * 88 backing_bucket_authority [32]\r\n * 120 oracle_authority [32]\r\n * 152 max_staleness_secs u64\r\n * 160 hybrid_soft_stale_slots u64\r\n * 168 mark_ewma_e6 u64\r\n * 176 mark_ewma_last_slot u64\r\n * 184 mark_ewma_halflife_slots u64\r\n * 192 mark_min_fee u64\r\n * 200 oracle_target_price_e6 u64\r\n * 208 oracle_target_publish_time i64\r\n * 216 last_good_oracle_slot u64\r\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 344 oracle_leg_publish_times [i64;3] (24B)\r\n * 368 asset_admin [32] ← v17 NEW\r\n * Total: 400\r\n */\r\nexport interface AssetOracleProfileV17 {\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsLong: number;\r\n backingTradeFeeBpsShort: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n insuranceAuthority: PublicKey;\r\n insuranceOperator: PublicKey;\r\n backingBucketAuthority: PublicKey;\r\n oracleAuthority: PublicKey;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n lastGoodOracleSlot: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n /** v17 NEW: asset_admin pubkey at offset 368. */\r\n assetAdmin: PublicKey;\r\n}\r\n\r\n/**\r\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\r\n *\r\n * @param data Raw bytes containing the profile block.\r\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\r\n * @returns Parsed AssetOracleProfileV17 object.\r\n */\r\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\r\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = profileOff;\r\n const ORACLE_LEG_CAP = 3;\r\n\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\r\n }\r\n\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\r\n }\r\n\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\r\n }\r\n\r\n return {\r\n oracleMode: readU8(data, b + 0),\r\n oracleLegCount: readU8(data, b + 1),\r\n oracleLegFlags: readU8(data, b + 2),\r\n invert: readU8(data, b + 3),\r\n unitScale: readU32LE(data, b + 4),\r\n confFilterBps: readU16LE(data, b + 8),\r\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\r\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\r\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\r\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\r\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\r\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\r\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\r\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\r\n maxStalenessSecs: readU64LE(data, b + 152),\r\n hybridSoftStaleSlots: readU64LE(data, b + 160),\r\n markEwmaE6: readU64LE(data, b + 168),\r\n markEwmaLastSlot: readU64LE(data, b + 176),\r\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\r\n markMinFee: readU64LE(data, b + 192),\r\n oracleTargetPriceE6: readU64LE(data, b + 200),\r\n oracleTargetPublishTime: readI64LE(data, b + 208),\r\n lastGoodOracleSlot: readU64LE(data, b + 216),\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\r\n };\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer contains a v17 percolator account.\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\r\n */\r\nexport function isV17Account(data: Uint8Array): boolean {\r\n if (data.length < 10) return false;\r\n const magic = readU64LE(data, 0);\r\n const version = readU16LE(data, 8);\r\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer is a v17 percolator MARKET account.\r\n *\r\n * Stricter than {@link isV17Account}: requires both that the account is a valid\r\n * v17 account (magic + version) AND that the kind byte at offset 10 is\r\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\r\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\r\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\r\n */\r\nexport function isV17MarketAccount(data: Uint8Array): boolean {\r\n if (data.length < V17_KIND_OFF + 1) return false;\r\n if (!isV17Account(data)) return false;\r\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\r\n}\r\n\r\n// =============================================================================\r\n// V17 OI parser\r\n// =============================================================================\r\n\r\n/**\r\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\r\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\r\n */\r\nconst V17_HEADER_INSURANCE_OFF = 301;\r\n\r\n/**\r\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\r\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\r\n */\r\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\r\n\r\n/**\r\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\r\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\r\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\r\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\r\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\r\n * oi_eff_short_q follows at 273 + 16 = 289\r\n */\r\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\r\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\r\n\r\n/**\r\n * Aggregated open-interest parsed from a v17 market group account.\r\n *\r\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\r\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\r\n * slots in the account and also returns per-asset breakdown.\r\n *\r\n * All quantities are in token micro-units (raw, not scaled by decimals).\r\n */\r\nexport interface V17MarketGroupOI {\r\n /** Group-level insurance reserve (u128, micro-units) */\r\n insuranceBalance: bigint;\r\n /** Sum of oi_eff_long_q across all asset slots */\r\n totalLongOiQ: bigint;\r\n /** Sum of oi_eff_short_q across all asset slots */\r\n totalShortOiQ: bigint;\r\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\r\n assets: Array<{\r\n assetIndex: number;\r\n oiEffLongQ: bigint;\r\n oiEffShortQ: bigint;\r\n }>;\r\n}\r\n\r\n/**\r\n * Parse open-interest fields from a v17 market group account.\r\n *\r\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\r\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\r\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\r\n * which follows the 512-byte wrapper T at the start of each slot).\r\n *\r\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\r\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\r\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\r\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are exact byte offsets.\r\n *\r\n * The absolute offsets below follow from the CURRENT wrapper layout —\r\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\r\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\r\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\r\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\r\n * - insurance: 592 + 301 = 893\r\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\r\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\r\n *\r\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\r\n * giving insurance @ 813. The CODE was always correct — it composes the named\r\n * constants — but the stated numbers were stale. Verified against the first real\r\n * v17 market on the new devnet deployment.)\r\n *\r\n * @param data Raw bytes of the v17 market group account.\r\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\r\n * @throws Error if the buffer is not a valid v17 market account or is too short.\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketGroupPk);\r\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\r\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\r\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\r\n * ```\r\n */\r\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\r\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\r\n const insuranceBalance = readU128LE(data, insuranceOff);\r\n\r\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\r\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\r\n const numSlots = Math.floor(\r\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\r\n );\r\n\r\n let totalLongOiQ = 0n;\r\n let totalShortOiQ = 0n;\r\n const assets: V17MarketGroupOI[\"assets\"] = [];\r\n\r\n for (let i = 0; i < numSlots; i++) {\r\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\r\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\r\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\r\n const longOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\r\n const shortOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\r\n\r\n // Guard against a truncated buffer (should not happen on well-formed accounts).\r\n if (shortOff + 16 > data.length) break;\r\n\r\n const oiEffLongQ = readU128LE(data, longOff);\r\n const oiEffShortQ = readU128LE(data, shortOff);\r\n\r\n totalLongOiQ += oiEffLongQ;\r\n totalShortOiQ += oiEffShortQ;\r\n\r\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\r\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\r\n }\r\n }\r\n\r\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\r\n}\r\n\r\n// =============================================================================\r\n// V17 account decoders (DESYNC fixes — new standalone account types)\r\n// =============================================================================\r\n\r\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\r\nconst V17_ACCOUNT_HEADER_LEN = 16;\r\nconst V17_KIND_PORTFOLIO = 2;\r\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\r\nconst V17_KIND_LP_REDEMPTION = 6;\r\n\r\nfunction assertV17StandaloneHeader(\r\n data: Uint8Array,\r\n parserName: string,\r\n expectedKind: number,\r\n): void {\r\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\r\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\r\n }\r\n const magic = readU64LE(data, 0);\r\n if (magic !== V17_MAGIC) {\r\n throw new Error(`${parserName}: invalid v17 magic`);\r\n }\r\n const version = readU16LE(data, 8);\r\n if (version !== V17_EXPECTED_VERSION) {\r\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\r\n }\r\n const kind = readU8(data, 10);\r\n if (kind !== expectedKind) {\r\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\r\n }\r\n}\r\n\r\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\r\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\r\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\r\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\r\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\r\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\r\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\r\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\r\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\r\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\r\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\r\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\r\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\r\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\r\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\r\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\r\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\r\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\r\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\r\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\r\n// PortfolioLegV16Account (144 bytes each):\r\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\r\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\r\nconst PF_LEG_SIZE = 144;\r\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\r\nconst PF_LEGS_COUNT = 16;\r\n// PortfolioSourceDomainV16Account (196 bytes each):\r\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\r\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\r\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\r\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\r\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\r\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\r\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\r\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\r\nconst PF_SOURCE_DOMAIN_SIZE = 196;\r\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\r\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\r\n// HealthCertV16Account (121 bytes):\r\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\r\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\r\n// CloseProgressLedgerV16Account (188 bytes):\r\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\r\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\r\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\r\n// ResolvedPayoutReceiptV16Account (66 bytes):\r\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\r\n\r\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\r\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\r\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\r\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\r\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\r\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\r\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\r\n// noted above (188) does not even match its own field breakdown (sums to 184; see\r\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\r\n// the same anchor-from-the-end offset).\r\nconst PF_MATCHER_CONFIG_LEN = 104;\r\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\r\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\r\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\r\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\r\n\r\n/** Per-leg decoded data returned by parsePortfolioV17. */\r\nexport interface PortfolioLegV17 {\r\n active: boolean;\r\n assetIndex: number;\r\n marketId: bigint;\r\n /** 0 = long, 1 = short */\r\n side: number;\r\n basisPosQ: bigint;\r\n aBasis: bigint;\r\n kSnap: bigint;\r\n fSnap: bigint;\r\n epochSnap: bigint;\r\n lossWeight: bigint;\r\n bSnap: bigint;\r\n bRem: bigint;\r\n bEpochSnap: bigint;\r\n bStale: boolean;\r\n stale: boolean;\r\n}\r\n\r\n/** Per source-domain slot returned by parsePortfolioV17. */\r\nexport interface PortfolioSourceDomainV17 {\r\n domain: number;\r\n sourceClaimMarketId: bigint;\r\n sourceClaimBoundNum: bigint;\r\n sourceClaimLienedNum: bigint;\r\n sourceClaimCounterpartyLienedNum: bigint;\r\n sourceClaimInsuranceLienedNum: bigint;\r\n sourceLienEffectiveReserved: bigint;\r\n sourceLienCounterpartyBackingNum: bigint;\r\n sourceLienInsuranceBackingNum: bigint;\r\n sourceLienFeeLastSlot: bigint;\r\n sourceClaimImpairedNum: bigint;\r\n sourceLienImpairedEffectiveReserved: bigint;\r\n sourceLienCapitalAtRiskFeeRevenue: bigint;\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\r\n}\r\n\r\n/** Decoded v17 PortfolioAccountV16Account. */\r\nexport interface PortfolioV17 {\r\n /** Market group this portfolio belongs to. */\r\n marketGroupId: PublicKey;\r\n /** Portfolio account identity pubkey (immutable PDA). */\r\n portfolioAccountId: PublicKey;\r\n /** Owner wallet pubkey from the provenance header. */\r\n provenanceOwner: PublicKey;\r\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\r\n owner: PublicKey;\r\n /** Collateral capital in atoms (u128). */\r\n capital: bigint;\r\n /** Unrealised P&L in atoms (i128). */\r\n pnl: bigint;\r\n /** Capital reserved for pending payout (u128). */\r\n reservedPnl: bigint;\r\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\r\n residualCrystallizedLossAtomsTotal: bigint;\r\n /** Genesis farming: cumulative spent principal atoms (u128). */\r\n residualSpentPrincipalAtomsTotal: bigint;\r\n /** Genesis farming: cumulative received atoms (u128). */\r\n residualReceivedAtomsTotal: bigint;\r\n /** Fee credits (i128, can be negative). */\r\n feeCredits: bigint;\r\n /** Cancel-deposit escrow holding (u128). */\r\n cancelDepositEscrow: bigint;\r\n /** Slot when fees were last accrued. */\r\n lastFeeSlot: bigint;\r\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\r\n activeBitmap: bigint;\r\n /** All 16 position leg slots (active or empty). */\r\n legs: PortfolioLegV17[];\r\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\r\n sourceDomains: PortfolioSourceDomainV17[];\r\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\r\n matcherProgram: PublicKey;\r\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\r\n matcherContext: PublicKey;\r\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\r\n matcherDelegate: PublicKey;\r\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\r\n matcherEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Parse a v17 PortfolioAccountV16Account from raw account data.\r\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\r\n *\r\n * @param data - Raw account bytes from `connection.getAccountInfo`.\r\n * @returns Decoded portfolio state.\r\n * @throws If data is too short or magic does not match.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(portfolioPubkey);\r\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\r\n * console.log('capital:', portfolio.capital);\r\n * ```\r\n */\r\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\r\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\r\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\r\n if (data.length < MIN_PORTFOLIO_BYTES) {\r\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\r\n }\r\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\r\n\r\n // Provenance header\r\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\r\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\r\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\r\n\r\n // Body fields\r\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\r\n const capital = readU128LE(data, PF_CAPITAL_OFF);\r\n const pnl = readI128LE(data, PF_PNL_OFF);\r\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\r\n\r\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\r\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\r\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\r\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\r\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\r\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\r\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\r\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\r\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\r\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\r\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\r\n\r\n // Legs\r\n const legs: PortfolioLegV17[] = [];\r\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\r\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\r\n if (data.length < b + PF_LEG_SIZE) break;\r\n legs.push({\r\n active: data[b] !== 0,\r\n assetIndex: readU32LE(data, b + 1),\r\n marketId: readU64LE(data, b + 5),\r\n side: data[b + 13],\r\n basisPosQ: readI128LE(data, b + 14),\r\n aBasis: readU128LE(data, b + 30),\r\n kSnap: readI128LE(data, b + 46),\r\n fSnap: readI128LE(data, b + 62),\r\n epochSnap: readU64LE(data, b + 78),\r\n lossWeight: readU128LE(data, b + 86),\r\n bSnap: readU128LE(data, b + 102),\r\n bRem: readU128LE(data, b + 118),\r\n bEpochSnap: readU64LE(data, b + 134),\r\n bStale: data[b + 142] !== 0,\r\n stale: data[b + 143] !== 0,\r\n });\r\n }\r\n\r\n // Source domains\r\n const sourceDomains: PortfolioSourceDomainV17[] = [];\r\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\r\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\r\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\r\n sourceDomains.push({\r\n domain: readU32LE(data, b + 0),\r\n sourceClaimMarketId: readU64LE(data, b + 4),\r\n sourceClaimBoundNum: readU128LE(data, b + 12),\r\n sourceClaimLienedNum: readU128LE(data, b + 28),\r\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\r\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\r\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\r\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\r\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\r\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\r\n sourceClaimImpairedNum: readU128LE(data, b + 132),\r\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\r\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\r\n });\r\n }\r\n\r\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\r\n : PublicKey.default;\r\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\r\n : PublicKey.default;\r\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\r\n : PublicKey.default;\r\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\r\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\r\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\r\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\r\n // for an account the program itself would refuse to operate on.\r\n let matcherEnabled = false;\r\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\r\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\r\n if (rawEnabled > 1n) {\r\n throw new Error(\r\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\r\n );\r\n }\r\n matcherEnabled = rawEnabled === 1n;\r\n }\r\n\r\n return {\r\n marketGroupId,\r\n portfolioAccountId,\r\n provenanceOwner,\r\n owner,\r\n capital,\r\n pnl,\r\n reservedPnl,\r\n residualCrystallizedLossAtomsTotal,\r\n residualSpentPrincipalAtomsTotal,\r\n residualReceivedAtomsTotal,\r\n feeCredits,\r\n cancelDepositEscrow,\r\n lastFeeSlot,\r\n activeBitmap,\r\n legs,\r\n sourceDomains,\r\n matcherProgram,\r\n matcherContext,\r\n matcherDelegate,\r\n matcherEnabled,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpVaultRegistryV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\r\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\r\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\r\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\r\n// _padding[6]+_reserved[16] = 160 bytes.\r\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\r\n\r\n/** Decoded v17 LpVaultRegistryV16 account. */\r\nexport interface LpVaultRegistryV17 {\r\n marketGroup: PublicKey;\r\n lpMint: PublicKey;\r\n totalLpSharesOutstanding: bigint;\r\n insuranceFeeSnapshotAtoms: bigint;\r\n feeDistributionTotalAtoms: bigint;\r\n epoch: bigint;\r\n redemptionCooldownSlots: bigint;\r\n feeShareBps: number;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n paused: boolean;\r\n version: number;\r\n bump: number;\r\n mintBump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\r\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP vault registry state.\r\n * @throws If data is shorter than 176 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(registryPubkey);\r\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\r\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\r\n * ```\r\n */\r\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\r\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\r\n throw new Error(\r\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\r\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\r\n totalLpSharesOutstanding: readU128LE(data, b + 64),\r\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\r\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\r\n epoch: readU64LE(data, b + 112),\r\n redemptionCooldownSlots: readU64LE(data, b + 120),\r\n feeShareBps: readU16LE(data, b + 128),\r\n oiReservationThresholdBps: readU16LE(data, b + 130),\r\n domain: readU16LE(data, b + 132),\r\n paused: data[b + 134] !== 0,\r\n version: data[b + 135],\r\n bump: data[b + 136],\r\n mintBump: data[b + 137],\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpRedemptionV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\r\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\r\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\r\n\r\n/** Decoded v17 LpRedemptionV16 account. */\r\nexport interface LpRedemptionV17 {\r\n registry: PublicKey;\r\n redeemer: PublicKey;\r\n /** LP shares requested for redemption (u128). */\r\n shares: bigint;\r\n /** Slot when RequestRedeemLpShares was called. */\r\n requestSlot: bigint;\r\n version: number;\r\n bump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpRedemptionV16 account from raw bytes.\r\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP redemption request state.\r\n * @throws If data is shorter than 112 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(redemptionPubkey);\r\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\r\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\r\n * ```\r\n */\r\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\r\n if (data.length < LP_REDEMPTION_TOTAL) {\r\n throw new Error(\r\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\r\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\r\n shares: readU128LE(data, b + 64),\r\n requestSlot: readU64LE(data, b + 80),\r\n version: data[b + 88],\r\n bump: data[b + 89],\r\n };\r\n}\r\n\r\n/**\r\n * Parse all used accounts.\r\n */\r\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\r\n const indices = parseUsedIndices(data);\r\n const maxIdx = maxAccountIndex(data.length);\r\n const validIndices = indices.filter(idx => idx < maxIdx);\r\n const droppedCount = indices.length - validIndices.length;\r\n if (droppedCount > 0) {\r\n console.warn(\r\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\r\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\r\n );\r\n }\r\n return validIndices.map(idx => ({\r\n idx,\r\n account: parseAccount(data, idx),\r\n }));\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Encode a u16 as a 2-byte little-endian buffer.\r\n * Used for PDA seed segments that include a domain/index as u16 LE.\r\n */\r\nfunction u16LE(value: number): Uint8Array {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isInteger(value) ||\r\n value < 0 ||\r\n value > 0xffff\r\n ) {\r\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive vault authority PDA.\r\n * Seeds: [\"vault\", slab_key]\r\n *\r\n * Mirrors `derive_vault_authority(program_id, market_key)` in\r\n * `percolator-prog/src/v16_program.rs:17339-17341`.\r\n */\r\nexport function deriveVaultAuthority(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"vault\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * SPL Associated Token Account program.\r\n *\r\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\r\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\r\n */\r\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\r\n);\r\n\r\n/**\r\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\r\n *\r\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\r\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\r\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\r\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\r\n * ATA's middle seed is always this program id.\r\n */\r\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n);\r\n\r\n/**\r\n * Derive the CANONICAL vault token account for a market + collateral mint.\r\n *\r\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\r\n *\r\n * ```text\r\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\r\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\r\n * ```\r\n *\r\n * Mirrors `canonical_vault_address(vault_authority, mint)`\r\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\r\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\r\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\r\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\r\n * without it an attacker could route deposits to a second `vault_authority`-owned account\r\n * and strand honest withdrawals against the canonical one.\r\n *\r\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\r\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\r\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\r\n * address with a detected token program would produce a key the program rejects with\r\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\r\n *\r\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\r\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\r\n * token path.\r\n *\r\n * @param programId - The Percolator wrapper program ID (the market's owner).\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\r\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketData);\r\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * ```\r\n */\r\nexport function deriveCanonicalVault(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\r\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\r\n}\r\n\r\n/**\r\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\r\n *\r\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\r\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\r\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\r\n *\r\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\r\n * @param mint - The market's collateral mint.\r\n * @returns `[vaultTokenAccount, bump]`\r\n *\r\n * @example\r\n * ```ts\r\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\r\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\r\n * ```\r\n */\r\nexport function deriveCanonicalVaultForAuthority(\r\n vaultAuthority: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n vaultAuthority.toBytes(),\r\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n ASSOCIATED_TOKEN_PROGRAM_ID\r\n );\r\n}\r\n\r\n/** Both halves of a market's vault, as required by tags 84 and 87. */\r\nexport interface MarketVaultAccounts {\r\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\r\n vaultAuthority: PublicKey;\r\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\r\n vaultAuthorityBump: number;\r\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\r\n vaultToken: PublicKey;\r\n /** Bump for `vaultToken`. */\r\n vaultTokenBump: number;\r\n /** The token program that must be passed alongside — always legacy SPL Token. */\r\n tokenProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\r\n *\r\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\r\n * the vault token account, the vault authority PDA and the token program as three separate\r\n * accounts that must agree with one another; deriving them together makes disagreement\r\n * impossible.\r\n *\r\n * Account positions:\r\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\r\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\r\n *\r\n * @param programId - The Percolator wrapper program ID.\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint.\r\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\r\n *\r\n * @example\r\n * ```ts\r\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * const keys = [\r\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\r\n * { pubkey: marketPk, isSigner: false, isWritable: true },\r\n * { pubkey: destToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\r\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\r\n * ];\r\n * ```\r\n */\r\nexport function deriveMarketVaultAccounts(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): MarketVaultAccounts {\r\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\r\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\r\n vaultAuthority,\r\n mint\r\n );\r\n return {\r\n vaultAuthority,\r\n vaultAuthorityBump,\r\n vaultToken,\r\n vaultTokenBump,\r\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\r\n };\r\n}\r\n\r\n/**\r\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\r\n * Seeds: [\"lp_vault_mint\", slab_key]\r\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\r\n */\r\nexport function deriveInsuranceLpMint(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\nconst LP_INDEX_U16_MAX = 0xffff;\r\n\r\n/**\r\n * Derive LP PDA for TradeCpi.\r\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\r\n */\r\nexport function deriveLpPda(\r\n programId: PublicKey,\r\n slab: PublicKey,\r\n lpIdx: number\r\n): [PublicKey, number] {\r\n if (\r\n typeof lpIdx !== \"number\" ||\r\n !Number.isInteger(lpIdx) ||\r\n lpIdx < 0 ||\r\n lpIdx > LP_INDEX_U16_MAX\r\n ) {\r\n throw new Error(\r\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\r\n );\r\n }\r\n const idxBuf = new Uint8Array(2);\r\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DEX Program IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/** PumpSwap AMM program ID. */\r\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\r\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\r\n);\r\n\r\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\r\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\r\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\r\n);\r\n\r\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\r\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\r\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth Push Oracle\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Pyth Push Oracle program on mainnet. */\r\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\r\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Creator Lock PDA (PERC-627)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Seed used to derive the creator lock PDA.\r\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\r\n */\r\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\r\n\r\n/**\r\n * Derive the creator lock PDA for a given slab.\r\n * Seeds: [\"creator_lock\", slab_key]\r\n *\r\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\r\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\r\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\r\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\r\n *\r\n * @param programId - The percolator program ID.\r\n * @param slab - The slab (market) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * ```\r\n */\r\nexport function deriveCreatorLockPda(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// LP Vault PDAs (v17 — tags 74-80)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the LP Vault registry PDA.\r\n * Seeds: [\"lp_vault\", marketGroup]\r\n *\r\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\r\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\r\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\r\n *\r\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpVaultRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP redemption ticket PDA for a specific redeemer.\r\n * Seeds: [\"lp_redemption\", registry, redeemer]\r\n *\r\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\r\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\r\n * @param redeemer - The wallet public key of the redeemer.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\r\n * ```\r\n */\r\nexport function deriveLpRedemption(\r\n programId: PublicKey,\r\n registry: PublicKey,\r\n redeemer: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_redemption\"),\r\n registry.toBytes(),\r\n redeemer.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP backing-domain ledger PDA.\r\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\r\n *\r\n * Required by: DepositToLpVault (tag 75) at accounts[7],\r\n * LpVaultCrankFees (tag 78) at accounts[3].\r\n *\r\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\r\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\r\n * (line 3127) — domain is encoded as 2-byte little-endian.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\r\n * ```\r\n */\r\nexport function deriveLpBackingLedger(\r\n programId: PublicKey,\r\n marketGroup: PublicKey,\r\n domainIdx: number\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_backing_ledger\"),\r\n marketGroup.toBytes(),\r\n u16LE(domainIdx),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP escrow SPL token account PDA.\r\n * Seeds: [\"lp_escrow\", marketGroup]\r\n *\r\n * The escrow is owned by the registry PDA and holds LP tokens during the\r\n * redemption window. Required by ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\r\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpEscrow(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NFT Registry PDA (v17 — tag 73)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the per-market NFT program-id registry PDA.\r\n * Seeds: [\"nft_registry\", marketGroup]\r\n *\r\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\r\n * (TransferPortfolioOwnership, tag 72).\r\n *\r\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\r\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveNftRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the matcher delegate PDA.\r\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\r\n * (all six seed segments are 32-byte public keys)\r\n *\r\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\r\n * The program signs CPI calls to the external matcher program using this PDA.\r\n *\r\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\r\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param market - The market (slab) public key.\r\n * @param accountB - The maker/LP portfolio account public key.\r\n * @param accountBOwner - The owner of accountB.\r\n * @param matcherProg - The external matcher program public key.\r\n * @param matcherCtx - The matcher context account public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [delegatePda] = deriveMatcherDelegate(\r\n * PROGRAM_ID,\r\n * marketKey,\r\n * accountBKey,\r\n * accountBOwnerKey,\r\n * matcherProgKey,\r\n * matcherCtxKey,\r\n * );\r\n * ```\r\n */\r\nexport function deriveMatcherDelegate(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n accountB: PublicKey,\r\n accountBOwner: PublicKey,\r\n matcherProg: PublicKey,\r\n matcherCtx: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"matcher\"),\r\n market.toBytes(),\r\n accountB.toBytes(),\r\n accountBOwner.toBytes(),\r\n matcherProg.toBytes(),\r\n matcherCtx.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\r\nconst PYTH_FEED_ID_HEX_LEN = 64;\r\n\r\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\r\n let s = feedIdHex.trim();\r\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\r\n s = s.slice(2);\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Derive the Pyth Push Oracle PDA for a given feed ID.\r\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\r\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\r\n */\r\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\r\n const normalized = normalizePythFeedIdHex(feedIdHex);\r\n if (!FEED_HEX_RE.test(normalized)) {\r\n throw new Error(\r\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\r\n }\r\n const feedId = new Uint8Array(32);\r\n for (let i = 0; i < 32; i++) {\r\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\r\n }\r\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\r\n return PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n PYTH_PUSH_ORACLE_PROGRAM_ID,\r\n );\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n getAssociatedTokenAddress,\r\n getAssociatedTokenAddressSync,\r\n getAccount,\r\n Account,\r\n TOKEN_PROGRAM_ID,\r\n} from \"@solana/spl-token\";\r\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\r\n\r\n/**\r\n * Get the associated token address for an owner and mint.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport async function getAta(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Synchronous version of getAta.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport function getAtaSync(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): PublicKey {\r\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Fetch token account info.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n * Throws if account doesn't exist.\r\n */\r\nexport async function fetchTokenAccount(\r\n connection: Connection,\r\n address: PublicKey,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAccount(connection, address, undefined, tokenProgramId);\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n parseHeader,\r\n parseConfig,\r\n parseParams,\r\n detectSlabLayout,\r\n isV17MarketAccount,\r\n parseWrapperConfigV17,\r\n SLAB_TIERS_V1M,\r\n SLAB_TIERS_V1M2,\r\n SLAB_TIERS_V2,\r\n SLAB_TIERS_V_ADL,\r\n SLAB_TIERS_V12_1,\r\n SLAB_TIERS_V12_15,\r\n SLAB_TIERS_V12_17,\r\n SLAB_TIERS_V12_19,\r\n SLAB_TIERS_V_SETDEXPOOL,\r\n type SlabHeader,\r\n type MarketConfig,\r\n type EngineState,\r\n type RiskParams,\r\n type SlabLayout,\r\n type WrapperConfigV17,\r\n} from \"./slab.js\";\r\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\r\nimport { type Network } from \"../config/program-ids.js\";\r\n\r\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\r\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\r\n/** V0 bitmap offset within engine struct (deployed devnet program) */\r\nconst ENGINE_BITMAP_OFF_V0 = 320;\r\n\r\n/**\r\n * A discovered Percolator market from on-chain program accounts.\r\n */\r\nexport interface DiscoveredMarket {\r\n slabAddress: PublicKey;\r\n /** The program that owns this slab account */\r\n programId: PublicKey;\r\n /**\r\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\r\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\r\n */\r\n header: SlabHeader;\r\n /**\r\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\r\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\r\n */\r\n config: MarketConfig;\r\n /**\r\n * v12.x engine state (bitmap, account counts).\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n engine: EngineState;\r\n /**\r\n * v12.x risk parameters.\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n params: RiskParams;\r\n /**\r\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\r\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\r\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\r\n * Absent for v12 slab accounts.\r\n *\r\n * Use `isV17Market(m)` to narrow the type:\r\n * ```ts\r\n * if (m.configV17) {\r\n * console.log(m.configV17.collateralMint.toBase58());\r\n * }\r\n * ```\r\n */\r\n configV17?: WrapperConfigV17;\r\n}\r\n\r\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\r\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\r\n * These are the first 8 bytes of every v17 percolator-owned market group account.\r\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\r\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\r\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\r\n */\r\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\r\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\r\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\r\n *\r\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\r\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\r\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\r\n *\r\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\r\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\r\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\r\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\r\n *\r\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\r\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\r\n * See GH #1109, GH #1112.\r\n *\r\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\r\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\r\n */\r\n/**\r\n * Default slab tiers for the current mainnet program (v12.17).\r\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\r\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\r\n */\r\nexport const SLAB_TIERS = {\r\n small: SLAB_TIERS_V12_17[\"small\"],\r\n medium: SLAB_TIERS_V12_17[\"medium\"],\r\n large: SLAB_TIERS_V12_17[\"large\"],\r\n} as const;\r\n\r\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\r\nexport const SLAB_TIERS_V0 = {\r\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\r\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\r\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\r\n} as const;\r\n\r\n/**\r\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\r\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\r\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\r\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\r\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\r\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\r\n * micro = 17,064 (64 slots)\r\n * small = 65,088 (256 slots)\r\n * medium = 257,184 (1,024 slots)\r\n * large = 1,025,568 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D = {\r\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\r\n} as const;\r\n\r\n/**\r\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\r\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\r\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\r\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\r\n * micro = 17,080 (64 slots)\r\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\r\n * medium = 257,200 (1,024 slots)\r\n * large = 1,025,584 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D_LEGACY = {\r\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\r\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\r\n} as const;\r\n\r\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\r\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\r\n */\r\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\r\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\r\n\r\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\r\n\r\n/** Calculate slab data size for arbitrary account count.\r\n *\r\n * Layout (SBF, u128 align = 8):\r\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\r\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\r\n * + bitmap: ceil(N/64)*8\r\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\r\n * + next_free: N*2\r\n * + pad to 8-byte alignment for Account array\r\n * + accounts: N*248\r\n *\r\n * Must match the on-chain program's SLAB_LEN exactly.\r\n */\r\nexport function slabDataSize(maxAccounts: number): number {\r\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\r\n const ENGINE_OFF_V0 = 480;\r\n const ENGINE_BITMAP_OFF_V0 = 320;\r\n const ACCOUNT_SIZE_V0 = 240;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\r\n}\r\n\r\n/**\r\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\r\n *\r\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\r\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\r\n * difference at high account counts or a post-PERC-118 struct addition in the\r\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\r\n * verified on-chain) over this formula for production use.\r\n */\r\nexport function slabDataSizeV1(maxAccounts: number): number {\r\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\r\n const ENGINE_BITMAP_OFF_V1 = 656;\r\n const ACCOUNT_SIZE_V1 = 248;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\r\n}\r\n\r\n/**\r\n * Validate that a slab data size matches one of the known tier sizes.\r\n * Use this to catch tier↔program mismatches early (PERC-277).\r\n *\r\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\r\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\r\n * @returns true if sizes match, false if there's a mismatch\r\n */\r\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\r\n return dataSize === programSlabLen;\r\n}\r\n\r\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\r\nconst ALL_SLAB_SIZES = [\r\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\r\n];\r\n\r\n/** Legacy constant for backward compat */\r\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\r\n\r\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\r\nconst HEADER_SLICE_LENGTH = 1940;\r\n\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\r\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\r\n *\r\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\r\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\r\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\r\n */\r\nexport function parseEngineLight(\r\n data: Uint8Array,\r\n layout: SlabLayout | null,\r\n maxAccounts: number = 4096,\r\n): EngineState {\r\n const isV0 = !layout || layout.version === 0;\r\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\r\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\r\n\r\n const minLen = base + bitmapOff;\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\r\n }\r\n\r\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\r\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\r\n\r\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\r\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\r\n\r\n if (isV0) {\r\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\r\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\r\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\r\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\r\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\r\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\r\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\r\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: readU128LE(data, base + 32),\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + 104),\r\n fundingIndexQpbE6: readI128LE(data, base + 112),\r\n lastFundingSlot: readU64LE(data, base + 128),\r\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: readU64LE(data, base + 144),\r\n maxCrankStalenessSlots: readU64LE(data, base + 152),\r\n totalOpenInterest: readU128LE(data, base + 160),\r\n longOi: 0n,\r\n shortOi: 0n,\r\n cTot: readU128LE(data, base + 176),\r\n pnlPosTot: readU128LE(data, base + 192),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: readU16LE(data, base + 208),\r\n gcCursor: readU16LE(data, base + 210),\r\n lastSweepStartSlot: readU64LE(data, base + 216),\r\n lastSweepCompleteSlot: readU64LE(data, base + 224),\r\n crankCursor: readU16LE(data, base + 232),\r\n sweepStartIdx: readU16LE(data, base + 234),\r\n lifetimeLiquidations: readU64LE(data, base + 240),\r\n lifetimeForceCloses: readU64LE(data, base + 248),\r\n netLpPos: readI128LE(data, base + 256),\r\n lpSumAbs: readU128LE(data, base + 272),\r\n lpMaxAbs: readU128LE(data, base + 288),\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n, // V0 engine has no mark_price field\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\r\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\r\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\r\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\r\n // (the currently-deployed mainnet tier line) were being routed through this branch's\r\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\r\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\r\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\r\n // per the layout-driven branch's own comment below, which already documents that it\r\n // covers V12_15/17/19 — that was the intended path all along.\r\n\r\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\r\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\r\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\r\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\r\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\r\n // that share engineOff=640 but have different internal struct sizes.\r\n if (layout !== null) {\r\n const l = layout;\r\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\r\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\r\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\r\n // struct for that tier has no such field, and `base + (-1)` would read\r\n // garbage straddling the byte before the engine region rather than failing.\r\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\r\n // below goes through these instead of reading the offset directly.\r\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\r\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\r\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\r\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\r\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + l.engineInsuranceOff),\r\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\r\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\r\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\r\n },\r\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\r\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\r\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\r\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\r\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\r\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\r\n : readI128LE(data, base + l.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\r\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\r\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\r\n totalOpenInterest: u128At(l.engineTotalOiOff),\r\n longOi: u128At(l.engineLongOiOff),\r\n shortOi: u128At(l.engineShortOiOff),\r\n cTot: readU128LE(data, base + l.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: u16At(l.engineLiqCursorOff),\r\n gcCursor: u16At(l.engineGcCursorOff),\r\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\r\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\r\n crankCursor: u16At(l.engineCrankCursorOff),\r\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\r\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\r\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\r\n netLpPos: i128At(l.engineNetLpPosOff),\r\n lpSumAbs: u128At(l.engineLpSumAbsOff),\r\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\r\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\r\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\r\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\r\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\r\n markPriceE6: u64At(l.engineMarkPriceOff),\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // layout === null: unrecognized slab format — callers should have skipped via the\r\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\r\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\r\n}\r\n\r\n/** Options for `discoverMarkets`. */\r\nexport interface DiscoverMarketsOptions {\r\n /**\r\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\r\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\r\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\r\n * Default: false (preserves original parallel behaviour).\r\n *\r\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\r\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\r\n */\r\n sequential?: boolean;\r\n /**\r\n * Delay in ms between sequential tier queries (only used when sequential=true).\r\n * Default: 200 ms.\r\n */\r\n interTierDelayMs?: number;\r\n /**\r\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\r\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\r\n */\r\n rateLimitBackoffMs?: number[];\r\n\r\n /**\r\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\r\n * at once to avoid accidental RPC storms from client code.\r\n *\r\n * Default: 6\r\n */\r\n maxParallelTiers?: number;\r\n\r\n /**\r\n * Hard cap on how many tier dataSize queries are attempted.\r\n * Default: all known tiers.\r\n */\r\n maxTierQueries?: number;\r\n\r\n /**\r\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\r\n *\r\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\r\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\r\n * mainnet RPCs that reject `getProgramAccounts`).\r\n *\r\n * The API returns slab addresses which are then fetched on-chain via\r\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\r\n *\r\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * });\r\n * ```\r\n */\r\n apiBaseUrl?: string;\r\n\r\n /**\r\n * Timeout in ms for the API fallback HTTP request.\r\n * Only used when `apiBaseUrl` is set.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n apiTimeoutMs?: number;\r\n\r\n /**\r\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\r\n *\r\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\r\n * `discoverMarkets` will fall back to a bundled static list of known slab\r\n * addresses for the specified network. The addresses are fetched on-chain\r\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * If not set, tier-3 fallback is disabled.\r\n *\r\n * The static list can be extended at runtime via `registerStaticMarkets()`.\r\n *\r\n * @see {@link registerStaticMarkets} to add addresses at runtime\r\n * @see {@link getStaticMarkets} to inspect the current static list\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * network: \"mainnet\", // enables tier-3 static fallback\r\n * });\r\n * ```\r\n */\r\n network?: Network;\r\n}\r\n\r\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\r\nfunction isRateLimitError(err: unknown): boolean {\r\n if (!err) return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return (\r\n msg.includes(\"429\") ||\r\n msg.toLowerCase().includes(\"rate limit\") ||\r\n msg.toLowerCase().includes(\"too many requests\")\r\n );\r\n}\r\n\r\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\r\nfunction withJitter(delayMs: number): number {\r\n const half = Math.floor(delayMs / 2);\r\n return half + Math.floor(Math.random() * (delayMs - half + 1));\r\n}\r\n\r\n/**\r\n * Discover all Percolator markets owned by the given program.\r\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\r\n *\r\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\r\n */\r\nexport async function discoverMarkets(\r\n connection: Connection,\r\n programId: PublicKey,\r\n options: DiscoverMarketsOptions = {},\r\n): Promise {\r\n const {\r\n sequential = false,\r\n interTierDelayMs = 200,\r\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\r\n maxParallelTiers = 6,\r\n } = options;\r\n\r\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\r\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\r\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\r\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\r\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\r\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\r\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\r\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\r\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\r\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\r\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\r\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\r\n //\r\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\r\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\r\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\r\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\r\n const ALL_TIERS_RAW = [\r\n ...Object.values(SLAB_TIERS), // v12.17 (default)\r\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\r\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\r\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\r\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\r\n ...Object.values(SLAB_TIERS_V0),\r\n ...Object.values(SLAB_TIERS_V1D),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\r\n ...Object.values(SLAB_TIERS_V2),\r\n ...Object.values(SLAB_TIERS_V1M),\r\n ...Object.values(SLAB_TIERS_V1M2),\r\n ...Object.values(SLAB_TIERS_V_ADL),\r\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\r\n ];\r\n const tierBySize = new Map();\r\n for (const tier of ALL_TIERS_RAW) {\r\n const existing = tierBySize.get(tier.dataSize);\r\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\r\n tierBySize.set(tier.dataSize, tier);\r\n }\r\n }\r\n const ALL_TIERS = [...tierBySize.values()];\r\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\r\n let rawAccounts: RawEntry[] = [];\r\n\r\n /**\r\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\r\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\r\n */\r\n async function fetchTierWithRetry(\r\n tier: { dataSize: number; maxAccounts: number },\r\n ): Promise {\r\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\r\n try {\r\n const results = await connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\r\n } catch (err) {\r\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\r\n const delay = withJitter(rateLimitBackoffMs[attempt]);\r\n console.warn(\r\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\r\n );\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n // Non-429 or exhausted retries\r\n console.warn(\r\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n return [];\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\r\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\r\n\r\n // Avoid accidental `0`/negative or NaN causing infinite loops.\r\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\r\n\r\n try {\r\n if (sequential) {\r\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\r\n for (let i = 0; i < tiersToQuery.length; i++) {\r\n const tier = tiersToQuery[i];\r\n const entries = await fetchTierWithRetry(tier);\r\n rawAccounts.push(...entries);\r\n if (i < tiersToQuery.length - 1) {\r\n await new Promise(r => setTimeout(r, interTierDelayMs));\r\n }\r\n }\r\n } else {\r\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\r\n // getProgramAccounts calls at once from a single client call.\r\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\r\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\r\n const queries = chunk.map(tier =>\r\n connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n }).then(results =>\r\n results.map(entry => ({\r\n ...entry,\r\n maxAccounts: tier.maxAccounts,\r\n dataSize: tier.dataSize,\r\n })),\r\n ),\r\n );\r\n\r\n const results = await Promise.allSettled(queries);\r\n for (const result of results) {\r\n if (result.status === \"fulfilled\") {\r\n for (const entry of result.value) {\r\n rawAccounts.push(entry as RawEntry);\r\n }\r\n } else {\r\n console.warn(\r\n \"[discoverMarkets] Tier query rejected:\",\r\n result.reason instanceof Error ? result.reason.message : result.reason,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\r\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\r\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\r\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\r\n try {\r\n const v17Results = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\r\n encoding: \"base64\",\r\n },\r\n },\r\n ],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n for (const e of v17Results) {\r\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\r\n }\r\n } catch {\r\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\r\n }\r\n\r\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\r\n // account size changed; RPC returns no error, so we must fallback on empty results too.\r\n if (rawAccounts.length === 0) {\r\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\r\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\r\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\r\n err instanceof Error ? err.message : err,\r\n );\r\n try {\r\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n } catch (memcmpErr) {\r\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\r\n console.warn(\r\n \"[discoverMarkets] memcmp fallback also failed:\",\r\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\r\n );\r\n }\r\n }\r\n\r\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\r\n // rejects it) and an API base URL is configured, fall back to the REST API to\r\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\r\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\r\n console.warn(\r\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\r\n );\r\n try {\r\n const apiResult = await discoverMarketsViaApi(\r\n connection,\r\n programId,\r\n options.apiBaseUrl,\r\n { timeoutMs: options.apiTimeoutMs },\r\n );\r\n if (apiResult.length > 0) {\r\n return apiResult;\r\n }\r\n // API returned 0 markets — fall through to tier 3\r\n console.warn(\r\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\r\n );\r\n } catch (apiErr) {\r\n console.warn(\r\n \"[discoverMarkets] API fallback also failed:\",\r\n apiErr instanceof Error ? apiErr.message : apiErr,\r\n );\r\n // Fall through to tier 3\r\n }\r\n }\r\n\r\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\r\n // the REST API failed (or returned 0 results) and a network hint is provided,\r\n // use the bundled static market list as a last-resort address directory.\r\n if (rawAccounts.length === 0 && options.network) {\r\n const staticEntries = getStaticMarkets(options.network);\r\n if (staticEntries.length > 0) {\r\n console.warn(\r\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\r\n );\r\n try {\r\n return await discoverMarketsViaStaticBundle(\r\n connection,\r\n programId,\r\n staticEntries,\r\n );\r\n } catch (staticErr) {\r\n console.warn(\r\n \"[discoverMarkets] Static bundle fallback also failed:\",\r\n staticErr instanceof Error ? staticErr.message : staticErr,\r\n );\r\n // Fall through to return empty array\r\n }\r\n } else {\r\n console.warn(\r\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\r\n );\r\n }\r\n }\r\n\r\n const accounts = rawAccounts;\r\n\r\n const markets: DiscoveredMarket[] = [];\r\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\r\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\r\n const seenPubkeys = new Set();\r\n\r\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\r\n const pkStr = pubkey.toBase58();\r\n if (seenPubkeys.has(pkStr)) continue;\r\n seenPubkeys.add(pkStr);\r\n const data = new Uint8Array(account.data);\r\n\r\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\r\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\r\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\r\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\r\n // memcmp fallback or if the account happens to match a tier size by coincidence.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\r\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\r\n // — are not mis-parsed as markets.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) continue;\r\n\r\n // Detect layout from actual slab size — not slice length — so parse functions\r\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\r\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\r\n const layout = detectSlabLayout(dataSize, data);\r\n\r\n if (!layout) {\r\n console.warn(\r\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n/**\r\n * Options for `getMarketsByAddress`.\r\n */\r\nexport interface GetMarketsByAddressOptions {\r\n /**\r\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\r\n * Solana limits a single call to 100 accounts; callers may lower this\r\n * to reduce per-request payload size or avoid 429s.\r\n *\r\n * Default: 100 (Solana maximum).\r\n */\r\n batchSize?: number;\r\n\r\n /**\r\n * Delay in ms between batches when the address list exceeds `batchSize`.\r\n * Helps avoid rate-limiting on public RPCs.\r\n *\r\n * Default: 0 (no delay).\r\n */\r\n interBatchDelayMs?: number;\r\n}\r\n\r\n/**\r\n * Fetch and parse Percolator markets by their known slab addresses.\r\n *\r\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\r\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\r\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\r\n *\r\n * Callers must already know the market slab addresses (e.g. from an indexer,\r\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param programId - The Percolator program that owns these slabs\r\n * @param addresses - Array of slab account public keys to fetch\r\n * @param options - Optional batching/delay configuration\r\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection, PublicKey } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const slabs = [\r\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n * // ... more known slab addresses\r\n * ];\r\n *\r\n * const markets = await getMarketsByAddress(connection, programId, slabs);\r\n * console.log(`Found ${markets.length} markets`);\r\n * ```\r\n */\r\nexport async function getMarketsByAddress(\r\n connection: Connection,\r\n programId: PublicKey,\r\n addresses: PublicKey[],\r\n options: GetMarketsByAddressOptions = {},\r\n): Promise {\r\n if (addresses.length === 0) return [];\r\n\r\n const {\r\n batchSize = 100,\r\n interBatchDelayMs = 0,\r\n } = options;\r\n\r\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\r\n\r\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\r\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\r\n const fetched: AccountResult[] = [];\r\n\r\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\r\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\r\n\r\n const response = await connection.getMultipleAccountsInfo(batch);\r\n\r\n for (let i = 0; i < batch.length; i++) {\r\n const info = response[i];\r\n if (info && info.data) {\r\n if (!info.owner.equals(programId)) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\r\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\r\n );\r\n continue;\r\n }\r\n fetched.push({ pubkey: batch[i], data: info.data });\r\n }\r\n }\r\n\r\n // Inter-batch delay to avoid rate-limiting\r\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\r\n await new Promise(r => setTimeout(r, interBatchDelayMs));\r\n }\r\n }\r\n\r\n // Parse each account into a DiscoveredMarket\r\n const markets: DiscoveredMarket[] = [];\r\n\r\n for (const entry of fetched) {\r\n if (!entry) continue;\r\n const { pubkey, data: rawData } = entry;\r\n const data = new Uint8Array(rawData);\r\n\r\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\r\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n // v17 accounts have no slab header/config/engine/params; supply defaults so\r\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\r\n // to detect a v17 market.\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n // Validate v12 magic bytes\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\r\n );\r\n continue;\r\n }\r\n\r\n // Detect layout from full account data length\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// REST API-based market discovery (GH#59 / PERC-8424)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Shape of a single market entry returned by the Percolator REST API\r\n * (`GET /markets`). Only the fields needed for discovery are typed here;\r\n * the full API response may contain additional statistics fields.\r\n */\r\nexport interface ApiMarketEntry {\r\n slab_address: string;\r\n symbol?: string;\r\n name?: string;\r\n decimals?: number;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Options for {@link discoverMarketsViaApi}. */\r\nexport interface DiscoverMarketsViaApiOptions {\r\n /**\r\n * Timeout in ms for the HTTP request to the REST API.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n timeoutMs?: number;\r\n\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets by first querying the REST API for slab addresses,\r\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\r\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\r\n *\r\n * This is the recommended discovery path for mainnet users who do not have a\r\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\r\n *\r\n * The REST API acts as an address directory only — all market data is verified\r\n * on-chain via `getMarketsByAddress`, so the caller gets the same\r\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\r\n *\r\n * @param connection - Solana RPC connection (any endpoint, including public)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param apiBaseUrl - Base URL of the Percolator REST API\r\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\r\n * @param options - Optional timeout and on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts discovered via the API\r\n *\r\n * @example\r\n * ```ts\r\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const markets = await discoverMarketsViaApi(\r\n * connection,\r\n * programId,\r\n * \"https://percolatorlaunch.com/api\",\r\n * );\r\n * console.log(`Discovered ${markets.length} markets via API fallback`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaApi(\r\n connection: Connection,\r\n programId: PublicKey,\r\n apiBaseUrl: string,\r\n options: DiscoverMarketsViaApiOptions = {},\r\n): Promise {\r\n const { timeoutMs = 10_000, onChainOptions } = options;\r\n\r\n // Normalise base URL — strip trailing slash to avoid double-slash in path\r\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\r\n const url = `${base}/markets`;\r\n\r\n // Fetch market list from REST API\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: \"GET\",\r\n headers: { Accept: \"application/json\" },\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\r\n );\r\n }\r\n\r\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\r\n const apiMarkets = body.markets;\r\n\r\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\r\n return [];\r\n }\r\n\r\n // Extract valid slab addresses\r\n const addresses: PublicKey[] = [];\r\n for (const entry of apiMarkets) {\r\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slab_address));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\r\n );\r\n\r\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\r\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Static bundle fallback (PERC-8435 — tier 3)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options for {@link discoverMarketsViaStaticBundle}. */\r\nexport interface DiscoverMarketsViaStaticBundleOptions {\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets from a static list of known slab addresses.\r\n *\r\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\r\n * a bundled list of known slab addresses and fetches their full account data\r\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * The static list acts as an address directory only — all market data is verified\r\n * on-chain, so stale entries are silently skipped (the account won't have valid\r\n * magic bytes or will have been closed).\r\n *\r\n * @param connection - Solana RPC connection (any endpoint)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\r\n * @param options - Optional on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import {\r\n * discoverMarketsViaStaticBundle,\r\n * getStaticMarkets,\r\n * getProgramId,\r\n * } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const entries = getStaticMarkets(\"mainnet\");\r\n *\r\n * const markets = await discoverMarketsViaStaticBundle(\r\n * connection,\r\n * programId,\r\n * entries,\r\n * );\r\n * console.log(`Recovered ${markets.length} markets from static bundle`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaStaticBundle(\r\n connection: Connection,\r\n programId: PublicKey,\r\n entries: StaticMarketEntry[],\r\n options: DiscoverMarketsViaStaticBundleOptions = {},\r\n): Promise {\r\n if (entries.length === 0) return [];\r\n\r\n // Extract valid slab addresses from static entries\r\n const addresses: PublicKey[] = [];\r\n for (const entry of entries) {\r\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slabAddress));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\r\n );\r\n\r\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\r\n}\r\n","/**\r\n * Static market registry — bundled list of known Percolator slab addresses.\r\n *\r\n * This is the tier-3 fallback for `discoverMarkets()`: when both\r\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\r\n * the SDK falls back to this bundled list to bootstrap market discovery.\r\n *\r\n * The addresses are fetched on-chain via `getMarketsByAddress`\r\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\r\n * list only provides the *address directory* — no cached market data is used.\r\n *\r\n * ## Maintenance\r\n *\r\n * Update this list when new markets are deployed or old ones are retired.\r\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\r\n * or the REST API.\r\n *\r\n * @module\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport type { Network } from \"../config/program-ids.js\";\r\n\r\n/**\r\n * A single entry in the static market registry.\r\n *\r\n * Only the slab address (base58) is required. Optional metadata fields\r\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\r\n * they are **not** used for on-chain data and may become stale.\r\n */\r\nexport interface StaticMarketEntry {\r\n /** Base58-encoded slab account address. */\r\n slabAddress: string;\r\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\r\n symbol?: string;\r\n /** Optional descriptive name. */\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Known mainnet market slab addresses.\r\n *\r\n * These are the markets deployed to the mainnet Percolator program\r\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\r\n *\r\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\r\n */\r\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\r\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\r\n];\r\n\r\n/**\r\n * Known devnet market slab addresses.\r\n *\r\n * These are discovered from the devnet Percolator program\r\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\r\n *\r\n * **Last updated:** 2026-04-04.\r\n */\r\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\r\n // Populated from prior discoverMarkets() runs on devnet.\r\n // These serve as the tier-3 safety net for devnet users.\r\n];\r\n\r\n/**\r\n * Full static registry indexed by network.\r\n */\r\nconst STATIC_REGISTRY: Record = {\r\n mainnet: MAINNET_MARKETS,\r\n devnet: DEVNET_MARKETS,\r\n};\r\n\r\n/**\r\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\r\n * Keyed by network.\r\n */\r\nconst USER_MARKETS: Record = {\r\n mainnet: [],\r\n devnet: [],\r\n};\r\n\r\n/**\r\n * Get the bundled static market list for a given network.\r\n *\r\n * Returns the built-in list merged with any entries added via\r\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\r\n * automatically — user-registered entries take precedence.\r\n *\r\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\r\n * @returns Array of static market entries (may be empty if no markets are known)\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * const markets = getStaticMarkets(\"mainnet\");\r\n * console.log(`${markets.length} known mainnet slab addresses`);\r\n * ```\r\n */\r\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\r\n const builtin = STATIC_REGISTRY[network] ?? [];\r\n const user = USER_MARKETS[network] ?? [];\r\n\r\n if (user.length === 0) return [...builtin];\r\n\r\n // Merge: user entries override builtin entries with same slabAddress\r\n const seen = new Map();\r\n for (const entry of builtin) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n for (const entry of user) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n return [...seen.values()];\r\n}\r\n\r\n/**\r\n * Register additional static market entries at runtime.\r\n *\r\n * Use this to inject known slab addresses before calling `discoverMarkets()`\r\n * so that tier-3 fallback has addresses to work with — especially useful\r\n * right after mainnet launch when the bundled list may be empty.\r\n *\r\n * Entries are deduplicated by `slabAddress` — calling this multiple times\r\n * with the same address is safe.\r\n *\r\n * @param network - Target network\r\n * @param entries - One or more static market entries to register\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * registerStaticMarkets(\"mainnet\", [\r\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\r\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\r\n * ]);\r\n * ```\r\n */\r\nexport function registerStaticMarkets(\r\n network: Network,\r\n entries: StaticMarketEntry[],\r\n): void {\r\n const existing = USER_MARKETS[network];\r\n const seen = new Set(existing.map(e => e.slabAddress));\r\n\r\n for (const entry of entries) {\r\n if (!entry.slabAddress) continue;\r\n if (seen.has(entry.slabAddress)) continue;\r\n // Validate that slabAddress is a valid base58 public key\r\n try {\r\n new PublicKey(entry.slabAddress);\r\n } catch {\r\n console.warn(\r\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\r\n );\r\n continue;\r\n }\r\n seen.add(entry.slabAddress);\r\n existing.push(entry);\r\n }\r\n}\r\n\r\n/**\r\n * Clear all user-registered static market entries for a network.\r\n *\r\n * Useful in tests or when resetting state.\r\n *\r\n * @param network - Target network to clear (omit to clear all networks)\r\n */\r\nexport function clearStaticMarkets(network?: Network): void {\r\n if (network) {\r\n USER_MARKETS[network] = [];\r\n } else {\r\n USER_MARKETS.mainnet = [];\r\n USER_MARKETS.devnet = [];\r\n }\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n PUMPSWAP_PROGRAM_ID,\r\n RAYDIUM_CLMM_PROGRAM_ID,\r\n METEORA_DLMM_PROGRAM_ID,\r\n} from \"./pda.js\";\r\n\r\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\r\n\r\nexport interface DexPoolInfo {\r\n dexType: DexType;\r\n poolAddress: PublicKey;\r\n baseMint: PublicKey;\r\n quoteMint: PublicKey;\r\n baseVault?: PublicKey; // PumpSwap only\r\n quoteVault?: PublicKey; // PumpSwap only\r\n}\r\n\r\n/**\r\n * Detect DEX type from the program that owns the pool account.\r\n *\r\n * @param ownerProgramId - The program ID that owns the pool account\r\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\r\n *\r\n * Supported DEX programs:\r\n * - PumpSwap (constant-product AMM)\r\n * - Raydium CLMM (concentrated liquidity)\r\n * - Meteora DLMM (discretized liquidity)\r\n */\r\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\r\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\r\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\r\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\r\n *\r\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\r\n * @param poolAddress - The on-chain address of the pool account\r\n * @param data - Raw account data bytes\r\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\r\n * @throws Error if data is too short for the given DEX type\r\n */\r\nexport function parseDexPool(\r\n dexType: DexType,\r\n poolAddress: PublicKey,\r\n data: Uint8Array,\r\n): DexPoolInfo {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n return parsePumpSwapPool(poolAddress, data);\r\n case \"raydium-clmm\":\r\n return parseRaydiumClmmPool(poolAddress, data);\r\n case \"meteora-dlmm\":\r\n return parseMeteoraPool(poolAddress, data);\r\n }\r\n}\r\n\r\n/**\r\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\r\n *\r\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\r\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\r\n * markets, prefer Pyth or Chainlink oracles.\r\n *\r\n * @param dexType - The type of DEX\r\n * @param data - Raw pool account data\r\n * @param vaultData - For PumpSwap only: base and quote vault account data\r\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\r\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\r\n * ignored for raydium-clmm (decimals are embedded in the pool account).\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\r\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\r\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\r\n * and for PumpSwap pools quoted in a non-WSOL mint.\r\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\r\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\r\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\r\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\r\n * price mislabeled as USD.\r\n * @throws Error if data is too short, required params are missing, or computation fails\r\n */\r\nexport function computeDexSpotPriceE6(\r\n dexType: DexType,\r\n data: Uint8Array,\r\n vaultData?: { base: Uint8Array; quote: Uint8Array },\r\n decimals?: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\r\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\r\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\r\n // MUST supply decimals (fetched from the base/quote mints), matching the\r\n // meteora-dlmm contract below.\r\n if (!decimals) {\r\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\r\n case \"raydium-clmm\":\r\n return computeRaydiumClmmPriceE6(data);\r\n case \"meteora-dlmm\":\r\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\r\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\r\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\r\n if (!decimals) {\r\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Mint decimals helper\r\n// ============================================================================\r\n\r\n/**\r\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\r\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\r\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\r\n * can read this field directly instead of duplicating the magic number.\r\n */\r\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\r\n\r\n/**\r\n * Read the `decimals` field of any SPL mint account (including native WSOL).\r\n *\r\n * This replaces `getMint(connection, mint).decimals` for callers that need to\r\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\r\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\r\n * because the system account is not a valid token-program mint; this function\r\n * reads raw account data and extracts byte 44 directly, which works for all\r\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param mint - The mint public key to query\r\n * @returns The `decimals` field value (0–255)\r\n * @throws Error if the account does not exist or is too short to hold a mint\r\n *\r\n * @example\r\n * ```ts\r\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\r\n *\r\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\r\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\r\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\r\n * base: baseDecimals,\r\n * quote: quoteDecimals,\r\n * });\r\n * ```\r\n */\r\nexport async function fetchMintDecimals(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) {\r\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\r\n }\r\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\r\n throw new Error(\r\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\r\n );\r\n }\r\n return info.data[SPL_MINT_DECIMALS_OFFSET];\r\n}\r\n\r\n// ============================================================================\r\n// PumpSwap\r\n// ============================================================================\r\n\r\n/**\r\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\r\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\r\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\r\n */\r\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\r\n\r\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\r\n// account layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8] pool_bump u8\r\n// [9:11] index u16\r\n// [11:43] creator Pubkey\r\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\r\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\r\n// [107:139] lp_mint Pubkey\r\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\r\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\r\n// [203:211] lp_supply u64\r\n// [211:243] coin_creator Pubkey\r\n//\r\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\r\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\r\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\r\n// pubkeys. Verified against the live ANSEM pool on mainnet\r\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\r\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\r\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\r\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\r\n// balance at verification time). Note the base vault (holding the pump.fun token)\r\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\r\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\r\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\r\n\r\n/**\r\n * Parse a PumpSwap constant-product AMM pool account.\r\n * @internal\r\n */\r\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"pumpswap\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(43, 75)),\r\n quoteMint: new PublicKey(data.slice(75, 107)),\r\n baseVault: new PublicKey(data.slice(139, 171)),\r\n quoteVault: new PublicKey(data.slice(171, 203)),\r\n };\r\n}\r\n\r\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\r\n\r\n/**\r\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\r\n * converted to USD.\r\n *\r\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\r\n *\r\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\r\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\r\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\r\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\r\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\r\n * at all unless multiplied by the SOL/USD rate.\r\n *\r\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\r\n * whether SOL→USD conversion applies)\r\n * @param vaultData - Base and quote vault (SPL token account) raw data\r\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\r\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\r\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\r\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\r\n * PumpSwap pool).\r\n * @internal\r\n */\r\nfunction computePumpSwapPriceE6(\r\n poolData: Uint8Array,\r\n vaultData: { base: Uint8Array; quote: Uint8Array },\r\n decimals: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n if (poolData.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\r\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\r\n\r\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\r\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\r\n\r\n const baseAmount = readU64LE(baseDv, 64);\r\n const quoteAmount = readU64LE(quoteDv, 64);\r\n\r\n if (baseAmount === 0n) return 0n;\r\n\r\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\r\n // the numerator by both the base-decimal correction AND the 1e6 output scale\r\n // before the single division, so low-priced tokens don't truncate to 0n.\r\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\r\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\r\n const baseScale = 10n ** BigInt(decimals.base);\r\n const quoteScale = 10n ** BigInt(decimals.quote);\r\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\r\n\r\n const quoteMint = new PublicKey(poolData.slice(75, 107));\r\n if (quoteMint.equals(WSOL_MINT)) {\r\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\r\n if (solPriceE6 === undefined) {\r\n throw new Error(\r\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\r\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\r\n );\r\n }\r\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\r\n }\r\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\r\n // already ~USD once decimal-adjusted — no further conversion needed.\r\n return quotePerBaseE6;\r\n}\r\n\r\n// ============================================================================\r\n// Raydium CLMM\r\n// ============================================================================\r\n\r\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\r\n\r\n/**\r\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\r\n * @internal\r\n */\r\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"raydium-clmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(73, 105)),\r\n quoteMint: new PublicKey(data.slice(105, 137)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\r\n *\r\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\r\n *\r\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\r\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\r\n *\r\n * @internal\r\n */\r\nconst MAX_TOKEN_DECIMALS = 24;\r\n\r\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\r\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n}\r\n\r\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n const decimals0 = data[233];\r\n const decimals1 = data[234];\r\n\r\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n\r\n const sqrtPriceX64 = readU128LE(dv, 253);\r\n\r\n if (sqrtPriceX64 === 0n) return 0n;\r\n\r\n // #210: defer truncation to a single shift at the very end. The previous form\r\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\r\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\r\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\r\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\r\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\r\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\r\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\r\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\r\n\r\n const decimalDiff = 6 + decimals0 - decimals1;\r\n const adjustedDiff = decimalDiff - 6;\r\n\r\n if (adjustedDiff >= 0) {\r\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\r\n } else {\r\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Meteora DLMM\r\n// ============================================================================\r\n\r\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8:40] parameters (StaticParameters, 32 bytes)\r\n// [40:72] v_parameters (VariableParameters, 32 bytes)\r\n// [72] bump_seed u8\r\n// [73:75] bin_step_seed [u8;2]\r\n// [75] pair_type u8\r\n// [76:80] active_id i32\r\n// [80:82] bin_step u16\r\n// [82] status u8\r\n// [83] require_base_factor_seed u8\r\n// [84:86] base_factor_seed [u8;2]\r\n// [86] activation_type u8\r\n// [87] creator_pool_on_off_control u8\r\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\r\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\r\n// [152:184] reserve_x Pubkey\r\n// [184:216] reserve_y Pubkey\r\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\r\n\r\n/**\r\n * Parse a Meteora DLMM (discretized liquidity) pool account.\r\n *\r\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\r\n * on-chain `LbPair` struct layout (verified against mainnet pool\r\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\r\n *\r\n * @internal\r\n */\r\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"meteora-dlmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(88, 120)),\r\n quoteMint: new PublicKey(data.slice(120, 152)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Meteora DLMM spot price from active_id and bin_step.\r\n *\r\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\r\n *\r\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\r\n * For negative active_id, computes the inverse.\r\n *\r\n * @internal\r\n */\r\nconst MAX_BIN_STEP = 10_000;\r\nconst MAX_ACTIVE_ID_ABS = 500_000;\r\n\r\nfunction computeMeteoraDlmmPriceE6(\r\n data: Uint8Array,\r\n decimalsBase: number,\r\n decimalsQuote: number,\r\n): bigint {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\r\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\r\n // They happen to encode the same integer for most pools (explaining why the\r\n // old code produced correct prices), but reading the correct field is required\r\n // for correctness once those fields diverge.\r\n const binStep = dv.getUint16(80, true);\r\n const activeId = dv.getInt32(76, true);\r\n\r\n if (binStep === 0) return 0n;\r\n if (binStep > MAX_BIN_STEP) {\r\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\r\n }\r\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\r\n throw new Error(\r\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\r\n );\r\n }\r\n\r\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\r\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\r\n\r\n const isNeg = activeId < 0;\r\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\r\n\r\n let result = SCALE;\r\n let b = base;\r\n\r\n while (exp > 0n) {\r\n if (exp & 1n) {\r\n result = (result * b) / SCALE;\r\n }\r\n exp >>= 1n;\r\n if (exp > 0n) {\r\n b = (b * b) / SCALE;\r\n }\r\n }\r\n\r\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\r\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\r\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\r\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\r\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\r\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\r\n // arbitrary-precision, so the intermediate products cannot overflow.\r\n const diff = decimalsBase - decimalsQuote;\r\n\r\n if (isNeg) {\r\n if (result === 0n) return 0n;\r\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\r\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\r\n if (diff >= 0) {\r\n return (num * 10n ** BigInt(diff)) / result;\r\n }\r\n return num / (result * 10n ** BigInt(-diff));\r\n } else {\r\n // price_e6 = (result / 1e12) * 10^diff\r\n if (diff >= 0) {\r\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\r\n }\r\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Read a little-endian u64 from a DataView. */\r\nfunction readU64LE(dv: DataView, offset: number): bigint {\r\n const lo = BigInt(dv.getUint32(offset, true));\r\n const hi = BigInt(dv.getUint32(offset + 4, true));\r\n return lo | (hi << 32n);\r\n}\r\n\r\n/** Read a little-endian u128 from a DataView. */\r\nfunction readU128LE(dv: DataView, offset: number): bigint {\r\n const lo = readU64LE(dv, offset);\r\n const hi = readU64LE(dv, offset + 8);\r\n return lo | (hi << 64n);\r\n}\r\n","/**\r\n * Oracle account parsing utilities.\r\n *\r\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\r\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\r\n * so that this parser and the on-chain program agree byte-for-byte:\r\n *\r\n * CHAINLINK_HEADER_SIZE = 192\r\n * offset 8: version (u8) CL_OFF_VERSION\r\n * offset 138: decimals (u8) CL_OFF_DECIMALS\r\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\r\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\r\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\r\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\r\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\r\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\r\n *\r\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\r\n *\r\n * These utilities validate oracle data BEFORE parsing to prevent silent\r\n * propagation of stale or malformed Chainlink data as price.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Minimum buffer size to read Chainlink price data.\r\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\r\n * The previous value (224) was smaller than the program's own floor, so the SDK\r\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\r\n * answer at offset 216.\r\n */\r\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\r\n\r\n/** Maximum reasonable decimals for a price feed */\r\nconst MAX_DECIMALS = 18;\r\n\r\n/** Offset of decimals field in Chainlink aggregator account */\r\nconst CHAINLINK_DECIMALS_OFFSET = 138;\r\n\r\n/**\r\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\r\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\r\n */\r\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\r\n\r\n/**\r\n * Offset of the latest answer.\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\r\n */\r\nconst CHAINLINK_ANSWER_OFFSET = 216;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface OraclePrice {\r\n price: bigint;\r\n decimals: number;\r\n /** Unix timestamp (seconds) of the last oracle update, if available. */\r\n updatedAt?: number;\r\n}\r\n\r\nexport interface ParseChainlinkOptions {\r\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\r\n maxStalenessSeconds?: number;\r\n /**\r\n * How far ahead of the local clock a publish timestamp may be before it is\r\n * treated as invalid rather than as clock skew. Defaults to 60s.\r\n * Only consulted when `maxStalenessSeconds` is set.\r\n */\r\n futureToleranceSeconds?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Browser-compatible read helpers using DataView\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n return data[off];\r\n}\r\n\r\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\r\n}\r\n\r\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\r\n}\r\n\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\r\n}\r\n\r\n/**\r\n * Default tolerance for a publish timestamp that appears to be in the future.\r\n *\r\n * The program compares the feed timestamp against the on-chain clock\r\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\r\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\r\n * between a user's machine and the cluster would otherwise reject a perfectly\r\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\r\n */\r\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse price data from a Chainlink aggregator account buffer.\r\n *\r\n * Validates:\r\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\r\n * program's own CHAINLINK_FEED_MIN_LEN)\r\n * - Decimals are in a reasonable range (0-18)\r\n * - Price is positive (non-zero)\r\n *\r\n * @param data - Raw account data from Chainlink aggregator\r\n * @param options - Optional staleness check (maxStalenessSeconds)\r\n * @returns Parsed oracle price with decimals and last-update timestamp\r\n * @throws if the buffer is invalid, contains unreasonable data, or (when\r\n * maxStalenessSeconds is set) the last update is older than that bound\r\n */\r\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\r\n if (data.length < CHAINLINK_MIN_SIZE) {\r\n throw new Error(\r\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\r\n );\r\n }\r\n\r\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\r\n if (decimals > MAX_DECIMALS) {\r\n throw new Error(\r\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\r\n );\r\n }\r\n\r\n // The program reads the answer as a full i128 LE (read_i128_le at\r\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\r\n // high (signed) halves rather than reading only the low 8 bytes, which would\r\n // silently truncate a large answer into a different price than the chain sees.\r\n //\r\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\r\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\r\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\r\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\r\n // on-chain. `price` is a bigint and holds the full i128 range.\r\n const answer =\r\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\r\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\r\n if (answer <= 0n) {\r\n throw new Error(\r\n `Oracle price is non-positive: ${answer}`\r\n );\r\n }\r\n const price = answer;\r\n\r\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\r\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\r\n\r\n if (options?.maxStalenessSeconds !== undefined) {\r\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\r\n // skipping the check: a zero timestamp means the feed has never published,\r\n // which is maximally stale, not exempt from staleness.\r\n if (updatedAt <= 0) {\r\n throw new Error(\r\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\r\n );\r\n }\r\n const now = Math.floor(Date.now() / 1000);\r\n const age = now - updatedAt;\r\n // The program rejects a negative age, but it measures against the on-chain\r\n // clock. We only have the local one, so a couple of seconds of ordinary skew\r\n // must not condemn a healthy feed — only an implausible jump ahead should.\r\n const futureTolerance =\r\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\r\n if (age < -futureTolerance) {\r\n throw new Error(\r\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\r\n `check the feed or the local clock`\r\n );\r\n }\r\n if (age > options.maxStalenessSeconds) {\r\n throw new Error(\r\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\r\n );\r\n }\r\n }\r\n\r\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\r\n}\r\n\r\n/**\r\n * Validate that a buffer looks like a valid Chainlink aggregator account.\r\n * Returns true if the buffer passes all validation checks, false otherwise.\r\n * Use this for non-throwing validation.\r\n */\r\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\r\n try {\r\n parseChainlinkPrice(data);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-export constants for consumers\r\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Token2022 (Token Extensions) program ID.\r\n */\r\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\r\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\r\n);\r\n\r\n/**\r\n * Detect which token program owns a given mint account.\r\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\r\n *\r\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\r\n * attacker-controlled account owned by an arbitrary program (or a non-mint\r\n * account) would be accepted and its owner propagated as the \"token program\",\r\n * letting a forged program be passed into a later token CPI. Now we branch on\r\n * the owner and accept ONLY the two real token programs, throwing otherwise.\r\n *\r\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\r\n * Token-2022.\r\n */\r\nexport async function detectTokenProgram(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\r\n\r\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\r\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\r\n\r\n throw new Error(\r\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\r\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\r\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\r\n );\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is Token2022.\r\n */\r\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is the standard SPL Token program.\r\n */\r\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\r\n}\r\n","/**\r\n * @module stake\r\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\r\n *\r\n * Program: percolator-stake (dcccrypto/percolator-stake)\r\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\r\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\r\n * `src/config/program-ids.ts`)\r\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\r\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\r\n * this writing; treat as a placeholder until DevOps confirms)\r\n *\r\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\r\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\r\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\r\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\r\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\r\n * do not use it for new integrations).\r\n */\r\n\r\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\r\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\r\nexport { TOKEN_2022_PROGRAM_ID };\r\nimport { safeEnv } from '../config/program-ids.js';\r\nimport { concatBytes } from '../abi/encode.js';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Known stake program addresses per network.\r\n *\r\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\r\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\r\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\r\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\r\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\r\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\r\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\r\n * module targets — see the module doc above.\r\n *\r\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\r\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\r\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\r\n * confirms.\r\n *\r\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\r\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\r\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\r\n * silently default to mainnet: an unconfigured browser caller would have resolved to\r\n * a real, executing mainnet program rather than failing safe.\r\n */\r\nexport const STAKE_PROGRAM_IDS = {\r\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\r\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\r\n} as const;\r\nObject.freeze(STAKE_PROGRAM_IDS);\r\n\r\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\r\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\r\n\r\n/**\r\n * Resolve the stake program ID for the given network.\r\n *\r\n * Priority:\r\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\r\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\r\n *\r\n * Throws a clear error on mainnet when no address is available so callers\r\n * surface the gap instead of silently hitting the devnet program.\r\n */\r\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\r\n // Only consult the env override when no explicit network arg is provided.\r\n // An explicit network argument always wins so tests and multi-network callers\r\n // are not silently redirected to a DevOps-set override address.\r\n if (!network) {\r\n const override = safeEnv('STAKE_PROGRAM_ID');\r\n if (override) {\r\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\r\n // ambient env poisoning while allowing fresh pre-deploy addresses).\r\n if (\r\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\r\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\r\n ) {\r\n throw new Error(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\r\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\r\n );\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n const detectedNetwork =\r\n network ??\r\n (() => {\r\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\r\n safeEnv('NETWORK')?.toLowerCase() ?? '';\r\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\r\n if (n === 'devnet') return 'devnet' as const;\r\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\r\n // i.e. in every browser bundle, where process.env is empty because env vars\r\n // are not inlined into third-party SDK code. An unconfigured frontend caller\r\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\r\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\r\n //\r\n // We deliberately do NOT substitute a devnet default here. Unlike\r\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\r\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\r\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\r\n // defaulting to devnet would merely defer it to the day mainnet launches and\r\n // a forgotten env var silently points a mainnet UI at the devnet vault.\r\n // Refuse to guess: the network must be explicit.\r\n // The message must not assert a cause it has not established. This fires in\r\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\r\n // with process.env fully available — so claiming \"browser bundle\" would send\r\n // a server-side caller chasing the wrong thing.\r\n throw new Error(\r\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\r\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\r\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\r\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\r\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\r\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\r\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\r\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\r\n 'for the wrong network.',\r\n );\r\n })();\r\n\r\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\r\n if (!id) {\r\n throw new Error(\r\n `Stake program not deployed on ${detectedNetwork}. ` +\r\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\r\n );\r\n }\r\n return new PublicKey(id);\r\n}\r\n\r\n/**\r\n * Default export — resolves for the current runtime network.\r\n * Use getStakeProgramId() with an explicit network argument where possible.\r\n *\r\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\r\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\r\n * resolving to the devnet address.\r\n */\r\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Tags — ADOPTED percolator-stake lineage\r\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\r\n//\r\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\r\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\r\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\r\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\r\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\r\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\r\n// side-by-side tag-delta table this was verified against. The comparison is now\r\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\r\n// NEW address that already runs the ADOPTED lineage below — there is no more\r\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport const STAKE_IX = {\r\n InitPool: 0,\r\n Deposit: 1,\r\n Withdraw: 2,\r\n FlushToInsurance: 3,\r\n UpdateConfig: 4,\r\n /**\r\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\r\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\r\n * zero pubkey CANCELS an outstanding proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\r\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\r\n * wrapper marketauth rotation (a completely different key, done via the\r\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\r\n *\r\n * Wire: tag(1) + new_admin(32) = 33 bytes.\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\n ProposeAdmin: 5,\r\n /**\r\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to take ownership; requires an outstanding proposal\r\n * and the signer to equal `pool.pending_admin`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\r\n * removed `AdminSetOracleAuthority` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\n AcceptAdmin: 6,\r\n /**\r\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\r\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\r\n * LP holders an exit window. A decrease/unchanged value is rejected here\r\n * (use UpdateConfig, which applies decreases immediately).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\r\n * removed `AdminSetRiskThreshold` (rejects on-chain).\r\n *\r\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n ProposeCooldownIncrease: 7,\r\n /**\r\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\r\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n CommitCooldownIncrease: 8,\r\n /**\r\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\r\n * proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\r\n * removed `AdminResolveMarket` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n CancelCooldownIncrease: 9,\r\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\r\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\r\n TransferAdmin: 5,\r\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\r\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\r\n AdminSetOracleAuthority: 6,\r\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\r\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\r\n AdminSetRiskThreshold: 7,\r\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\r\n * CommitCooldownIncrease. */\r\n AdminSetMaintenanceFee: 8,\r\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\r\n * CancelCooldownIncrease. */\r\n AdminResolveMarket: 9,\r\n /**\r\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\r\n * percolator-vault program: transfer withdrawn insurance back into the pool\r\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\r\n * books admin-ATA -> pool-vault).\r\n */\r\n ReturnInsurance: 10,\r\n /** @deprecated Legacy alias for ReturnInsurance. */\r\n AdminWithdrawInsurance: 10,\r\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\r\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\r\n AdminSetInsurancePolicy: 11,\r\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\r\n AccrueFees: 12,\r\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\r\n InitTradingPool: 13,\r\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\r\n AdminSetHwmConfig: 14,\r\n /**\r\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\r\n * tranches. Sets `junior_fee_mult_bps`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * below). Sending this payload against the DEPLOYED vault program would\r\n * execute BindInsuranceAuthority instead; only send it against the\r\n * ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n AdminSetTrancheConfig: 15,\r\n /**\r\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\r\n * Same account shape as Deposit (tag 1).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\n DepositJunior: 16,\r\n /**\r\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\r\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\r\n * binds both in one call, unlike the deployed vault program which only\r\n * bound insurance_authority. The human admin signs the outer tx as the\r\n * current authority/operator; vault_auth signs via invoke_signed.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n BindInsuranceAuthority: 19,\r\n /**\r\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\r\n * escape that moves the market's `insurance_authority` OFF our vault_auth\r\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\r\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\r\n * authority. NEW in the adopted lineage — no equivalent in the deployed\r\n * percolator-vault program (which has no un-bind escape at all).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceAuthority: 20,\r\n /**\r\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\r\n * has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\r\n */\r\n BurnAssetAdmin: 21,\r\n /**\r\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceOperator: 22,\r\n /**\r\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\r\n * insurance_operator, not asset_admin. `amount` capped to\r\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\r\n * NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\r\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\r\n * tokenProgram, percolatorProgram]\r\n */\r\n RecoverFlushedInsurance: 23,\r\n /**\r\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\r\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\r\n * without this proxy every stake-initialized market would be permanently\r\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\r\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\r\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\r\n * percolator-stake (see src/instruction.rs / src/processor.rs\r\n * `process_admin_resolve_market`, tag 24).\r\n *\r\n * NOTE on the name: the on-chain enum variant is literally\r\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\r\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\r\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\r\n * avoid re-using that already-claimed object key/export name — the tag-9\r\n * alias and this tag-24 instruction are unrelated aside from sharing an\r\n * on-chain name across two different lineages.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n */\r\n AdminResolveMarketCpi: 24,\r\n /**\r\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n SetMarketResolved: 18,\r\n /**\r\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\r\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\r\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\r\n * signs the CPI via invoke_signed.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\r\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\r\n * Custom(52)/Custom(51) through the CPI.\r\n */\r\n AdminUpdateFeeSplit: 25,\r\n /**\r\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\r\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\r\n * signer model as tag 25.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\r\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\r\n * `read_u128`.\r\n */\r\n AdminUpdateMaintenanceFeePerSlot: 26,\r\n /**\r\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\r\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\r\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\r\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\r\n *\r\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\r\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\r\n *\r\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n AdminUpdateBackingFeePolicy: 27,\r\n /**\r\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\r\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\r\n * model as tag 27.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\r\n * `read_u64`, wrapper tag 88 with `read_u128`.\r\n */\r\n AdminUpdateTradeFeePolicy: 28,\r\n} as const;\r\nObject.freeze(STAKE_IX);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * User-facing hint text for `StakeError` custom program error codes\r\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\r\n *\r\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\r\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\r\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\r\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\r\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\r\n * error\" for 25-27 despite them being named enum variants); the hints below\r\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\r\n * (missing) on-chain string.\r\n */\r\nexport const STAKE_ERRORS: Record = {\r\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\r\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\r\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\r\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\r\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\r\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\r\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\r\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\r\n 8: \"Market is resolved — no new deposits allowed after resolution\",\r\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\r\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\r\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\r\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\r\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\r\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\r\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\r\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\r\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\r\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\r\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\r\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\r\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\r\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\r\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\r\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\r\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\r\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\r\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\r\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\r\n};\r\nObject.freeze(STAKE_ERRORS);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PDA Derivation\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\n/** Derive the stake pool PDA for a given slab (market). */\r\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\r\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\r\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getBigUint64(off, /* littleEndian= */ true);\r\n}\r\n\r\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getUint16(off, /* littleEndian= */ true);\r\n}\r\n\r\nfunction requireDiscriminator(\r\n accountName: string,\r\n data: Uint8Array,\r\n offset: number,\r\n expected: Uint8Array,\r\n): void {\r\n for (let i = 0; i < expected.length; i += 1) {\r\n if (data[offset + i] !== expected[i]) {\r\n throw new Error(`${accountName} invalid discriminator`);\r\n }\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Encoders\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction u64Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\r\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\r\n const arr = new Uint8Array(8);\r\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\r\n}\r\n\r\nfunction u128Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\r\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\r\n const arr = new Uint8Array(16);\r\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\r\n view.setBigUint64(8, big >> 64n, true);\r\n return arr;\r\n}\r\n\r\nfunction u16Le(v: number): Uint8Array {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\r\n return arr;\r\n}\r\n\r\n/** Tag 0: InitPool — create stake pool for a slab. */\r\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\r\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\r\n}\r\n\r\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\r\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\r\n}\r\n\r\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\r\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\r\n}\r\n\r\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\r\nexport function encodeStakeUpdateConfig(\r\n newCooldownSlots?: bigint | number,\r\n newDepositCap?: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.UpdateConfig]),\r\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\r\n u64Le(newCooldownSlots ?? 0n),\r\n new Uint8Array([newDepositCap != null ? 1 : 0]),\r\n u64Le(newDepositCap ?? 0n),\r\n );\r\n}\r\n\r\nfunction removedStakeInstruction(name: string, tag: number): never {\r\n throw new Error(\r\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\r\n );\r\n}\r\n\r\n/**\r\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\r\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\r\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\r\n * proposal.\r\n *\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeAdmin]),\r\n newAdmin.toBytes(),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to become admin. Requires an outstanding proposal.\r\n *\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAcceptAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\r\n}\r\n\r\n/**\r\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\r\n * until CommitCooldownIncrease is called after the on-chain timelock has\r\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\r\n u64Le(newCooldownSlots),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\r\n * increase proposal.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\r\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\r\n * percolator-stake lineage this module targets, tag 5 is the two-step\r\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\r\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\r\n */\r\nexport function encodeStakeTransferAdmin(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\r\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\r\n void newAuthority;\r\n throw new Error(\r\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\r\n 'lineage — use encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\r\n void newThreshold;\r\n throw new Error(\r\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\r\n void newFee;\r\n throw new Error(\r\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\r\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ReturnInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\r\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\r\n return encodeStakeReturnInsurance(amount);\r\n}\r\n\r\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\r\nexport function encodeStakeAccrueFees(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AccrueFees]);\r\n}\r\n\r\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\r\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitTradingPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\r\nexport function encodeStakeAdminSetHwmConfig(\r\n enabled: boolean,\r\n hwmFloorBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\r\n new Uint8Array([enabled ? 1 : 0]),\r\n u16Le(hwmFloorBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\r\n * percolator-stake lineage; sending it against the currently-deployed vault\r\n * program would silently execute BindInsuranceAuthority instead.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\r\n u16Le(juniorFeeMultBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\r\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\r\n}\r\n\r\n/**\r\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeSetMarketResolved(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\r\n}\r\n\r\n/**\r\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\r\n * then kind=2) — a broader bind than the deployed vault program's\r\n * single-CPI version (insurance_authority only). Must be called once after\r\n * InitPool, before FlushToInsurance will work.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\r\n *\r\n * @returns 1-byte Uint8Array `[0x13]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBindInsuranceAuthority();\r\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\r\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\r\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\r\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BindInsuranceAuthorityAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * Account order matches src/processor.rs process_bind_insurance_authority\r\n * (adopted lineage — same account shape as the deployed vault program's tag\r\n * 15, only the tag byte moved):\r\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\r\n * [1] pool_pda writable (stake pool PDA)\r\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n *\r\n * @example\r\n * ```ts\r\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\r\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\r\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function bindInsuranceAuthorityAccounts(\r\n a: BindInsuranceAuthorityAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\r\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\r\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\r\n * the deployed percolator-vault program (which has no un-bind escape).\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceAuthority();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceOperator();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\r\n}\r\n\r\n/**\r\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\r\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA.\r\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\r\n * @param newTarget The successor authority/operator — co-signs the outer tx.\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RotateInsuranceAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n newTarget: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\r\n * (tag 22) — identical account order in both (src/processor.rs\r\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only\r\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\r\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\r\n * [4] slab writable (wrapper market; needed for CPI)\r\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function rotateInsuranceAccounts(\r\n a: RotateInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after\r\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBurnAssetAdmin();\r\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\r\n}\r\n\r\n/**\r\n * Account inputs for BurnAssetAdmin (tag 21).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\r\n * @param poolPda Stake pool PDA (writable — records the burn).\r\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BurnAssetAdminAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\r\n * process_burn_asset_admin:\r\n * [0] admin signer, writable (current asset_admin == pool.admin)\r\n * [1] pool_pda writable (records asset_admin_burned)\r\n * [2] vault_auth read-only (placeholder new_authority slot)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function burnAssetAdminAccounts(\r\n a: BurnAssetAdminAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\r\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\r\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\r\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\r\n * adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n *\r\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\r\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\r\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for RecoverFlushedInsurance (tag 23).\r\n *\r\n * @param caller Permissionless caller — no signer check required.\r\n * @param poolPda Stake pool PDA (writable).\r\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\r\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\r\n * @param wrapperMarket Wrapper market/slab account (writable).\r\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\r\n * @param wrapperVaultAuth Wrapper vault authority PDA.\r\n * @param tokenProgram Token program.\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RecoverFlushedInsuranceAccounts {\r\n caller: PublicKey;\r\n poolPda: PublicKey;\r\n poolVault: PublicKey;\r\n vaultAuth: PublicKey;\r\n wrapperMarket: PublicKey;\r\n wrapperVault: PublicKey;\r\n wrapperVaultAuth: PublicKey;\r\n tokenProgram: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\r\n * process_recover_flushed_insurance:\r\n * [0] caller (no signer check — permissionless)\r\n * [1] pool_pda writable\r\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\r\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\r\n * [4] market (wrapper) writable\r\n * [5] wrapper_vault writable (source — wrapper insurance vault)\r\n * [6] wrapper_vault_auth read-only\r\n * [7] token_program read-only\r\n * [8] percolator_program read-only\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function recoverFlushedInsuranceAccounts(\r\n a: RecoverFlushedInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.caller, isSigner: false, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\r\n * can call the wrapper's ResolveMarket directly; this instruction has the\r\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\r\n * the (human) admin can trigger resolution. Does not mutate any local\r\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\r\n * separately afterward for local bookkeeping.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n *\r\n * @returns 1-byte Uint8Array `[24]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminResolveMarketCpi();\r\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\r\n}\r\n\r\n/**\r\n * Account inputs for AdminResolveMarketCpi (tag 24).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\r\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface AdminResolveMarketCpiAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\r\n * process_admin_resolve_market:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\r\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function adminResolveMarketCpiAccounts(\r\n a: AdminResolveMarketCpiAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\r\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\r\n//\r\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\r\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\r\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\r\n// transaction, so the affected wrapper setters become reachable ONLY through a\r\n// stake-program CPI proxy. Before these four, exactly one proxy existed\r\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\r\n// wrapper handlers reachable — which is the mechanical reason the fee split\r\n// was unachievable on a staked market.\r\n//\r\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\r\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\r\n// VAULT_AUTH PDA signs.\r\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n//\r\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\r\n * whose length is not exactly 6 bytes after the tag.\r\n *\r\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\r\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\r\n *\r\n * Share validation happens in the WRAPPER, not here: a split that does not sum\r\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\r\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\r\n *\r\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\r\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\r\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\r\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateFeeSplit(\r\n creatorShareBps: number,\r\n lpShareBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\r\n u16Le(creatorShareBps),\r\n u16Le(lpShareBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\r\n * wrapper tag 88.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\r\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\r\n * u64 fails at the stake program before the CPI is even attempted.\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\r\n * 0 (maintenance fee disabled). The wrapper\r\n * range-checks against MAX_PROTOCOL_FEE_ABS.\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\r\n maintenanceFeePerSlot: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\r\n u128Le(maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\r\n * tag 51, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\r\n * = 7 bytes.\r\n *\r\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\r\n * @param feeBps Backing fee in bps (u16).\r\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\r\n * const keys = adminUpdateBackingFeePolicyAccounts({\r\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\r\n * });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateBackingFeePolicy(\r\n domain: number,\r\n feeBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\r\n u16Le(domain),\r\n u16Le(feeBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\r\n * 55, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\r\n * checks `rest.len() == 8`.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\r\n * values above the market's `max_trading_fee_bps` or\r\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateTradeFeePolicy(\r\n tradeFeeBaseBps: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\r\n u64Le(tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\r\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupAProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP A proxies — src/processor.rs\r\n * `process_admin_update_fee_split` (tag 25) and\r\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\r\n * identical layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\r\n * [2] slab writable (wrapper market; CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupAProxyAccounts(\r\n a: StakeGroupAProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\r\n\r\n/**\r\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\r\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\r\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\r\n * insurance_authority; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupBProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP B proxies — src/processor.rs\r\n * `process_admin_update_backing_fee_policy` (tag 27) and\r\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\r\n * layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\r\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; CPI target)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\r\n * difference from GROUP A, and getting it wrong makes the CPI fail its\r\n * authority check rather than fail loudly at the account level.\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupBProxyAccounts(\r\n a: StakeGroupBProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\r\nexport function encodeStakeAdminSetInsurancePolicy(\r\n authority: PublicKey,\r\n minWithdrawBase: bigint | number,\r\n maxWithdrawBps: number,\r\n cooldownSlots: bigint | number,\r\n): Uint8Array {\r\n void authority;\r\n void minWithdrawBase;\r\n void maxWithdrawBps;\r\n void cooldownSlots;\r\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// On-Chain State Layout — StakePool decoded fields\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\r\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\r\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\r\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\r\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\r\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\r\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\r\n * and PERC-303 (tranches).\r\n *\r\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\r\n * `_reserved` layout (verified against `state.rs` on\r\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\r\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\r\n * whatever bytes the program actually writes):\r\n *\r\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\r\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\r\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\r\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\r\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\r\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\r\n * (added later, #242) write into [10..18]/[18..26] regardless.\r\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\r\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\r\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\r\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\r\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\r\n * - This decoder reads both field sets as the raw bytes currently define\r\n * them (matching on-chain reality); it does NOT attempt to reconcile or\r\n * invalidate one set when the other is in use. Callers combining HWM and\r\n * the cooldown timelock on one pool should treat both `hwm*` and\r\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\r\n * against a direct on-chain read before trusting either.\r\n */\r\nexport interface StakePoolState {\r\n isInitialized: boolean;\r\n bump: number;\r\n vaultAuthorityBump: number;\r\n adminTransferred: boolean;\r\n marketResolved: boolean;\r\n\r\n slab: PublicKey;\r\n admin: PublicKey;\r\n collateralMint: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n\r\n totalDeposited: bigint;\r\n totalLpSupply: bigint;\r\n cooldownSlots: bigint;\r\n depositCap: bigint;\r\n totalFlushed: bigint;\r\n totalReturned: bigint;\r\n totalWithdrawn: bigint;\r\n\r\n percolatorProgram: PublicKey;\r\n\r\n /**\r\n * Pending admin for the two-step rotation (stake v2, offset 288).\r\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\r\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\r\n */\r\n pendingAdmin: PublicKey | null;\r\n\r\n // PERC-272: Fee yield fields\r\n totalFeesEarned: bigint;\r\n lastFeeAccrualSlot: bigint;\r\n lastVaultSnapshot: bigint;\r\n poolMode: number;\r\n\r\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\r\n // [0..8] discriminator\r\n // [8] version\r\n // [9] market_resolved\r\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\r\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\r\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\r\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\r\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\r\n // [24..32] PERC-313 hwm_last_epoch (u64)\r\n // [32] PERC-303 tranche_enabled\r\n // [33..41] PERC-303 junior_balance (u64)\r\n // [41..49] PERC-303 junior_total_lp (u64)\r\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\r\n // [51..59] N-realized_junior_loss (u64) — issue #161\r\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\r\n // [60..64] free\r\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\r\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\r\n\r\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\r\n hwmEnabled: boolean;\r\n epochHighWaterTvl: bigint;\r\n hwmFloorBps: number;\r\n hwmLastEpoch: bigint;\r\n\r\n // PERC-303: Tranche fields (from _reserved[32..51])\r\n trancheEnabled: boolean;\r\n juniorBalance: bigint;\r\n juniorTotalLp: bigint;\r\n juniorFeeMultBps: number;\r\n\r\n /**\r\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\r\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n pendingCooldownSlots: bigint;\r\n /**\r\n * #242 timelock: the slot at which the pending cooldown increase was\r\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n cooldownProposedAtSlot: bigint;\r\n /**\r\n * Cumulative insurance loss a fully-exited junior tranche permanently\r\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\r\n * total_pool_value() so recovered tokens don't windfall senior.\r\n */\r\n realizedJuniorLoss: bigint;\r\n /**\r\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\r\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\r\n * stay disabled — the wrapper roles cannot be moved back to an\r\n * admin-controlled key.\r\n */\r\n assetAdminBurned: boolean;\r\n /**\r\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\r\n * collateral actually recovered from the WRAPPER via the tag-23\r\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\r\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\r\n * insurance back out of the wrapper. Real struct field at offset 384..392\r\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\r\n *\r\n * Deliberately separate from `totalReturned`, which is also bumped by two\r\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\r\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\r\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\r\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\r\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\r\n */\r\n totalRecoveredFromWrapper: bigint | null;\r\n}\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v1 layout.\r\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\r\n * The _reserved block in v1 starts at offset 288; version byte = 1.\r\n *\r\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\r\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\r\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\r\n * migration is needed\"). v1/352-byte pools can only ever be observed as\r\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\r\n * redeploy (which abandons every existing market/pool wholesale — VERSION\r\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\r\n * detection exists purely to decode those pre-redeploy artifacts if you ever\r\n * need to; the ADOPTED program itself never creates a v1 pool.\r\n */\r\nexport const STAKE_POOL_SIZE_V1 = 352;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v2 layout.\r\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\r\n * The _reserved block in v2 starts at offset 320; version byte = 2.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\r\n * padding (every u64 field lands on an 8-aligned cumulative offset).\r\n *\r\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\r\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\r\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\r\n * still needs to construct a v2-shaped buffer explicitly.\r\n */\r\nexport const STAKE_POOL_SIZE_V2 = 384;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\r\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\r\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\r\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\r\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\r\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\r\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\r\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\r\n * instead of the broader (and gameable) `total_returned` counter — see\r\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\r\n * padding (the appended u64 lands on the already-8-aligned offset 384).\r\n */\r\nexport const STAKE_POOL_SIZE_V3 = 392;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\r\n * ADOPTED percolator-stake lineage creates. Currently equal to\r\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\r\n * constants in new code so a future version bump doesn't silently change the\r\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\r\n */\r\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\r\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\r\nexport const STAKE_POOL_CURRENT_VERSION = 3;\r\n\r\n/**\r\n * Decode a StakePool account from raw data buffer.\r\n *\r\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\r\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\r\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\r\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\r\n * v2 and v3). The layout version is detected from the data length before\r\n * reading the discriminator.\r\n *\r\n * v1/v2 support exists only to decode legacy pools created before the\r\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\r\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\r\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\r\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\r\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\r\n * on-chain `_reserved` layout collision).\r\n *\r\n * Uses DataView for all u64/u16 reads — browser-safe.\r\n */\r\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\r\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\r\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\r\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\r\n if (!isV3 && !isV2 && !isV1) {\r\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\r\n }\r\n\r\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\r\n // AFTER _reserved, not inside it, so the block start doesn't move again).\r\n const reservedOffset = isV1 ? 288 : 320;\r\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\r\n const version = data[reservedOffset + 8];\r\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\r\n if (version !== expectedVersion) {\r\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\r\n }\r\n\r\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\r\n let off = 0;\r\n const isInitialized = bytes[off] === 1; off += 1;\r\n const bump = bytes[off]; off += 1;\r\n const vaultAuthorityBump = bytes[off]; off += 1;\r\n const adminTransferred = bytes[off] === 1; off += 1;\r\n off += 4; // _padding\r\n\r\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n const totalDeposited = readU64LE(bytes, off); off += 8;\r\n const totalLpSupply = readU64LE(bytes, off); off += 8;\r\n const cooldownSlots = readU64LE(bytes, off); off += 8;\r\n const depositCap = readU64LE(bytes, off); off += 8;\r\n const totalFlushed = readU64LE(bytes, off); off += 8;\r\n const totalReturned = readU64LE(bytes, off); off += 8;\r\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\r\n\r\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n // PERC-272 fields (offset 256..288 in both v1 and v2)\r\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\r\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\r\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\r\n const poolMode = bytes[off]; off += 1;\r\n off += 7; // _mode_padding (off is now 288)\r\n\r\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\r\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\r\n let pendingAdmin: PublicKey | null = null;\r\n if (isV2 || isV3) {\r\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\r\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\r\n ? null\r\n : new PublicKey(pendingAdminBytes);\r\n }\r\n\r\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\r\n const reservedStart = off;\r\n // _reserved[8] = version (skipped)\r\n // _reserved[9] = market_resolved\r\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\r\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\r\n const marketResolved = bytes[reservedStart + 9] === 1;\r\n const hwmEnabled = bytes[reservedStart + 10] === 1;\r\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\r\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\r\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\r\n\r\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\r\n const trancheEnabled = bytes[reservedStart + 32] === 1;\r\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\r\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\r\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\r\n\r\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\r\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\r\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\r\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\r\n\r\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\r\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\r\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\r\n\r\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\r\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\r\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\r\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\r\n const totalRecoveredFromWrapper = isV3\r\n ? readU64LE(bytes, reservedStart + 64)\r\n : null;\r\n\r\n return {\r\n isInitialized,\r\n bump,\r\n vaultAuthorityBump,\r\n adminTransferred,\r\n marketResolved,\r\n slab,\r\n admin,\r\n collateralMint,\r\n lpMint,\r\n vault,\r\n totalDeposited,\r\n totalLpSupply,\r\n cooldownSlots,\r\n depositCap,\r\n totalFlushed,\r\n totalReturned,\r\n totalWithdrawn,\r\n percolatorProgram,\r\n pendingAdmin,\r\n totalFeesEarned,\r\n lastFeeAccrualSlot,\r\n lastVaultSnapshot,\r\n poolMode,\r\n hwmEnabled,\r\n epochHighWaterTvl,\r\n hwmFloorBps,\r\n hwmLastEpoch,\r\n trancheEnabled,\r\n juniorBalance,\r\n juniorTotalLp,\r\n juniorFeeMultBps,\r\n pendingCooldownSlots,\r\n cooldownProposedAtSlot,\r\n realizedJuniorLoss,\r\n assetAdminBurned,\r\n totalRecoveredFromWrapper,\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// StakeDeposit PDA decoder\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Size of StakeDeposit on-chain (bytes). */\r\nexport const STAKE_DEPOSIT_SIZE = 152;\r\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\r\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\r\n\r\n/** Decoded StakeDeposit PDA state. */\r\nexport interface StakeDepositState {\r\n isInitialized: boolean;\r\n bump: number;\r\n pool: PublicKey;\r\n user: PublicKey;\r\n lastDepositSlot: bigint;\r\n lpAmount: bigint;\r\n}\r\n\r\n/**\r\n * Decode a StakeDeposit PDA account from raw data.\r\n *\r\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\r\n * [0] is_initialized u8\r\n * [1] bump u8\r\n * [2..8] _padding\r\n * [8..40] pool [u8; 32]\r\n * [40..72] user [u8; 32]\r\n * [72..80] last_deposit_slot u64\r\n * [80..88] lp_amount u64\r\n * [88..152] _reserved\r\n */\r\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\r\n if (data.length < STAKE_DEPOSIT_SIZE) {\r\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\r\n }\r\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\r\n return {\r\n isInitialized: data[0] === 1,\r\n bump: data[1],\r\n pool: new PublicKey(data.subarray(8, 40)),\r\n user: new PublicKey(data.subarray(40, 72)),\r\n lastDepositSlot: readU64LE(data, 72),\r\n lpAmount: readU64LE(data, 80),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Account Specs (for building TransactionInstructions)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface StakeAccounts {\r\n /** InitPool accounts */\r\n initPool: {\r\n admin: PublicKey;\r\n slab: PublicKey;\r\n pool: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n collateralMint: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n /** Deposit accounts */\r\n deposit: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vault: PublicKey;\r\n lpMint: PublicKey;\r\n userLpAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** Withdraw accounts */\r\n withdraw: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userLpAta: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** FlushToInsurance accounts (CPI from stake → percolator) */\r\n flushToInsurance: {\r\n caller: PublicKey;\r\n pool: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n wrapperVault: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n}\r\n\r\n/**\r\n * Build account keys for InitPool instruction.\r\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\r\n *\r\n * @param a - Named accounts for the InitPool instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function initPoolAccounts(\r\n a: StakeAccounts['initPool'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Deposit instruction.\r\n *\r\n * @param a - Named accounts for the Deposit instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function depositAccounts(\r\n a: StakeAccounts['deposit'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Withdraw instruction.\r\n *\r\n * @param a - Named accounts for the Withdraw instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function withdrawAccounts(\r\n a: StakeAccounts['withdraw'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for FlushToInsurance instruction.\r\n *\r\n * @param a - Named accounts for the FlushToInsurance instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function flushToInsuranceAccounts(\r\n a: StakeAccounts['flushToInsurance'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.caller, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n","/**\r\n * @module adl\r\n * Percolator ADL (Auto-Deleveraging) client utilities.\r\n *\r\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\r\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\r\n * The most profitable positions on the dominant side are deleveraged first.\r\n *\r\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\r\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\r\n * instruction being structurally available to any signer.\r\n *\r\n * API surface:\r\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\r\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\r\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\r\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\r\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\r\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\r\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\r\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\r\n * - AdlRankingResult — full ranking with trigger status\r\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\r\n * - AdlApiRanking — single ranked position from /api/adl/rankings\r\n * - AdlApiResult — full result from /api/adl/rankings\r\n * - AdlSide — \"long\" | \"short\"\r\n */\r\n\r\nimport {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n} from \"@solana/web3.js\";\r\nimport {\r\n fetchSlab,\r\n parseAllAccounts,\r\n parseEngine,\r\n parseConfig,\r\n detectSlabLayout,\r\n AccountKind,\r\n Account,\r\n SlabLayout,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Position side derived from positionSize sign. */\r\nexport type AdlSide = \"long\" | \"short\";\r\n\r\nconst V17_ADL_UNSUPPORTED_MESSAGE =\r\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\r\n\r\n/**\r\n * A ranked open position for ADL purposes.\r\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\r\n * and will be deleveraged first.\r\n */\r\nexport interface AdlRankedPosition {\r\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\r\n idx: number;\r\n /** Owner public key. */\r\n owner: PublicKey;\r\n /** Raw position size (i128 — negative = short, positive = long). */\r\n positionSize: bigint;\r\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\r\n pnl: bigint;\r\n /** Capital at entry in lamports (u128). */\r\n capital: bigint;\r\n /**\r\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\r\n * pnlPct = pnl * 10_000 / capital.\r\n * Higher = more profitable = deleveraged first.\r\n */\r\n pnlPct: bigint;\r\n /** Long or short. */\r\n side: AdlSide;\r\n /**\r\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\r\n * `-1` if position size is zero (inactive).\r\n */\r\n adlRank: number;\r\n}\r\n\r\n/**\r\n * Result of `fetchAdlRankedPositions`.\r\n */\r\nexport interface AdlRankingResult {\r\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\r\n ranked: AdlRankedPosition[];\r\n /**\r\n * Longs ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\r\n */\r\n longs: AdlRankedPosition[];\r\n /**\r\n * Shorts ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\r\n * unrealised gain for the short-side holder).\r\n */\r\n shorts: AdlRankedPosition[];\r\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\r\n isTriggered: boolean;\r\n /** pnl_pos_tot from engine state. */\r\n pnlPosTot: bigint;\r\n /** max_pnl_cap from market config. */\r\n maxPnlCap: bigint;\r\n /**\r\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\r\n *\r\n * `null` when the side cannot be determined — either engine state could not be\r\n * parsed at all, OR the detected slab layout carries no open-interest fields.\r\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\r\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\r\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\r\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\r\n *\r\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\r\n * convention, not an on-chain guarantee — the deployed wrapper\r\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\r\n */\r\n dominantSide: AdlSide | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute PnL% in basis points for a position.\r\n * Returns 0n when capital is 0 to avoid division by zero.\r\n */\r\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\r\n if (capital === 0n) return 0n;\r\n return (pnl * 10_000n) / capital;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check whether ADL is currently triggered on a slab.\r\n *\r\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\r\n *\r\n * @param slabData - Raw slab account bytes.\r\n * @returns true if ADL is triggered.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = await fetchSlab(connection, slabKey);\r\n * if (isAdlTriggered(data)) {\r\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\r\n * }\r\n * ```\r\n */\r\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n if (!layout) return false;\r\n try {\r\n const engine = parseEngine(slabData);\r\n if (engine.pnlPosTot === 0n) return false;\r\n const config = parseConfig(slabData, layout);\r\n if (config.maxPnlCap === 0n) return false;\r\n return engine.pnlPosTot > config.maxPnlCap;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\r\n *\r\n * Positions are ranked separately per side:\r\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\r\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\r\n *\r\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\r\n * the position at rank 0 of the dominant side is deleveraged first.\r\n *\r\n * @param connection - Solana connection.\r\n * @param slab - Slab (market) public key.\r\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\r\n *\r\n * @example\r\n * ```ts\r\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\r\n * if (isTriggered && longs.length > 0) {\r\n * const target = longs[0]; // highest PnL long\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankedPositions(\r\n connection: Connection,\r\n slab: PublicKey\r\n): Promise {\r\n const data = await fetchSlab(connection, slab);\r\n return rankAdlPositions(data);\r\n}\r\n\r\n/**\r\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\r\n * Useful when you already have the slab data (e.g., from a subscription).\r\n */\r\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n\r\n let pnlPosTot = 0n;\r\n let dominantSide: AdlSide | null = null;\r\n try {\r\n const engine = parseEngine(slabData);\r\n pnlPosTot = engine.pnlPosTot;\r\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\r\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\r\n // comparing them would fabricate \"long\" from absent data.\r\n const hasOiFields =\r\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\r\n if (hasOiFields) {\r\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\r\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\r\n }\r\n } catch (err) {\r\n console.warn(\r\n `[rankAdlPositions] parseEngine failed:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n let maxPnlCap = 0n;\r\n let isTriggered = false;\r\n if (layout) {\r\n try {\r\n const config = parseConfig(slabData, layout);\r\n maxPnlCap = config.maxPnlCap;\r\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\r\n } catch {\r\n // If config parse fails, leave isTriggered=false; ranking still useful.\r\n }\r\n }\r\n\r\n // Parse all used accounts.\r\n const accounts = parseAllAccounts(slabData);\r\n\r\n // Build ranked position list (user accounts with non-zero position only).\r\n const positions: AdlRankedPosition[] = [];\r\n for (const { idx, account } of accounts) {\r\n if (account.kind !== AccountKind.User) continue;\r\n if (account.positionSize === 0n) continue;\r\n\r\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\r\n // For shorts, positionSize is negative — PnL computation is symmetric:\r\n // a short profits when price falls, so pnl stored in the slab already\r\n // reflects mark-to-market gain/loss for both sides.\r\n const pnlPct = computePnlPct(account.pnl, account.capital);\r\n\r\n positions.push({\r\n idx,\r\n owner: account.owner,\r\n positionSize: account.positionSize,\r\n pnl: account.pnl,\r\n capital: account.capital,\r\n pnlPct,\r\n side,\r\n adlRank: -1, // assigned below\r\n });\r\n }\r\n\r\n // Rank longs: descending pnlPct (most profitable first).\r\n const longs = positions\r\n .filter(p => p.side === \"long\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n longs.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\r\n // magnitude, but pnlPct can be negative; sort descending still puts\r\n // the \"least negative\" aka \"most profitable\" short first).\r\n const shorts = positions\r\n .filter(p => p.side === \"short\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n shorts.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\r\n const ranked = [...longs, ...shorts].sort(\r\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\r\n );\r\n\r\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\r\n}\r\n\r\n/**\r\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\r\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\r\n * utilities remain available.\r\n *\r\n * This function is kept as a deprecated compatibility stub so consumers get a\r\n * deterministic error instead of a lower-level removed-instruction throw.\r\n *\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key for this market.\r\n * @param programId - Percolator program ID.\r\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\r\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\r\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\r\n */\r\nexport function buildAdlInstruction(\r\n _caller: PublicKey,\r\n _slab: PublicKey,\r\n _oracle: PublicKey,\r\n _programId: PublicKey,\r\n targetIdx: number,\r\n _backupOracles: PublicKey[] = []\r\n): TransactionInstruction {\r\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\r\n throw new Error(\r\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\r\n );\r\n }\r\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\r\n}\r\n\r\n/**\r\n * Choose which ranked position an ADL should target.\r\n *\r\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\r\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\r\n * a test routed through it could not observe the choice.\r\n *\r\n * - An explicit `preferSide` always wins.\r\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\r\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\r\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\r\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\r\n * a candidate, nothing more.\r\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\r\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\r\n * rather than guessing a side.\r\n */\r\nexport function selectAdlTarget(\r\n ranking: Pick,\r\n preferSide?: AdlSide,\r\n): AdlRankedPosition | undefined {\r\n if (preferSide === \"long\") return ranking.longs[0];\r\n if (preferSide === \"short\") return ranking.shorts[0];\r\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\r\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\r\n return ranking.ranked[0];\r\n}\r\n\r\n/**\r\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\r\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\r\n *\r\n * Returns `null` when ADL is not triggered or no eligible positions exist.\r\n *\r\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\r\n * When a target IS found it calls `buildAdlInstruction`, which throws\r\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\r\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\r\n * revision of this note claimed it did, which was simply wrong.) It is kept for\r\n * v12 slabs and for when an equivalent v17 instruction lands; the target\r\n * selection in `selectAdlTarget` stays valid either way.\r\n *\r\n * @param connection - Solana connection.\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key.\r\n * @param programId - Percolator program ID.\r\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\r\n * If omitted, picks the dominant side's (greater net OI)\r\n * top-ranked position — or the overall top-ranked position\r\n * when dominantSide is null (engine unparseable, or a\r\n * layout with no OI fields such as V0/V2/v12.15).\r\n * @param backupOracles - Optional extra oracle accounts.\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = await buildAdlTransaction(\r\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\r\n * );\r\n * if (ix) {\r\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\r\n * }\r\n * ```\r\n */\r\nexport async function buildAdlTransaction(\r\n connection: Connection,\r\n caller: PublicKey,\r\n slab: PublicKey,\r\n oracle: PublicKey,\r\n programId: PublicKey,\r\n preferSide?: AdlSide,\r\n backupOracles: PublicKey[] = []\r\n): Promise {\r\n const ranking = await fetchAdlRankedPositions(connection, slab);\r\n\r\n if (!ranking.isTriggered) return null;\r\n\r\n const target = selectAdlTarget(ranking, preferSide);\r\n\r\n if (!target) return null;\r\n\r\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AdlEvent — on-chain log decoder (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\r\n *\r\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\r\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\r\n *\r\n * Fields:\r\n * - `tag` — always `0xAD1E_0001` (2970353665n)\r\n * - `targetIdx` — slab account index that was deleveraged\r\n * - `price` — oracle price used (in market price units, e.g. e6)\r\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\r\n *\r\n * @example\r\n * ```ts\r\n * const logs = tx.meta?.logMessages ?? [];\r\n * const event = parseAdlEvent(logs);\r\n * if (event) {\r\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\r\n * }\r\n * ```\r\n */\r\nexport interface AdlEvent {\r\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\r\n tag: bigint;\r\n /** Slab account index that was deleveraged. */\r\n targetIdx: number;\r\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\r\n price: bigint;\r\n /**\r\n * Absolute position size closed (reassembled from lo+hi u64).\r\n * This is the i128 absolute value — always non-negative.\r\n */\r\n closedAbs: bigint;\r\n}\r\n\r\n/** Magic discriminator for the ADL event log line. */\r\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\r\n\r\n/**\r\n * Parse the AdlEvent from a transaction's log messages.\r\n *\r\n * Searches for a \"Program log: \" line where the first\r\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\r\n *\r\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\r\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\r\n * by this program ID are accepted. Events from CPI-called programs (which can\r\n * produce identical `Program log:` lines) are silently ignored. Pass the\r\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\r\n * Omit only in contexts where the full log has already been filtered.\r\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\r\n *\r\n * @example\r\n * ```ts\r\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\r\n * if (event) {\r\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\r\n * }\r\n * ```\r\n */\r\nexport function parseAdlEvent(\r\n logs: string[],\r\n percolatorProgramId?: string,\r\n): AdlEvent | null {\r\n // Track whether we are currently inside a top-level Percolator invocation.\r\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\r\n let insidePercolator = percolatorProgramId === undefined;\r\n let cpiDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n if (percolatorProgramId !== undefined) {\r\n // Detect Percolator entry / exit.\r\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\r\n insidePercolator = true;\r\n cpiDepth = 0;\r\n continue;\r\n }\r\n if (\r\n line.startsWith(`Program ${percolatorProgramId} success`) ||\r\n line.startsWith(`Program ${percolatorProgramId} failed`)\r\n ) {\r\n insidePercolator = false;\r\n continue;\r\n }\r\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\r\n if (insidePercolator) {\r\n if (/^Program \\S+ invoke/.test(line)) {\r\n cpiDepth++;\r\n continue;\r\n }\r\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\r\n cpiDepth = Math.max(0, cpiDepth - 1);\r\n continue;\r\n }\r\n }\r\n // Skip log lines that are not inside Percolator or are from a CPI callee.\r\n if (!insidePercolator || cpiDepth > 0) continue;\r\n }\r\n\r\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\r\n const match = line.match(\r\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\r\n );\r\n if (!match) continue;\r\n\r\n let tag: bigint;\r\n try {\r\n tag = BigInt(match[1]);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (tag !== ADL_EVENT_TAG) continue;\r\n\r\n try {\r\n const targetIdx = Number(BigInt(match[2]));\r\n const price = BigInt(match[3]);\r\n const closedLo = BigInt(match[4]);\r\n const closedHi = BigInt(match[5]);\r\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\r\n const closedAbs = (closedHi << 64n) | closedLo;\r\n return { tag, targetIdx, price, closedAbs };\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A single ranked position as returned by the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiRanking {\r\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\r\n rank: number;\r\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\r\n idx: number;\r\n /** Absolute PnL (lamports) as a decimal string. */\r\n pnlAbs: string;\r\n /** Capital at entry (lamports) as a decimal string. */\r\n capital: string;\r\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\r\n pnlPctMillionths: string;\r\n}\r\n\r\n/**\r\n * Full result from the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiResult {\r\n slabAddress: string;\r\n /** pnl_pos_tot from slab engine state (decimal string). */\r\n pnlPosTot: string;\r\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\r\n maxPnlCap: string;\r\n /** Insurance fund balance (decimal string). */\r\n insuranceFundBalance: string;\r\n /** Insurance fund lifetime fee revenue (decimal string). */\r\n insuranceFundFeeRevenue: string;\r\n /** Insurance utilization in basis points (0–10000). */\r\n insuranceUtilizationBps: number;\r\n /** true if pnlPosTot > maxPnlCap. */\r\n capExceeded: boolean;\r\n /** true if insurance fund is fully depleted (balance == 0). */\r\n insuranceDepleted: boolean;\r\n /** true if utilization BPS exceeds the configured ADL threshold. */\r\n utilizationTriggered: boolean;\r\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\r\n adlNeeded: boolean;\r\n /** Excess PnL above cap (decimal string). */\r\n excess: string;\r\n /** Ranked positions (empty if adlNeeded=false). */\r\n rankings: AdlApiRanking[];\r\n}\r\n\r\n/**\r\n * Fetch ADL rankings from the Percolator API.\r\n *\r\n * Calls `GET /api/adl/rankings?slab=
` and returns the\r\n * parsed result. Use this from the frontend or keeper to determine ADL\r\n * trigger status and pick the target index.\r\n *\r\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\r\n * @param slab - Slab (market) public key or base58 address string.\r\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\r\n * @returns Parsed `AdlApiResult`.\r\n * @throws On HTTP error or JSON parse failure.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\r\n * if (result.adlNeeded && result.rankings.length > 0) {\r\n * const target = result.rankings[0]; // rank 1 = highest PnL%\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankings(\r\n apiBase: string,\r\n slab: PublicKey | string,\r\n fetchFn: typeof fetch = fetch,\r\n): Promise {\r\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\r\n const base = apiBase.replace(/\\/$/, \"\");\r\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\r\n\r\n const res = await fetchFn(url);\r\n if (!res.ok) {\r\n let body = \"\";\r\n try { body = await res.text(); } catch { /* ignore */ }\r\n throw new Error(\r\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\r\n );\r\n }\r\n\r\n const json: unknown = await res.json();\r\n\r\n // Runtime validation — the API response shape is not guaranteed\r\n if (typeof json !== \"object\" || json === null) {\r\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\r\n }\r\n const obj = json as Record;\r\n if (!Array.isArray(obj.rankings)) {\r\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\r\n }\r\n if (typeof obj.adlNeeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\r\n }\r\n if (typeof obj.capExceeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\r\n }\r\n if (typeof obj.slabAddress !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\r\n }\r\n if (typeof obj.pnlPosTot !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\r\n }\r\n if (typeof obj.maxPnlCap !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\r\n }\r\n for (const entry of obj.rankings) {\r\n if (typeof entry !== \"object\" || entry === null) {\r\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\r\n }\r\n const r = entry as Record;\r\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\r\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\r\n }\r\n }\r\n\r\n return json as AdlApiResult;\r\n}\r\n","/**\r\n * @module backing-bucket\r\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\r\n *\r\n * ## Why this module exists\r\n *\r\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\r\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\r\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\r\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\r\n * predicate.\r\n *\r\n * ## Why lapsing is routine, not exceptional\r\n *\r\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\r\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\r\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\r\n * bucket and only computes a fresh horizon once the bucket is no longer\r\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\r\n * far-future expiry defers the lapse; it does not prevent it.\r\n *\r\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\r\n *\r\n * | Attempt against a lapsed domain | Result |\r\n * |---|---|\r\n * | settle a **loss** | `EngineLockActive` Custom(21) |\r\n * | settle a **gain** | `EngineStale` Custom(19) |\r\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\r\n *\r\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\r\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\r\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\r\n * keeper duty, alongside the fee crank.\r\n *\r\n * ## Layout provenance\r\n *\r\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\r\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\r\n *\r\n * ```\r\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\r\n * BackingBucketV16Account size=97\r\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\r\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\r\n * 88 expiry_slot 96 status\r\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\r\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\r\n * ```\r\n *\r\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\r\n */\r\n\r\nimport {\r\n V17_MARKET_GROUP_OFF,\r\n V17_MARKET_GROUP_LEN,\r\n V17_MARKET_ASSET_SLOT_LEN,\r\n isV17MarketAccount,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Little-endian readers (module-local, matching slab.ts's private helpers)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8At(data: Uint8Array, off: number): number {\r\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\r\n return data[off]!;\r\n}\r\n\r\nfunction readU32LEAt(data: Uint8Array, off: number): number {\r\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\r\n}\r\n\r\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\r\n}\r\n\r\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\r\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\r\n const lo = dv.getBigUint64(0, true);\r\n const hi = dv.getBigUint64(8, true);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Layout constants — all verified with offset_of! (see module doc)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\r\nexport const V17_GROUP_CONFIG_REL = 32;\r\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\r\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\r\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\r\nexport const V17_GROUP_MODE_REL = 626;\r\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\r\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\r\n\r\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\r\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\r\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\r\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\r\n/** `size_of::()`. */\r\nexport const V17_BACKING_BUCKET_LEN = 97;\r\n\r\n// BackingBucketV16Account field offsets, relative to the bucket start.\r\nconst BB_MARKET_ID = 0;\r\nconst BB_FRESH_UNLIENED = 8;\r\nconst BB_VALID_LIENED = 24;\r\nconst BB_CONSUMED_LIENED = 40;\r\nconst BB_IMPAIRED_LIENED = 56;\r\nconst BB_UTILIZATION_FEE = 72;\r\nconst BB_EXPIRY_SLOT = 88;\r\nconst BB_STATUS = 96;\r\n\r\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\r\nexport const V17_MARKET_MODE_LIVE = 0;\r\n\r\n/**\r\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\r\n * serialized as a single `u8` in declaration order.\r\n *\r\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\r\n */\r\nexport enum BackingBucketStatus {\r\n Empty = 0,\r\n Fresh = 1,\r\n Expired = 2,\r\n Impaired = 3,\r\n}\r\n\r\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\r\nexport function backingBucketStatusName(status: number): string {\r\n switch (status) {\r\n case BackingBucketStatus.Empty:\r\n return \"Empty\";\r\n case BackingBucketStatus.Fresh:\r\n return \"Fresh\";\r\n case BackingBucketStatus.Expired:\r\n return \"Expired\";\r\n case BackingBucketStatus.Impaired:\r\n return \"Impaired\";\r\n default:\r\n return `Unknown(${status})`;\r\n }\r\n}\r\n\r\n/** One source-domain backing bucket, decoded from a v17 market account. */\r\nexport interface BackingBucketV17 {\r\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\r\n domain: number;\r\n /** `domain / 2` — the asset slot this domain belongs to. */\r\n assetIndex: number;\r\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\r\n side: \"long\" | \"short\";\r\n /** `BackingBucketV16Account::market_id`. */\r\n marketId: bigint;\r\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\r\n freshUnlienedBackingNum: bigint;\r\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\r\n validLienedBackingNum: bigint;\r\n /** Principal already consumed by settlement. */\r\n consumedLienedBackingNum: bigint;\r\n /** Principal whose lien has been impaired. */\r\n impairedLienedBackingNum: bigint;\r\n /** Utilization fees accrued to this bucket. */\r\n utilizationFeeEarnings: bigint;\r\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\r\n expirySlot: bigint;\r\n /** Raw status byte. */\r\n status: number;\r\n /** `backingBucketStatusName(status)`. */\r\n statusName: string;\r\n /**\r\n * `status === Fresh && nowSlot >= expirySlot`.\r\n *\r\n * This is the *deadlock* condition — settlement against this domain fails in both\r\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\r\n * which additionally applies the wrapper's mode and domain-bound gates.\r\n */\r\n lapsed: boolean;\r\n /**\r\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\r\n * See {@link isBackingBucketExpirable} for the full derivation.\r\n */\r\n expirable: boolean;\r\n}\r\n\r\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\r\nexport interface BackingBucketMarketState {\r\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\r\n mode: number;\r\n /** `header.current_slot` — the engine's own monotone slot counter. */\r\n headerCurrentSlot: bigint;\r\n /**\r\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\r\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\r\n */\r\n nowSlot: bigint;\r\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\r\n maxMarketSlots: number;\r\n /** Asset slots physically present in the account buffer. */\r\n physicalAssetSlots: number;\r\n /**\r\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\r\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\r\n * this index are never expirable; see {@link isBackingBucketExpirable}.\r\n */\r\n addressableDomainCount: number;\r\n /** One entry per addressable domain, ascending by `domain`. */\r\n buckets: BackingBucketV17[];\r\n}\r\n\r\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\r\nexport interface BackingBucketExpiryContext {\r\n /** `header.mode`. */\r\n mode: number;\r\n /** `max(chainSlot, header.current_slot)`. */\r\n nowSlot: bigint;\r\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\r\n addressableDomainCount: number;\r\n}\r\n\r\n/**\r\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\r\n *\r\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\r\n * program rather than from prose. In order of evaluation on chain:\r\n *\r\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\r\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\r\n * market reaches the same transition through the engine's own\r\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\r\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\r\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\r\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\r\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\r\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\r\n * may be *configured* for more slots than its account was *sized* for.\r\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\r\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\r\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\r\n * both deadlocked and expirable, and the two boundaries agree\r\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\r\n *\r\n * `now_slot` is never caller-supplied — the program computes\r\n * `max(Clock::get().slot, header.current_slot)` itself\r\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\r\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\r\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\r\n * bricked. It cannot produce a false positive, because the program recomputes the same\r\n * `max` and no caller can lower it.\r\n *\r\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\r\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\r\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\r\n * two more u128 reads to defend against something that indicates corruption anyway.\r\n *\r\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\r\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\r\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\r\n *\r\n * @example\r\n * ```ts\r\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\r\n * for (const b of state.buckets) {\r\n * if (isBackingBucketExpirable(b, state)) {\r\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isBackingBucketExpirable(\r\n bucket: Pick,\r\n ctx: BackingBucketExpiryContext,\r\n): boolean {\r\n // (1) Live-only mode gate.\r\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\r\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\r\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\r\n // (4) The lapse condition, exactly as the engine states it.\r\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\r\n return ctx.nowSlot >= bucket.expirySlot;\r\n}\r\n\r\n/** Options for {@link parseBackingBucketsV17}. */\r\nexport interface ParseBackingBucketsOptions {\r\n /**\r\n * The current chain slot (`connection.getSlot()`).\r\n *\r\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\r\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\r\n * lapses, never over-report them) but a keeper should always supply it — a market whose\r\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\r\n * bricked.\r\n */\r\n chainSlot?: bigint | number;\r\n}\r\n\r\n/**\r\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\r\n *\r\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\r\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\r\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\r\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\r\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketPk);\r\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\r\n * chainSlot: await connection.getSlot(),\r\n * });\r\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\r\n * ```\r\n */\r\nexport function parseBackingBucketsV17(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): BackingBucketMarketState {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n const groupOff = V17_MARKET_GROUP_OFF;\r\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\r\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\r\n const maxMarketSlots = readU32LEAt(\r\n data,\r\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\r\n );\r\n\r\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\r\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\r\n const chainSlot =\r\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\r\n if (chainSlot < 0n) {\r\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\r\n }\r\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\r\n\r\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\r\n const physicalAssetSlots = Math.max(\r\n 0,\r\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\r\n );\r\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\r\n const addressableDomainCount = addressableAssetSlots * 2;\r\n\r\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\r\n const buckets: BackingBucketV17[] = [];\r\n\r\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\r\n const engineBase =\r\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\r\n for (const side of [\"long\", \"short\"] as const) {\r\n const bucketOff =\r\n engineBase +\r\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\r\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\r\n\r\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\r\n const status = readU8At(data, bucketOff + BB_STATUS);\r\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\r\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\r\n\r\n const bucket: BackingBucketV17 = {\r\n domain,\r\n assetIndex,\r\n side,\r\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\r\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\r\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\r\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\r\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\r\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\r\n expirySlot,\r\n status,\r\n statusName: backingBucketStatusName(status),\r\n lapsed,\r\n expirable: false,\r\n };\r\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\r\n buckets.push(bucket);\r\n }\r\n }\r\n\r\n return {\r\n mode,\r\n headerCurrentSlot,\r\n nowSlot,\r\n maxMarketSlots,\r\n physicalAssetSlots,\r\n addressableDomainCount,\r\n buckets,\r\n };\r\n}\r\n\r\n/**\r\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\r\n *\r\n * Returns domain indices in ascending order, ready to feed straight into\r\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\r\n * common case on a healthy market, and the case in which a keeper must send nothing.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns Ascending list of expirable domain indices; empty when none are due.\r\n *\r\n * @example\r\n * ```ts\r\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\r\n * for (const domain of domains) {\r\n * tx.add(new TransactionInstruction({\r\n * programId: WRAPPER_ID,\r\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\r\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\r\n * }));\r\n * }\r\n * ```\r\n */\r\nexport function findExpirableBackingDomains(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): number[] {\r\n return parseBackingBucketsV17(data, opts)\r\n .buckets.filter((b) => b.expirable)\r\n .map((b) => b.domain);\r\n}\r\n","import {\r\n Connection,\r\n type Commitment,\r\n type ConnectionConfig,\r\n} from \"@solana/web3.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Configuration for exponential-backoff retry on RPC calls.\r\n *\r\n * @example\r\n * ```ts\r\n * const retryConfig: RetryConfig = {\r\n * maxRetries: 3,\r\n * baseDelayMs: 500,\r\n * maxDelayMs: 10_000,\r\n * retryableStatusCodes: [429, 502, 503],\r\n * };\r\n * ```\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts after the initial request fails.\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Base delay in ms for exponential backoff.\r\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\r\n * @default 500\r\n */\r\n baseDelayMs?: number;\r\n\r\n /**\r\n * Maximum delay in ms (backoff cap).\r\n * @default 10_000\r\n */\r\n maxDelayMs?: number;\r\n\r\n /**\r\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\r\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\r\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\r\n * jitter entirely (deterministic backoff).\r\n * @default 0.25\r\n */\r\n jitterFactor?: number;\r\n\r\n /**\r\n * HTTP status codes considered retryable.\r\n * Errors matching these codes (or containing their string representation)\r\n * will be retried.\r\n * @default [429, 502, 503, 504]\r\n */\r\n retryableStatusCodes?: number[];\r\n}\r\n\r\n/**\r\n * Configuration for a single RPC endpoint in the pool.\r\n *\r\n * @example\r\n * ```ts\r\n * const endpoint: RpcEndpointConfig = {\r\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\r\n * weight: 10,\r\n * label: \"helius-primary\",\r\n * };\r\n * ```\r\n */\r\nexport interface RpcEndpointConfig {\r\n /** RPC endpoint URL. */\r\n url: string;\r\n\r\n /**\r\n * Relative weight for round-robin selection.\r\n * Higher weight = more requests routed here.\r\n * @default 1\r\n */\r\n weight?: number;\r\n\r\n /**\r\n * Human-readable label for logging / diagnostics.\r\n * @default url hostname\r\n */\r\n label?: string;\r\n\r\n /**\r\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\r\n * merged into the Solana `Connection` constructor for this endpoint.\r\n */\r\n connectionConfig?: ConnectionConfig;\r\n}\r\n\r\n/**\r\n * Strategy for selecting the next RPC endpoint from the pool.\r\n *\r\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\r\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\r\n */\r\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\r\n\r\n/**\r\n * Full configuration for the RPC connection pool.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3, baseDelayMs: 500 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Use like a Connection — same surface\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n * ```\r\n */\r\nexport interface RpcPoolConfig {\r\n /**\r\n * One or more RPC endpoints. At least one is required.\r\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\r\n */\r\n endpoints: (RpcEndpointConfig | string)[];\r\n\r\n /**\r\n * How to pick the next endpoint.\r\n * @default \"failover\"\r\n */\r\n strategy?: SelectionStrategy;\r\n\r\n /**\r\n * Retry config applied to every `call()`.\r\n * Set to `false` to disable retries entirely.\r\n * @default { maxRetries: 3, baseDelayMs: 500 }\r\n */\r\n retry?: RetryConfig | false;\r\n\r\n /**\r\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\r\n * calls where supported, and is used as a deadline for the health probe.\r\n * @default 30_000\r\n */\r\n requestTimeoutMs?: number;\r\n\r\n /**\r\n * Default Solana commitment level for connections.\r\n * @default \"confirmed\"\r\n */\r\n commitment?: Commitment;\r\n\r\n /**\r\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n\r\n /**\r\n * Time in ms after which a continuously unhealthy endpoint is automatically\r\n * restored to healthy so it can be retried. Set to 0 to disable time-based\r\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\r\n * endpoints are exhausted).\r\n * @default 60_000\r\n */\r\n recoveryAfterMs?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Health Probe\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Result of an RPC health probe.\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\r\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\r\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\r\n * ```\r\n */\r\nexport interface RpcHealthResult {\r\n /** The endpoint that was probed. */\r\n endpoint: string;\r\n /** Whether the probe succeeded (getSlot returned without error). */\r\n healthy: boolean;\r\n /** Round-trip latency in milliseconds (0 if unhealthy). */\r\n latencyMs: number;\r\n /** Current slot height (0 if unhealthy). */\r\n slot: number;\r\n /** Error message if the probe failed. */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\r\n *\r\n * @param endpoint - RPC URL to probe\r\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\r\n * @returns Health result with latency and slot height\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\r\n * if (result.healthy) {\r\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\r\n * } else {\r\n * console.error(`RPC down: ${result.error}`);\r\n * }\r\n * ```\r\n */\r\nexport async function checkRpcHealth(\r\n endpoint: string,\r\n timeoutMs: number = 5_000,\r\n): Promise {\r\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\r\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\r\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\r\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\r\n const start = performance.now();\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: 1,\r\n method: \"getSlot\",\r\n params: [{ commitment: \"processed\" }],\r\n }),\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n const latencyMs = Math.round(performance.now() - start);\r\n if (!res.ok) {\r\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\r\n }\r\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\r\n if (json?.error || typeof json?.result !== \"number\") {\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: json?.error?.message ?? \"invalid getSlot response\",\r\n };\r\n }\r\n return { endpoint, healthy: true, latencyMs, slot: json.result };\r\n } catch (err) {\r\n const latencyMs = Math.round(performance.now() - start);\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved defaults for RetryConfig. */\r\ninterface ResolvedRetryConfig {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n jitterFactor: number;\r\n retryableStatusCodes: number[];\r\n}\r\n\r\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\r\n if (cfg === false) return null;\r\n const c = cfg ?? {};\r\n return {\r\n maxRetries: c.maxRetries ?? 3,\r\n baseDelayMs: c.baseDelayMs ?? 500,\r\n maxDelayMs: c.maxDelayMs ?? 10_000,\r\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\r\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\r\n };\r\n}\r\n\r\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\r\n if (typeof ep === \"string\") return { url: ep };\r\n return ep;\r\n}\r\n\r\nfunction endpointLabel(ep: RpcEndpointConfig): string {\r\n if (ep.label) return ep.label;\r\n try {\r\n return new URL(ep.url).hostname;\r\n } catch {\r\n return ep.url.slice(0, 40);\r\n }\r\n}\r\n\r\nfunction isRetryable(err: unknown, codes: number[]): boolean {\r\n if (!err) return false;\r\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\r\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\r\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\r\n // error shapes by name BEFORE any substring match below.\r\n const errName = (err as { name?: unknown })?.name;\r\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n for (const code of codes) {\r\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\r\n let timer: ReturnType;\r\n const promise = new Promise((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(message)), ms);\r\n });\r\n return { promise, cancel: () => clearTimeout(timer!) };\r\n}\r\n\r\n/** Sleep utility. */\r\nfunction sleep(ms: number): Promise {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\r\n * key, password) from a URL so it is safe for logging / status output.\r\n */\r\nfunction redactUrl(raw: string): string {\r\n try {\r\n const u = new URL(raw);\r\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\r\n for (const k of [...u.searchParams.keys()]) {\r\n if (sensitive.test(k)) {\r\n u.searchParams.set(k, \"***\");\r\n }\r\n }\r\n return u.toString();\r\n } catch {\r\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\r\n return raw;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// RpcPool\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-endpoint tracked state. */\r\ninterface EndpointState {\r\n config: RpcEndpointConfig;\r\n connection: Connection;\r\n label: string;\r\n weight: number;\r\n /** Consecutive failure count. Resets on success. */\r\n failures: number;\r\n /** Whether this endpoint is considered healthy. */\r\n healthy: boolean;\r\n /** Last probe latency (ms), -1 if never probed. */\r\n lastLatencyMs: number;\r\n /**\r\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\r\n * failure streak. Cleared on success or manual recovery. Used by the\r\n * time-based auto-recovery logic in `selectEndpoint`.\r\n */\r\n unhealthySince?: number;\r\n}\r\n\r\n/**\r\n * RPC connection pool with retry, failover, and round-robin support.\r\n *\r\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\r\n * that automatically retries transient errors and fails over to alternate\r\n * endpoints when one goes down.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Execute any Connection method through the pool\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n *\r\n * // Or get a raw connection for one-off use\r\n * const conn = pool.getConnection();\r\n *\r\n * // Health check all endpoints\r\n * const results = await pool.healthCheck();\r\n * ```\r\n */\r\nexport class RpcPool {\r\n private readonly endpoints: EndpointState[];\r\n private readonly strategy: SelectionStrategy;\r\n private readonly retryConfig: ResolvedRetryConfig | null;\r\n private readonly requestTimeoutMs: number;\r\n private readonly verbose: boolean;\r\n /** Time-based recovery window in ms (0 = disabled). */\r\n private readonly recoveryAfterMs: number;\r\n\r\n /** Round-robin index tracker. */\r\n private rrIndex: number = 0;\r\n\r\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\r\n private static readonly UNHEALTHY_THRESHOLD = 3;\r\n\r\n /** Minimum endpoints before auto-recovery is attempted. */\r\n private static readonly MIN_HEALTHY = 1;\r\n\r\n constructor(config: RpcPoolConfig) {\r\n if (!config.endpoints || config.endpoints.length === 0) {\r\n throw new Error(\"RpcPool: at least one endpoint is required\");\r\n }\r\n\r\n this.strategy = config.strategy ?? \"failover\";\r\n this.retryConfig = resolveRetryConfig(config.retry);\r\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\r\n this.verbose = config.verbose ?? true;\r\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\r\n\r\n const commitment = config.commitment ?? \"confirmed\";\r\n\r\n this.endpoints = config.endpoints.map(raw => {\r\n const ep = normalizeEndpoint(raw);\r\n const connConfig: ConnectionConfig = {\r\n commitment,\r\n ...ep.connectionConfig,\r\n };\r\n return {\r\n config: ep,\r\n connection: new Connection(ep.url, connConfig),\r\n label: endpointLabel(ep),\r\n weight: Math.max(1, ep.weight ?? 1),\r\n failures: 0,\r\n healthy: true,\r\n lastLatencyMs: -1,\r\n };\r\n });\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Public API\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Execute a function against a pooled connection with automatic retry\r\n * and failover.\r\n *\r\n * @param fn - Async function that receives a `Connection` and returns a result.\r\n * @returns The result of `fn`.\r\n * @throws The last error if all retries and failovers are exhausted.\r\n *\r\n * @example\r\n * ```ts\r\n * const balance = await pool.call(c => c.getBalance(pubkey));\r\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\r\n * ```\r\n */\r\n async call(fn: (connection: Connection) => Promise): Promise {\r\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\r\n let lastError: unknown;\r\n\r\n // Track which endpoints we have tried in this call to avoid infinite loops.\r\n const triedEndpoints = new Set();\r\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\r\n const maxTotalIterations = maxAttempts + this.endpoints.length;\r\n let totalIterations = 0;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (++totalIterations > maxTotalIterations) break;\r\n const epIdx = this.selectEndpoint(triedEndpoints);\r\n if (epIdx === -1) {\r\n // All endpoints exhausted\r\n break;\r\n }\r\n const ep = this.endpoints[epIdx];\r\n\r\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\r\n try {\r\n const result = await Promise.race([\r\n fn(ep.connection),\r\n timeout.promise,\r\n ]);\r\n\r\n // Success — reset failure count\r\n ep.failures = 0;\r\n ep.healthy = true;\r\n ep.unhealthySince = undefined;\r\n return result;\r\n } catch (err) {\r\n lastError = err;\r\n ep.failures++;\r\n\r\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\r\n ep.healthy = false;\r\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\r\n );\r\n }\r\n }\r\n\r\n const retryable = this.retryConfig\r\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\r\n : false;\r\n\r\n if (!retryable) {\r\n // For non-retryable errors in failover mode, try the next endpoint\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n // Don't count this as a retry attempt — just failover\r\n attempt--;\r\n if (triedEndpoints.size >= this.endpoints.length) break;\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Retryable error\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n // In failover mode, try next endpoint before retrying same one\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n }\r\n\r\n // Backoff before retry\r\n if (attempt < maxAttempts - 1 && this.retryConfig) {\r\n const delay = computeDelay(attempt, this.retryConfig);\r\n await sleep(delay);\r\n }\r\n } finally {\r\n timeout.cancel();\r\n }\r\n }\r\n\r\n // All attempts exhausted — try recovery before giving up\r\n this.maybeRecoverEndpoints();\r\n\r\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\r\n }\r\n\r\n /**\r\n * Get a raw `Connection` from the current preferred endpoint.\r\n * Useful when you need to pass a Connection to external code.\r\n *\r\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\r\n *\r\n * @returns Solana Connection from the current preferred endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const conn = pool.getConnection();\r\n * const balance = await conn.getBalance(pubkey);\r\n * ```\r\n */\r\n getConnection(): Connection {\r\n const idx = this.selectEndpoint();\r\n if (idx === -1) {\r\n // All marked unhealthy — reset and use first\r\n this.maybeRecoverEndpoints();\r\n return this.endpoints[0].connection;\r\n }\r\n return this.endpoints[idx].connection;\r\n }\r\n\r\n /**\r\n * Run a health check against all endpoints in the pool.\r\n *\r\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\r\n * @returns Array of health results, one per endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await pool.healthCheck();\r\n * for (const r of results) {\r\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\r\n * }\r\n * ```\r\n */\r\n async healthCheck(timeoutMs: number = 5_000): Promise {\r\n const results = await Promise.all(\r\n this.endpoints.map(async (ep) => {\r\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\r\n ep.lastLatencyMs = result.latencyMs;\r\n ep.healthy = result.healthy;\r\n if (result.healthy) {\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n result.endpoint = redactUrl(result.endpoint);\r\n return result;\r\n }),\r\n );\r\n return results;\r\n }\r\n\r\n /**\r\n * Get the number of endpoints in the pool.\r\n */\r\n get size(): number {\r\n return this.endpoints.length;\r\n }\r\n\r\n /**\r\n * Get the number of currently healthy endpoints.\r\n */\r\n get healthyCount(): number {\r\n return this.endpoints.filter(ep => ep.healthy).length;\r\n }\r\n\r\n /**\r\n * Get endpoint labels and their current status.\r\n *\r\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\r\n */\r\n status(): Array<{\r\n label: string;\r\n url: string;\r\n healthy: boolean;\r\n failures: number;\r\n lastLatencyMs: number;\r\n }> {\r\n return this.endpoints.map(ep => ({\r\n label: ep.label,\r\n url: redactUrl(ep.config.url),\r\n healthy: ep.healthy,\r\n failures: ep.failures,\r\n lastLatencyMs: ep.lastLatencyMs,\r\n }));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Internals\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Select the next endpoint based on strategy.\r\n * Returns -1 if no endpoint is available.\r\n */\r\n private selectEndpoint(exclude?: Set): number {\r\n // Time-based auto-recovery: restore endpoints that have been unhealthy\r\n // for longer than recoveryAfterMs so they can be retried.\r\n if (this.recoveryAfterMs > 0) {\r\n const now = Date.now();\r\n for (const ep of this.endpoints) {\r\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n if (this.verbose) {\r\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthy = this.endpoints\r\n .map((ep, i) => ({ ep, i }))\r\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\r\n\r\n if (healthy.length === 0) {\r\n // No healthy endpoints — try all non-excluded\r\n const remaining = this.endpoints\r\n .map((_, i) => i)\r\n .filter(i => !(exclude?.has(i)));\r\n return remaining.length > 0 ? remaining[0] : -1;\r\n }\r\n\r\n if (this.strategy === \"failover\") {\r\n // Return first healthy (by insertion order)\r\n return healthy[0].i;\r\n }\r\n\r\n // Weighted round-robin\r\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\r\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\r\n\r\n let cumulative = 0;\r\n for (const { ep, i } of healthy) {\r\n cumulative += ep.weight;\r\n if (this.rrIndex < cumulative) return i;\r\n }\r\n\r\n return healthy[healthy.length - 1].i;\r\n }\r\n\r\n /**\r\n * If all endpoints are unhealthy, reset them so we at least try again.\r\n */\r\n private maybeRecoverEndpoints(): void {\r\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\r\n if (healthyCount < RpcPool.MIN_HEALTHY) {\r\n if (this.verbose) {\r\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\r\n }\r\n for (const ep of this.endpoints) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone retry wrapper (for use without a full pool)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute an async function with exponential-backoff retry.\r\n *\r\n * Use this when you already have a `Connection` and just want retry logic\r\n * without a full pool.\r\n *\r\n * @param fn - Async function to execute\r\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\r\n * @returns Result of `fn`\r\n * @throws The last error if all retries are exhausted\r\n *\r\n * @example\r\n * ```ts\r\n * import { withRetry } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const slot = await withRetry(\r\n * () => conn.getSlot(),\r\n * { maxRetries: 3, baseDelayMs: 1000 },\r\n * );\r\n * ```\r\n */\r\nexport async function withRetry(\r\n fn: () => Promise,\r\n config?: RetryConfig,\r\n): Promise {\r\n const resolved = resolveRetryConfig(config) ?? {\r\n maxRetries: 3,\r\n baseDelayMs: 500,\r\n maxDelayMs: 10_000,\r\n jitterFactor: 0.25,\r\n retryableStatusCodes: [429, 502, 503, 504],\r\n };\r\n\r\n let lastError: unknown;\r\n const maxAttempts = resolved.maxRetries + 1;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (err) {\r\n lastError = err;\r\n\r\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\r\n throw err;\r\n }\r\n\r\n if (attempt < maxAttempts - 1) {\r\n const delay = computeDelay(attempt, resolved);\r\n await sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-export helpers for testing\r\n// ---------------------------------------------------------------------------\r\n\r\n/** @internal — exposed for unit tests only */\r\nexport const _internal = {\r\n isRetryable,\r\n computeDelay,\r\n resolveRetryConfig,\r\n normalizeEndpoint,\r\n endpointLabel,\r\n} as const;\r\n","import {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n Transaction,\r\n Keypair,\r\n SendOptions,\r\n Commitment,\r\n AccountMeta,\r\n ComputeBudgetProgram,\r\n} from \"@solana/web3.js\";\r\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\r\n\r\n/**\r\n * Rank of the three cluster confirmation levels the RPC reports in\r\n * `SignatureStatus.confirmationStatus`.\r\n */\r\nconst CONFIRMATION_RANK = {\r\n processed: 0,\r\n confirmed: 1,\r\n finalized: 2,\r\n} as const;\r\n\r\n/**\r\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\r\n * The deprecated aliases map onto their modern equivalents exactly as\r\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\r\n * recent -> processed.\r\n */\r\nfunction requiredConfirmationRank(commitment: Commitment): number {\r\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\r\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\r\n // aliases as:\r\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\r\n // 'finalized' | 'max' | 'root' -> requires finalized\r\n // everything else ('processed', 'recent') -> requires >= processed\r\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\r\n // meant a caller asking for `singleGossip` and observing only a `processed`\r\n // status was told the transaction had SETTLED — reintroducing exactly the\r\n // premature-settlement bug this function exists to prevent.\r\n switch (commitment) {\r\n case \"confirmed\":\r\n case \"single\":\r\n case \"singleGossip\":\r\n return CONFIRMATION_RANK.confirmed;\r\n case \"finalized\":\r\n case \"max\":\r\n case \"root\":\r\n return CONFIRMATION_RANK.finalized;\r\n case \"processed\":\r\n case \"recent\":\r\n default:\r\n return CONFIRMATION_RANK.processed;\r\n }\r\n}\r\n\r\n/**\r\n * True when an observed signature status is at least as strong as the level the\r\n * caller asked for. A merely \"processed\" transaction can still be dropped or\r\n * rolled back, so treating it as settled would reintroduce exactly the premature\r\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\r\n */\r\nfunction meetsCommitment(\r\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\r\n required: Commitment\r\n): boolean {\r\n if (!observed) return false;\r\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\r\n}\r\n\r\nexport interface BuildIxParams {\r\n programId: PublicKey;\r\n keys: AccountMeta[];\r\n data: Uint8Array | Buffer;\r\n}\r\n\r\n/**\r\n * Build a transaction instruction.\r\n */\r\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\r\n return new TransactionInstruction({\r\n programId: params.programId,\r\n keys: params.keys,\r\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\r\n // Cast to avoid Buffer polyfill issues in the browser.\r\n data: params.data as Buffer,\r\n });\r\n}\r\n\r\nexport interface TxResult {\r\n signature: string;\r\n slot: number;\r\n err: string | null;\r\n hint?: string;\r\n logs: string[];\r\n unitsConsumed?: number;\r\n}\r\n\r\nexport interface SimulateOrSendParams {\r\n connection: Connection;\r\n ix: TransactionInstruction;\r\n signers: Keypair[];\r\n simulate: boolean;\r\n commitment?: Commitment;\r\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\r\n /**\r\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\r\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\r\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\r\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\r\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\r\n * multiple of 1024 in [32768, 262144].\r\n */\r\n heapFrameBytes?: number;\r\n}\r\n\r\n/**\r\n * Simulate or send a transaction.\r\n * Returns consistent output for both modes.\r\n */\r\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\r\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\r\n\r\n/**\r\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\r\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\r\n */\r\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\r\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\r\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\r\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\r\n\r\nexport async function simulateOrSend(\r\n params: SimulateOrSendParams\r\n): Promise {\r\n const {\r\n connection,\r\n ix,\r\n signers,\r\n simulate,\r\n commitment,\r\n computeUnitLimit,\r\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\r\n } = params;\r\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\r\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\r\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\r\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\r\n\r\n if (typeof simulate !== \"boolean\") {\r\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\r\n }\r\n\r\n if (!signers.length) {\r\n throw new Error(\"simulateOrSend: at least one signer is required\");\r\n }\r\n\r\n if (computeUnitLimit !== undefined) {\r\n if (\r\n typeof computeUnitLimit !== \"number\" ||\r\n !Number.isInteger(computeUnitLimit) ||\r\n computeUnitLimit < 1 ||\r\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\r\n ) {\r\n throw new Error(\r\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\r\n );\r\n }\r\n }\r\n\r\n if (heapFrameBytes !== 0) {\r\n if (\r\n typeof heapFrameBytes !== \"number\" ||\r\n !Number.isInteger(heapFrameBytes) ||\r\n heapFrameBytes % 1024 !== 0 ||\r\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\r\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\r\n ) {\r\n throw new Error(\r\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\r\n );\r\n }\r\n }\r\n\r\n const tx = new Transaction();\r\n\r\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\r\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\r\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\r\n if (heapFrameBytes !== 0) {\r\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\r\n }\r\n\r\n // Add compute budget instruction if custom limit is specified\r\n if (computeUnitLimit !== undefined) {\r\n tx.add(\r\n ComputeBudgetProgram.setComputeUnitLimit({\r\n units: computeUnitLimit,\r\n })\r\n );\r\n }\r\n\r\n tx.add(ix);\r\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\r\n tx.recentBlockhash = latestBlockhash.blockhash;\r\n tx.feePayer = signers[0].publicKey;\r\n\r\n if (simulate) {\r\n try {\r\n tx.sign(...signers);\r\n const result = await connection.simulateTransaction(tx, signers);\r\n const logs = result.value.logs ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (result.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(result.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature: \"(simulated)\",\r\n slot: result.context.slot,\r\n err,\r\n hint,\r\n logs,\r\n unitsConsumed: result.value.unitsConsumed ?? undefined,\r\n };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"(simulated)\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n }\r\n\r\n // Send\r\n const options: SendOptions = {\r\n skipPreflight: false,\r\n preflightCommitment: effectiveCommitment,\r\n };\r\n\r\n // sendTransaction is its own try/catch: only here is it true that no\r\n // signature was ever produced, so signature: \"\" is the correct result.\r\n let signature: string;\r\n try {\r\n signature = await connection.sendTransaction(tx, signers, options);\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n\r\n // Fetch logs at the same finality level used for confirmation.\r\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\r\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\r\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\r\n\r\n try {\r\n const confirmation = await connection.confirmTransaction(\r\n {\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n },\r\n effectiveCommitment\r\n );\r\n\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (confirmation.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(confirmation.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature,\r\n slot: txInfo?.slot ?? 0,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n } catch (e: unknown) {\r\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\r\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\r\n // only that we didn't observe confirmation in time. Previously this branch discarded\r\n // the real signature obtained above and returned signature: \"\", which left the caller\r\n // with no way to check whether it's safe to retry — for a non-idempotent operation\r\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\r\n // transaction that had actually already landed. Check the real on-chain status before\r\n // reporting failure, and always return the real signature so the caller can verify\r\n // it themselves even if this fallback check also fails.\r\n const message = e instanceof Error ? e.message : String(e);\r\n try {\r\n const status = await connection.getSignatureStatus(signature, {\r\n searchTransactionHistory: true,\r\n });\r\n // Only treat the fallback lookup as authoritative when the observed level\r\n // actually satisfies the commitment the caller asked for. `status.value`\r\n // being non-null merely means the cluster has SEEN the transaction — at\r\n // \"processed\" it can still be dropped or rolled back, and reporting that\r\n // as a settled success would be the same premature-settlement bug #311 fixed.\r\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n if (status.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(status.value.err);\r\n }\r\n }\r\n return {\r\n signature,\r\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\r\n // `status.context.slot` is the RPC's head slot at query time — a\r\n // different, much later number — so it must not be used as the tx slot.\r\n slot: txInfo?.slot ?? status.value.slot,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n }\r\n if (status.value) {\r\n // Seen, but weaker than requested. Report it as unresolved rather than\r\n // settled, while still handing back the signature and the real landing slot.\r\n const observed = status.value.confirmationStatus ?? \"unknown\";\r\n return {\r\n signature,\r\n slot: status.value.slot,\r\n err:\r\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\r\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\r\n `Check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n } catch {\r\n // Status lookup itself failed too — fall through to the ambiguous result below,\r\n // which still carries the real signature instead of discarding it.\r\n }\r\n return {\r\n signature,\r\n slot: 0,\r\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Format transaction result for output.\r\n */\r\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\r\n if (jsonMode) {\r\n return JSON.stringify(result, null, 2);\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n if (result.err) {\r\n lines.push(`Error: ${result.err}`);\r\n if (result.hint) {\r\n lines.push(`Hint: ${result.hint}`);\r\n }\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.logs.length > 0) {\r\n lines.push(\"Logs:\");\r\n result.logs.forEach((log) => lines.push(` ${log}`));\r\n }\r\n } else {\r\n lines.push(`Signature: ${result.signature}`);\r\n lines.push(`Slot: ${result.slot}`);\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.signature !== \"(simulated)\") {\r\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * @module lighthouse\r\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\r\n *\r\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\r\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\r\n * scanning service. It adds assertion instructions to transactions that verify account\r\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\r\n * X lamports\").\r\n *\r\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\r\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\r\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\r\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\r\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\r\n * logic is correct.\r\n *\r\n * **Solution:** The SDK provides utilities to:\r\n * 1. Detect Lighthouse instructions in a transaction\r\n * 2. Strip them before sending\r\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\r\n * 4. Provide clear, actionable error messages for end users\r\n *\r\n * @example\r\n * ```ts\r\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\r\n *\r\n * // Before sending: strip injected Lighthouse IXs\r\n * const cleanIxs = stripLighthouseInstructions(instructions);\r\n *\r\n * // After error: classify and give user-friendly message\r\n * if (isLighthouseError(error)) {\r\n * console.warn(\"Wallet middleware blocked the transaction\");\r\n * }\r\n * ```\r\n */\r\n\r\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\r\n *\r\n * This is an immutable Anchor program deployed at slot 294,179,293.\r\n * Wallets like Phantom inject instructions from this program into user\r\n * transactions to enforce Blowfish security assertions.\r\n */\r\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\r\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\r\n);\r\n\r\n/** Base58 string form for fast comparison without PublicKey instantiation. */\r\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\r\n\r\n/**\r\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\r\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\r\n * when an account constraint check fails.\r\n */\r\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\r\n\r\n/**\r\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\r\n * All are in the Anchor error range (0x1770–0x1900+).\r\n */\r\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\r\n 0x1770, // InstructionMissing\r\n 0x1771, // InstructionFallbackNotFound\r\n 0x1772, // InstructionDidNotDeserialize\r\n 0x1773, // InstructionDidNotSerialize\r\n 0x1780, // IdlInstructionStub\r\n 0x1790, // ConstraintMut\r\n 0x1791, // ConstraintHasOne\r\n 0x1792, // ConstraintSigner\r\n 0x1793, // ConstraintRaw\r\n 0x1794, // ConstraintOwner\r\n 0x1795, // ConstraintRentExempt\r\n 0x1796, // ConstraintSeeds\r\n 0x1797, // ConstraintExecutable\r\n 0x1798, // ConstraintState\r\n 0x1799, // ConstraintAssociated\r\n 0x179a, // ConstraintAssociatedInit\r\n 0x179b, // ConstraintClose\r\n 0x1900, // ConstraintAddress (the one we hit most often)\r\n] as const);\r\n\r\n// ============================================================================\r\n// Detection\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a TransactionInstruction is from the Lighthouse program.\r\n *\r\n * @param ix - A Solana transaction instruction.\r\n * @returns `true` if the instruction's programId is Lighthouse.\r\n *\r\n * @example\r\n * ```ts\r\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\r\n * ```\r\n */\r\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\r\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if an error message or error object indicates a Lighthouse assertion failure.\r\n *\r\n * Detects:\r\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\r\n * - References to the Lighthouse program ID in error text\r\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\r\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\r\n * failing program is Lighthouse (identified by program ID in logs)\r\n *\r\n * @param error - An Error object, error message string, or transaction logs array.\r\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await sendTransaction(tx);\r\n * } catch (e) {\r\n * if (isLighthouseError(e)) {\r\n * // Retry with skipPreflight or notify user about wallet middleware\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isLighthouseError(error: unknown): boolean {\r\n const msg = extractErrorMessage(error);\r\n if (!msg) return false;\r\n\r\n // Direct program ID reference\r\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\r\n\r\n // 0x1900 hex error code (case-insensitive)\r\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\r\n\r\n // JSON InstructionError format: {\"Custom\": 6400}\r\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if transaction logs contain evidence of a Lighthouse failure.\r\n *\r\n * More precise than `isLighthouseError` on a string — examines the program\r\n * invocation chain to confirm the error originates from Lighthouse, not from\r\n * a Percolator instruction that happens to return a similar code.\r\n *\r\n * @param logs - Array of transaction log lines from `getTransaction()`.\r\n * @returns `true` if logs show a Lighthouse program failure.\r\n */\r\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\r\n if (!Array.isArray(logs)) return false;\r\n\r\n let lighthouseDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n // Track Lighthouse program invocation depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\r\n lighthouseDepth++;\r\n continue;\r\n }\r\n\r\n // Lighthouse program returned success — decrement depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\r\n if (lighthouseDepth > 0) lighthouseDepth--;\r\n continue;\r\n }\r\n\r\n // Only report failure when the Lighthouse program itself explicitly fails\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// Stripping / Mitigation\r\n// ============================================================================\r\n\r\n/**\r\n * Remove all Lighthouse assertion instructions from an instruction array.\r\n *\r\n * Call this before building a Transaction to prevent Lighthouse assertion\r\n * failures. Safe to call even if no Lighthouse instructions are present.\r\n *\r\n * @param instructions - Array of transaction instructions.\r\n * @returns Filtered array with Lighthouse instructions removed.\r\n *\r\n * @example\r\n * ```ts\r\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\r\n *\r\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\r\n * const clean = stripLighthouseInstructions(instructions);\r\n * const tx = new Transaction().add(...clean);\r\n * ```\r\n */\r\nexport function stripLighthouseInstructions(\r\n instructions: TransactionInstruction[],\r\n percolatorProgramId?: PublicKey,\r\n): TransactionInstruction[] {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions — prevents misuse on\r\n // arbitrary transactions where Lighthouse guards are legitimate protection.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) {\r\n return instructions; // no Percolator instructions — leave guards intact\r\n }\r\n }\r\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\r\n}\r\n\r\n/**\r\n * Strip Lighthouse instructions from an already-built Transaction.\r\n *\r\n * Creates a new Transaction with the same recentBlockhash and feePayer\r\n * but without any Lighthouse instructions. The returned transaction is\r\n * unsigned and must be re-signed.\r\n *\r\n * @param transaction - A Transaction (signed or unsigned).\r\n * @returns A new Transaction without Lighthouse instructions, or the same\r\n * transaction if no Lighthouse instructions were found.\r\n *\r\n * @example\r\n * ```ts\r\n * const signed = await wallet.signTransaction(tx);\r\n * if (hasLighthouseInstructions(signed)) {\r\n * const clean = stripLighthouseFromTransaction(signed);\r\n * const reSigned = await wallet.signTransaction(clean);\r\n * await connection.sendRawTransaction(reSigned.serialize());\r\n * }\r\n * ```\r\n */\r\nexport function stripLighthouseFromTransaction(\r\n transaction: Transaction,\r\n percolatorProgramId?: PublicKey,\r\n): Transaction {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = transaction.instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) return transaction;\r\n }\r\n\r\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\r\n if (!hasLighthouse) return transaction;\r\n\r\n const clean = new Transaction();\r\n clean.recentBlockhash = transaction.recentBlockhash;\r\n clean.feePayer = transaction.feePayer;\r\n\r\n for (const ix of transaction.instructions) {\r\n if (!isLighthouseInstruction(ix)) {\r\n clean.add(ix);\r\n }\r\n }\r\n\r\n return clean;\r\n}\r\n\r\n/**\r\n * Count Lighthouse instructions in an instruction array or transaction.\r\n *\r\n * @param ixsOrTx - Array of instructions or a Transaction.\r\n * @returns Number of Lighthouse instructions found.\r\n */\r\nexport function countLighthouseInstructions(\r\n ixsOrTx: TransactionInstruction[] | Transaction,\r\n): number {\r\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\r\n return instructions.filter(isLighthouseInstruction).length;\r\n}\r\n\r\n// ============================================================================\r\n// User-facing error messages\r\n// ============================================================================\r\n\r\n/**\r\n * User-friendly error message for Lighthouse assertion failures.\r\n *\r\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\r\n */\r\nexport const LIGHTHOUSE_USER_MESSAGE =\r\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\r\n \"This is a known compatibility issue — the transaction itself is valid. \" +\r\n \"Try one of these workarounds:\\n\" +\r\n \"1. Disable transaction simulation in your wallet settings\\n\" +\r\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\r\n \"3. The SDK will automatically retry without the guard\";\r\n\r\n/**\r\n * Classify an error and return an appropriate user-facing message.\r\n *\r\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\r\n * Otherwise returns `null` (callers should use their own error display).\r\n *\r\n * @param error - An Error, string, or logs array.\r\n * @returns User-facing message string, or `null` if not a Lighthouse error.\r\n */\r\nexport function classifyLighthouseError(error: unknown): string | null {\r\n if (isLighthouseError(error)) {\r\n return LIGHTHOUSE_USER_MESSAGE;\r\n }\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Internal helpers\r\n// ============================================================================\r\n\r\nfunction extractErrorMessage(error: unknown): string | null {\r\n if (!error) return null;\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n if (typeof error === \"object\" && \"message\" in error) {\r\n return String((error as { message: unknown }).message);\r\n }\r\n try {\r\n return JSON.stringify(error);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Coin-margined perpetual trade math utilities.\r\n *\r\n * On-chain PnL formula:\r\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\r\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\r\n *\r\n * All prices are in e6 format (1 USD = 1_000_000).\r\n * All token amounts are in native units (e.g. lamports).\r\n */\r\n\r\n/**\r\n * Compute mark-to-market PnL for an open position.\r\n */\r\nexport function computeMarkPnl(\r\n positionSize: bigint,\r\n entryPrice: bigint,\r\n oraclePrice: bigint,\r\n): bigint {\r\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n const diff =\r\n positionSize > 0n\r\n ? oraclePrice - entryPrice\r\n : entryPrice - oraclePrice;\r\n return (diff * absPos) / oraclePrice;\r\n}\r\n\r\n/**\r\n * Compute liquidation price given entry, capital, position and maintenance margin.\r\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\r\n */\r\nexport function computeLiqPrice(\r\n entryPrice: bigint,\r\n capital: bigint,\r\n positionSize: bigint,\r\n maintenanceMarginBps: bigint,\r\n): bigint {\r\n if (positionSize === 0n || entryPrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n // capitalPerUnit scaled by 1e6 for precision\r\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\r\n\r\n if (positionSize > 0n) {\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\r\n const liq = entryPrice - adjusted;\r\n return liq > 0n ? liq : 0n;\r\n } else {\r\n // Guard: short positions liquidate when price rises above liq price.\r\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\r\n // meaning the position can never be liquidated. Return max u64 to signal this.\r\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\r\n return entryPrice + adjusted;\r\n }\r\n}\r\n\r\n/**\r\n * Compute estimated liquidation price BEFORE opening a trade.\r\n * Accounts for trading fees reducing effective capital.\r\n */\r\nexport function computePreTradeLiqPrice(\r\n oracleE6: bigint,\r\n margin: bigint,\r\n posSize: bigint,\r\n maintBps: bigint,\r\n feeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\r\n const absPos = posSize < 0n ? -posSize : posSize;\r\n const signedPos = direction === \"long\" ? absPos : -absPos;\r\n // Fee adjusts the effective entry price, not the capital.\r\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\r\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\r\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\r\n let adjustedEntry: bigint;\r\n if (direction === \"long\") {\r\n adjustedEntry = oracleE6 + feeAdjust;\r\n } else {\r\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\r\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\r\n // feeBps >= 10000, misleading the UI into showing the position is safe.\r\n const shortEntry = oracleE6 - feeAdjust;\r\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\r\n }\r\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\r\n}\r\n\r\n/**\r\n * Compute trading fee from notional value and fee rate in bps.\r\n */\r\nexport function computeTradingFee(\r\n notional: bigint,\r\n tradingFeeBps: bigint,\r\n): bigint {\r\n return (notional * tradingFeeBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Dynamic fee tier configuration.\r\n */\r\nexport interface FeeTierConfig {\r\n /** Base trading fee (Tier 1) in bps */\r\n baseBps: bigint;\r\n /** Tier 2 fee in bps (0 = disabled) */\r\n tier2Bps: bigint;\r\n /** Tier 3 fee in bps (0 = disabled) */\r\n tier3Bps: bigint;\r\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\r\n tier2Threshold: bigint;\r\n /** Notional threshold to enter Tier 3 */\r\n tier3Threshold: bigint;\r\n}\r\n\r\n/**\r\n * Compute the effective fee rate in bps using the tiered fee schedule.\r\n *\r\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\r\n * - notional < tier2Threshold → baseBps (Tier 1)\r\n * - notional < tier3Threshold → tier2Bps (Tier 2)\r\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\r\n *\r\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\r\n */\r\nexport function computeDynamicFeeBps(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n if (config.tier2Threshold === 0n) return config.baseBps;\r\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\r\n if (notional >= config.tier2Threshold) return config.tier2Bps;\r\n return config.baseBps;\r\n}\r\n\r\n/**\r\n * Compute the dynamic trading fee for a given notional and tier config.\r\n *\r\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\r\n * via micro-trades).\r\n */\r\nexport function computeDynamicTradingFee(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n const feeBps = computeDynamicFeeBps(notional, config);\r\n if (notional <= 0n || feeBps <= 0n) return 0n;\r\n return (notional * feeBps + 9999n) / 10000n;\r\n}\r\n\r\n/**\r\n * Fee split configuration.\r\n */\r\nexport interface FeeSplitConfig {\r\n /** LP vault share in bps (0–10_000) */\r\n lpBps: bigint;\r\n /** Protocol treasury share in bps */\r\n protocolBps: bigint;\r\n /** Market creator share in bps */\r\n creatorBps: bigint;\r\n}\r\n\r\n/**\r\n * Compute fee split for a total fee amount.\r\n *\r\n * Returns [lpShare, protocolShare, creatorShare].\r\n * If all split params are 0, 100% goes to LP (legacy behavior).\r\n * Creator gets the rounding remainder to ensure total is preserved.\r\n */\r\nexport function computeFeeSplit(\r\n totalFee: bigint,\r\n config: FeeSplitConfig,\r\n): [bigint, bigint, bigint] {\r\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\r\n return [totalFee, 0n, 0n];\r\n }\r\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\r\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\r\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\r\n }\r\n if (totalBps !== 10000n) {\r\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\r\n }\r\n\r\n const lp = (totalFee * config.lpBps) / 10000n;\r\n const protocol = (totalFee * config.protocolBps) / 10000n;\r\n const creator = totalFee - lp - protocol;\r\n return [lp, protocol, creator];\r\n}\r\n\r\n/**\r\n * Compute PnL as a percentage of capital.\r\n *\r\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\r\n * Number(bigint) silently truncates values above 2^53, which can produce\r\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\r\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\r\n */\r\nexport function computePnlPercent(\r\n pnlTokens: bigint,\r\n capital: bigint,\r\n): number {\r\n if (capital === 0n) return 0;\r\n const scaledPct = (pnlTokens * 10_000n) / capital;\r\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\r\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\r\n // unhandled exceptions from crashing the UI on large positions.\r\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\r\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\r\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\r\n return Number(scaledPct) / 100;\r\n}\r\n\r\n/**\r\n * Estimate entry price including fee impact (slippage approximation).\r\n */\r\nexport function computeEstimatedEntryPrice(\r\n oracleE6: bigint,\r\n tradingFeeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n) return 0n;\r\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\r\n if (direction === \"long\") return oracleE6 + feeImpact;\r\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\r\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\r\n // when fee >= 100%, misleading the UI.\r\n const shortEntry = oracleE6 - feeImpact;\r\n return shortEntry > 0n ? shortEntry : 1n;\r\n}\r\n\r\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\r\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\r\n\r\n/**\r\n * Convert per-slot funding rate (bps) to annualized percentage.\r\n */\r\nexport function computeFundingRateAnnualized(\r\n fundingRateBpsPerSlot: bigint,\r\n): number {\r\n // Clamp rather than throw: extreme funding rates are display-only values;\r\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\r\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\r\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\r\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\r\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\r\n return (bpsPerSlot * slotsPerYear) / 100;\r\n}\r\n\r\n/**\r\n * Compute margin required for a given notional and initial margin bps.\r\n */\r\nexport function computeRequiredMargin(\r\n notional: bigint,\r\n initialMarginBps: bigint,\r\n): bigint {\r\n return (notional * initialMarginBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, as an exact ratio.\r\n *\r\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\r\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\r\n * {@link computeMaxLeverageFloor} instead.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\r\n }\r\n // Use floating-point division so fractional leverage is preserved.\r\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\r\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\r\n return 10000 / Number(initialMarginBps);\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, floored to a whole\r\n * multiplier — the conservative integer form used by risk/sizing math.\r\n *\r\n * Kept separate from {@link computeMaxLeverage} because that one is a display\r\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\r\n * DOWN also keeps client-side caps at or below what the program enforces, so a\r\n * caller can never build a position the chain would reject on leverage.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\r\n }\r\n return 10000n / initialMarginBps;\r\n}\r\n","/**\r\n * Warmup leverage cap utilities.\r\n *\r\n * During the market warmup period, capital is released linearly over\r\n * `warmupPeriodSlots` slots, which constrains the effective leverage\r\n * and maximum position size available to traders.\r\n */\r\n\r\nimport { computeMaxLeverageFloor } from \"./trading.js\";\r\n\r\n// =============================================================================\r\n// Warmup leverage cap utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Compute unlocked capital during the warmup period.\r\n *\r\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\r\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\r\n * warmup period is 0, all capital is considered unlocked.\r\n *\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The amount of capital currently unlocked.\r\n */\r\nexport function computeWarmupUnlockedCapital(\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n // No warmup configured or not started → all capital available\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\r\n if (totalCapital <= 0n) return 0n;\r\n\r\n const elapsed = currentSlot > warmupStartSlot\r\n ? currentSlot - warmupStartSlot\r\n : 0n;\r\n\r\n // Warmup complete\r\n if (elapsed >= warmupPeriodSlots) return totalCapital;\r\n\r\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\r\n return (totalCapital * elapsed) / warmupPeriodSlots;\r\n}\r\n\r\n/**\r\n * Compute the effective maximum leverage during the warmup period.\r\n *\r\n * During warmup, only unlocked capital can be used as margin. The effective\r\n * leverage relative to *total* capital is therefore capped at:\r\n *\r\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\r\n *\r\n * This returns a floored integer value (leverage is always a whole number\r\n * in the UI), with a minimum of 1x if any capital is unlocked.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The effective maximum leverage (integer, ≥ 1).\r\n */\r\nexport function computeWarmupLeverageCap(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): number {\r\n // Integer form: this is risk/sizing math, and the fractional\r\n // computeMaxLeverage() is a display value that cannot be used in BigInt\r\n // arithmetic. Flooring also keeps the client cap at or below the program's.\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n\r\n // No warmup or warmup not started → full leverage\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\r\n if (totalCapital <= 0n) return 1;\r\n\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n\r\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\r\n\r\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\r\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\r\n return Math.max(1, effectiveLev);\r\n}\r\n\r\n/**\r\n * Compute the maximum position size allowed during warmup.\r\n *\r\n * This is the unlocked capital multiplied by the base max leverage.\r\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\r\n * relative to total capital), this gives the absolute notional cap.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns Maximum position size in native units.\r\n */\r\nexport function computeWarmupMaxPositionSize(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n return unlocked * maxLev;\r\n}\r\n","/**\r\n * Input validation utilities for CLI commands.\r\n * Provides descriptive error messages for invalid input.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\n// Constants for numeric limits\r\nconst U16_MAX = 65535;\r\nconst U64_MAX = BigInt(\"18446744073709551615\");\r\nconst I64_MIN = BigInt(\"-9223372036854775808\");\r\nconst I64_MAX = BigInt(\"9223372036854775807\");\r\nconst U128_MAX = (1n << 128n) - 1n;\r\nconst I128_MIN = -(1n << 127n);\r\nconst I128_MAX = (1n << 127n) - 1n;\r\n\r\nexport class ValidationError extends Error {\r\n constructor(\r\n public readonly field: string,\r\n message: string\r\n ) {\r\n super(`Invalid ${field}: ${message}`);\r\n this.name = \"ValidationError\";\r\n }\r\n}\r\n\r\n/**\r\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\r\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\r\n */\r\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\r\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n */\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\r\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n *\r\n * @param value - The string to validate.\r\n * @param field - The field name used in error messages.\r\n * @returns The trimmed, validated decimal string.\r\n */\r\nexport function requireDecimalUIntString(value: string, field: string): string {\r\n const t = value.trim();\r\n if (t === \"\") {\r\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\r\n }\r\n if (!DECIMAL_UINT_RE.test(t)) {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\r\n );\r\n }\r\n return t;\r\n}\r\n\r\n/**\r\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\r\n * (hex, scientific notation, underscores, fractions, leading zeros).\r\n *\r\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\r\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\r\n *\r\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\r\n * @param caller - The calling function name, used in the error message.\r\n * @returns The parsed BigInt value.\r\n * @throws {Error} When `val` does not match the strict decimal integer format.\r\n *\r\n * @example\r\n * safeBigInt(\"123\", \"encU64\") // 123n\r\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\r\n * safeBigInt(\"0x1\", \"encU64\") // throws\r\n * safeBigInt(\"1e5\", \"encU128\") // throws\r\n */\r\nexport function safeBigInt(val: string, caller: string): bigint {\r\n const t = val.trim();\r\n if (!DECIMAL_INT_RE.test(t)) {\r\n throw new Error(\r\n `${caller}: \"${val}\" is not a valid decimal integer ` +\r\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\r\n );\r\n }\r\n return BigInt(t);\r\n}\r\n\r\n/**\r\n * Validate a public key string.\r\n */\r\nexport function validatePublicKey(value: string, field: string): PublicKey {\r\n try {\r\n return new PublicKey(value);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid base58 public key. ` +\r\n `Example: \"11111111111111111111111111111111\"`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate a non-negative integer index (u16 range for accounts).\r\n */\r\nexport function validateIndex(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a non-negative amount (u64 range).\r\n */\r\nexport function validateAmount(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U64_MAX} (u64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a u128 value.\r\n */\r\nexport function validateU128(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U128_MAX} (u128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i64 value.\r\n */\r\nexport function validateI64(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I64_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I64_MIN} (i64 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I64_MAX} (i64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i128 value (trade sizes).\r\n */\r\nexport function validateI128(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I128_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I128_MIN} (i128 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I128_MAX} (i128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a basis points value (0-10000).\r\n */\r\nexport function validateBps(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > 10000n) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= 10000 (100%), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a u64 value.\r\n */\r\nexport function validateU64(value: string, field: string): bigint {\r\n return validateAmount(value, field);\r\n}\r\n\r\n/**\r\n * Validate a u16 value.\r\n */\r\nexport function validateU16(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n","/**\r\n * Smart Price Router — automatic oracle selection for any token.\r\n *\r\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\r\n * ranks them by liquidity/reliability, and returns the best oracle config.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\r\n\r\nexport interface PriceSource {\r\n type: PriceSourceType;\r\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\r\n address: string;\r\n /** DEX id for dex sources */\r\n dexId?: string;\r\n /** Pair label e.g. \"SOL / USDC\" */\r\n pairLabel?: string;\r\n /** USD liquidity depth — higher is better */\r\n liquidity: number;\r\n /** Latest spot price in USD */\r\n price: number;\r\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\r\n confidence: number;\r\n}\r\n\r\nexport interface PriceRouterResult {\r\n mint: string;\r\n bestSource: PriceSource | null;\r\n allSources: PriceSource[];\r\n /** ISO timestamp of resolution */\r\n resolvedAt: string;\r\n}\r\n\r\n/** Options for {@link resolvePrice}. */\r\nexport interface ResolvePriceOptions {\r\n timeoutMs?: number;\r\n}\r\n\r\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\r\n\r\nfunction isRecord(v: unknown): v is Record {\r\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\r\n const already = signals.find((s) => s.aborted);\r\n if (already) {\r\n const c = new AbortController();\r\n c.abort(already.reason);\r\n return c.signal;\r\n }\r\n const active = signals.filter((s) => !s.aborted);\r\n if (active.length === 0) {\r\n const c = new AbortController();\r\n c.abort();\r\n return c.signal;\r\n }\r\n if (active.length === 1) return active[0];\r\n const ctrl = new AbortController();\r\n for (const s of active) {\r\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\r\n }\r\n return ctrl.signal;\r\n}\r\n\r\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\r\n\r\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\r\n if (!isRecord(json)) return [];\r\n const rawPairs = json.pairs;\r\n if (!Array.isArray(rawPairs)) return [];\r\n const sources: PriceSource[] = [];\r\n\r\n for (const pair of rawPairs) {\r\n if (!isRecord(pair)) continue;\r\n if (pair.chainId !== \"solana\") continue;\r\n const dexId = String(pair.dexId || \"\").toLowerCase();\r\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\r\n\r\n let liquidity = 0;\r\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\r\n liquidity = pair.liquidity.usd;\r\n }\r\n if (liquidity < 100) continue;\r\n\r\n let confidence = 30;\r\n if (liquidity > 1_000_000) confidence = 90;\r\n else if (liquidity > 100_000) confidence = 75;\r\n else if (liquidity > 10_000) confidence = 60;\r\n else if (liquidity > 1_000) confidence = 45;\r\n\r\n const priceUsd = pair.priceUsd;\r\n const price =\r\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\r\n ? parseFloat(String(priceUsd)) || 0\r\n : 0;\r\n\r\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\r\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\r\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\r\n // any source without a usable positive price.\r\n if (!(price > 0)) continue;\r\n\r\n let baseSym = \"?\";\r\n let quoteSym = \"?\";\r\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\r\n baseSym = pair.baseToken.symbol;\r\n }\r\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\r\n quoteSym = pair.quoteToken.symbol;\r\n }\r\n\r\n const addr = pair.pairAddress;\r\n sources.push({\r\n type: \"dex\",\r\n address: typeof addr === \"string\" ? addr : \"\",\r\n dexId,\r\n pairLabel: `${baseSym} / ${quoteSym}`,\r\n liquidity,\r\n price,\r\n confidence,\r\n });\r\n }\r\n\r\n sources.sort((a, b) => b.liquidity - a.liquidity);\r\n return sources.slice(0, 10);\r\n}\r\n\r\n/**\r\n * Parse a Jupiter price row.\r\n *\r\n * Handles BOTH shapes:\r\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\r\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\r\n *\r\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\r\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\r\n * cross-validation in this module was silently inert, including the #227/#315\r\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\r\n * mock or a proxy that still speaks v2 keeps working.\r\n */\r\nfunction parseJupiterMintEntry(\r\n json: unknown,\r\n mint: string,\r\n): { price: number; mintSymbol: string; liquidity: number } | null {\r\n if (!isRecord(json)) return null;\r\n\r\n // v3: the mint is a top-level key.\r\n const v3Row = json[mint];\r\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\r\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\r\n if (price <= 0) return null;\r\n const liquidity =\r\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\r\n ? v3Row.liquidity\r\n : 0;\r\n return { price, mintSymbol: \"?\", liquidity };\r\n }\r\n\r\n // v2 (retired): rows live under `data`.\r\n const data = json.data;\r\n if (!isRecord(data)) return null;\r\n const row = data[mint];\r\n if (!isRecord(row)) return null;\r\n const rawPrice = row.price;\r\n if (rawPrice === undefined || rawPrice === null) return null;\r\n const price = parseFloat(String(rawPrice)) || 0;\r\n if (price <= 0) return null;\r\n let mintSymbol = \"?\";\r\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\r\n return { price, mintSymbol, liquidity: 0 };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const PYTH_SOLANA_FEEDS: Record = {\r\n // SOL\r\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\r\n // BTC\r\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\r\n // ETH\r\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\r\n // USDC\r\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\r\n // USDT\r\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\r\n // BONK\r\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\r\n // JTO\r\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\r\n // JUP\r\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\r\n // PYTH\r\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\r\n // RAY\r\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\r\n // ORCA\r\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\r\n // MNGO\r\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\r\n // MSOL\r\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\r\n // JITOSOL\r\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\r\n // WIF\r\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\r\n // RENDER\r\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\r\n // W\r\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\r\n // TNSR\r\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\r\n // HNT\r\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\r\n // MOBILE\r\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\r\n // IOT\r\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\r\n};\r\nObject.freeze(PYTH_SOLANA_FEEDS);\r\n\r\n// Reverse lookup: mint → feed ID\r\nconst MINT_TO_PYTH_FEED = new Map();\r\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\r\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DexScreener fetcher\r\n// ---------------------------------------------------------------------------\r\n\r\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\r\n\r\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\r\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\r\n}\r\n\r\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return [];\r\n const json: unknown = await resp.json();\r\n return parseDexScreenerPairs(json);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth lookup\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction lookupPythSource(mint: string): PriceSource | null {\r\n const entry = MINT_TO_PYTH_FEED.get(mint);\r\n if (!entry) return null;\r\n return {\r\n type: \"pyth\",\r\n address: entry.feedId,\r\n pairLabel: `${entry.symbol} / USD (Pyth)`,\r\n liquidity: Infinity, // Pyth is considered deep liquidity\r\n price: 0, // We don't fetch live price here; caller can enrich\r\n confidence: 95, // Pyth is highest reliability for supported tokens\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Jupiter price fallback\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return null;\r\n const json: unknown = await resp.json();\r\n const row = parseJupiterMintEntry(json, mint);\r\n if (!row) return null;\r\n return {\r\n type: \"jupiter\",\r\n address: mint,\r\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\r\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\r\n // Used below to decide whether Jupiter is a credible enough reference to\r\n // demote a disagreeing pool.\r\n liquidity: row.liquidity,\r\n price: row.price,\r\n confidence: 40, // Fallback — lower confidence\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main resolver\r\n// ---------------------------------------------------------------------------\r\n\r\nexport async function resolvePrice(\r\n mint: string,\r\n signal?: AbortSignal,\r\n options?: ResolvePriceOptions,\r\n): Promise {\r\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\r\n const combinedSignal = signal\r\n ? combineAbortSignals([signal, timeoutSignal])\r\n : timeoutSignal;\r\n\r\n const [dexSources, jupiterSource] = await Promise.all([\r\n fetchDexSources(mint, combinedSignal),\r\n fetchJupiterSource(mint, combinedSignal),\r\n ]);\r\n\r\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\r\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\r\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\r\n // the common case for permissionless markets — had its top DEX source ranked\r\n // purely on self-reported liquidity, with no check against an independent price\r\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\r\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\r\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\r\n // source's confidence to Jupiter's when they diverge beyond the same tightened\r\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\r\n // independent reference purely on liquidity. The source stays in allSources for\r\n // transparency; only its ranking weight is reduced.\r\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\r\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\r\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\r\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\r\n // ahead and bestSource unchanged.\r\n const DISTRUST_CONFIDENCE_MARGIN = 1;\r\n if (jupiterSource && jupiterSource.price > 0) {\r\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\r\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\r\n // itself — enrichment reads dexSources[0].price, which is untouched; only\r\n // ranking weight changes, and Pyth's own confidence (95) still outranks\r\n // everything here.\r\n //\r\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\r\n // Jupiter is an aggregate across venues, so it is normally the better\r\n // reference — but with v2 retired a malformed/empty response used to yield a\r\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\r\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\r\n // ranking alone rather than trust it.\r\n const jupiterIsCredible = jupiterSource.liquidity > 0;\r\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\r\n if (jupiterIsCredible) {\r\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\r\n // returns up to 10 pools and confidence is a step function of liquidity, so a\r\n // second pool in the same tier would otherwise keep its score and win\r\n // bestSource at the divergent price.\r\n for (const dex of dexSources) {\r\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\r\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\r\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\r\n dex.confidence = Math.min(dex.confidence, distrusted);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const pythSource = lookupPythSource(mint);\r\n\r\n const allSources: PriceSource[] = [];\r\n\r\n // Add Pyth if available (highest priority for supported tokens)\r\n if (pythSource) {\r\n // Enrich Pyth price from Jupiter or DEX if available.\r\n // Guard: only push a Pyth source when we have at least one live price\r\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\r\n // at crank time on devnet/mainnet.\r\n const dexPrice = dexSources[0]?.price ?? 0;\r\n const jupPrice = jupiterSource?.price ?? 0;\r\n // #227: cross-validate the enrichment reference so a single manipulable DEX\r\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\r\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\r\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\r\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\r\n //\r\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\r\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\r\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\r\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\r\n let enrichedPrice = 0;\r\n let singleSource = false;\r\n if (dexPrice > 0 && jupPrice > 0) {\r\n const mid = (dexPrice + jupPrice) / 2;\r\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\r\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\r\n enrichedPrice = mid;\r\n } else {\r\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\r\n // DEX and Jupiter are still added below at their own confidence levels.\r\n console.warn(\r\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\r\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\r\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\r\n );\r\n }\r\n } else if (dexPrice > 0 || jupPrice > 0) {\r\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\r\n singleSource = true;\r\n }\r\n if (enrichedPrice > 0) {\r\n pythSource.price = enrichedPrice;\r\n if (singleSource) {\r\n pythSource.confidence = Math.min(pythSource.confidence, 50);\r\n }\r\n allSources.push(pythSource);\r\n }\r\n }\r\n\r\n // Add DEX sources\r\n allSources.push(...dexSources);\r\n\r\n // Add Jupiter as fallback\r\n if (jupiterSource) {\r\n allSources.push(jupiterSource);\r\n }\r\n\r\n // Sort by confidence descending (already accounts for liquidity/reliability)\r\n allSources.sort((a, b) => b.confidence - a.confidence);\r\n\r\n return {\r\n mint,\r\n bestSource: allSources[0] || null,\r\n allSources,\r\n resolvedAt: new Date().toISOString(),\r\n };\r\n}\r\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA,EAGA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AACA,WAAW,KAAK,OAAO,OAAO,iBAAiB,EAAG,QAAO,OAAO,CAAC;AACjE,OAAO,OAAO,iBAAiB;AAQxB,SAAS,YAAY,MAAqC;AAC/D,SAAO,kBAAkB,IAAI;AAC/B;AAQO,SAAS,aAAa,MAAsB;AACjD,SAAO,kBAAkB,IAAI,GAAG,QAAQ,WAAW,IAAI;AACzD;AAQO,SAAS,aAAa,MAAkC;AAC7D,SAAO,kBAAkB,IAAI,GAAG;AAClC;AAGA,IAAM,2BAA2B;AAiB1B,SAAS,mBAAmB,MAI1B;AACP,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,KAAK,IAAI;AAAA,IACb,0CAA0C,wBAAwB;AAAA,IAClE;AAAA,EACF;AACA,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,UAAU;AAC3B;AAAA,IACF;AACA,UAAM,QAAQ,IAAI,MAAM,EAAE;AAC1B,QAAI,OAAO;AACT,YAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAClC,UAAI,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,KAAK,OAAO,YAAa;AAC5D;AAAA,MACF;AACA,YAAM,OAAO,YAAY,IAAI;AAC7B,aAAO;AAAA,QACL;AAAA,QACA,MAAM,MAAM,QAAQ,WAAW,IAAI;AAAA,QACnC,MAAM,MAAM;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AC/ZA,SAAS,aAAAC,kBAAiB;;;ACvB1B,SAAS,aAAAC,kBAAiB;AAOnB,SAAS,QAAQ,KAAiC;AACvD,MAAI;AACF,WAAO,OAAO,YAAY,eAAe,SAAS,MAC9C,QAAQ,IAAI,GAAG,IACf;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA;AAAA;AAAA;AAAA,IAIN,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACF;AACA,OAAO,OAAO,YAAY,MAAM;AAChC,OAAO,OAAO,YAAY,OAAO;AACjC,OAAO,OAAO,WAAW;AAelB,IAAM,kBAAkB;AAAA;AAAA,EAE7B,YAAY;AAAA;AAAA,EAEZ,SAAS;AAAA;AAAA,EAET,KAAK;AAAA;AAAA,EAEL,OAAO;AACT;AACA,OAAO,OAAO,eAAe;AAGtB,IAAM,iBAAiB,IAAIA,WAAU,gBAAgB,UAAU;AAKtE,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC,YAAY,OAAO;AAAA,EACnB,YAAY,QAAQ;AAAA,EACpB,gBAAgB;AAClB,CAAC;AAGD,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC,YAAY,OAAO;AAAA,EACnB,YAAY,QAAQ;AACtB,CAAC;AASD,SAAS,uBAAgC;AACvC,SAAO,QAAQ,uCAAuC,MAAM;AAC9D;AAUO,SAAS,aAAa,SAA8B;AAKzD,MAAI,YAAY,QAAW;AACzB,UAAM,WAAW,QAAQ,YAAY;AACrC,QAAI,UAAU;AACZ,UAAI,CAAC,kBAAkB,IAAI,QAAQ,KAAK,CAAC,qBAAqB,GAAG;AAC/D,cAAM,IAAI;AAAA,UACR,wCAAwC,QAAQ,qDAC7B,CAAC,GAAG,iBAAiB,EAAE,KAAK,IAAI,CAAC;AAAA,QAGtD;AAAA,MACF;AACA,cAAQ,KAAK,oDAAoD,QAAQ,EAAE;AAC3E,aAAO,IAAIA,WAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,kBAAkB,kBAAkB;AAC1C,QAAM,gBAAgB,WAAW;AACjC,QAAM,YAAY,YAAY,aAAa,EAAE;AAE7C,SAAO,IAAIA,WAAU,SAAS;AAChC;AAKO,SAAS,oBAAoB,SAA8B;AAEhE,MAAI,YAAY,QAAW;AACzB,UAAM,WAAW,QAAQ,oBAAoB;AAC7C,QAAI,UAAU;AACZ,UAAI,CAAC,kBAAkB,IAAI,QAAQ,KAAK,CAAC,qBAAqB,GAAG;AAC/D,cAAM,IAAI;AAAA,UACR,gDAAgD,QAAQ,6DACrC,CAAC,GAAG,iBAAiB,EAAE,KAAK,IAAI,CAAC;AAAA,QAGtD;AAAA,MACF;AACA,cAAQ,KAAK,4DAA4D,QAAQ,EAAE;AACnF,aAAO,IAAIA,WAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,kBAAkB,kBAAkB;AAC1C,QAAM,gBAAgB,WAAW;AACjC,QAAM,YAAY,YAAY,aAAa,EAAE;AAE7C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,mCAAmC,aAAa,EAAE;AAAA,EACpE;AAEA,SAAO,IAAIA,WAAU,SAAS;AAChC;AAcO,SAAS,oBAA6B;AAC3C,QAAM,UAAU,QAAQ,SAAS,GAAG,YAAY;AAChD,MAAI,YAAY,aAAa,YAAY,gBAAgB;AACvD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ADxJA,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA;AAAA,EACA,gBAAgB;AAAA;AAClB,CAAC;AAED,IAAM,uBAAuB,QAAQ,gBAAgB;AACrD,IAAI,yBAAyB,UAAa,CAAC,sBAAsB,IAAI,oBAAoB,GAAG;AAC1F,QAAM,IAAI;AAAA,IACR,4CAA4C,oBAAoB,yDAC7C,CAAC,GAAG,qBAAqB,EAAE,KAAK,IAAI,CAAC;AAAA,EAE1D;AACF;AAYO,IAAM,iBAAiB,IAAIC,WAAU,wBAAwB,gBAAgB,GAAG;AAEhF,SAAS,kBAA6B;AAC3C,SAAO;AACT;AAMO,IAAM,aAAa;AAAA,EACxB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,oBAAoB;AACtB;AAOO,SAAS,cAAc,YAAgC;AAC5D,QAAM,gBAAgB,OAAO,YAAY,YAAY;AACrD,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,CAAC,IAAI,WAAW;AACpB,MAAI,IAAI,eAAe,CAAC;AACxB,SAAO;AACT;AAGO,SAAS,gBAA4B;AAC1C,SAAO,IAAI,WAAW,CAAC,WAAW,eAAe,CAAC;AACpD;AAGO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,WAAW,aAAa,CAAC;AAClD;AAGO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,WAAW,aAAa,CAAC;AAClD;AAOO,SAAS,qBAAiC;AAC/C,SAAO,IAAI,WAAW,CAAC,WAAW,kBAAkB,CAAC;AACvD;AA8BO,SAAS,qBACd,MACA,MACiE;AACjE,MAAI,KAAK,WAAW,KAAK,QAAQ;AAC/B,UAAM,IAAI;AAAA,MACR,0DAA0D,KAAK,MAAM,SAAS,KAAK,MAAM;AAAA,IAC3F;AAAA,EACF;AACA,SAAO,KAAK,IAAI,CAAC,MAAM,OAAO;AAAA,IAC5B,QAAQ,KAAK,CAAC;AAAA,IACd,UAAU,SAAS,OAAO,SAAS;AAAA,IACnC,YAAY,SAAS,OAAO,SAAS;AAAA,EACvC,EAAE;AACJ;AAsBO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,EAAM;AAAA,EAAK;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC3D;AAoBO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAChD;AAgBO,IAAM,8BAA6C;AAAA,EACxD;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAChD;AA4BO,IAAM,yBAAwC;AAAA,EACnD;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC1C;AAMA,IAAM,OAAO,IAAI,YAAY;AAE7B,SAAS,OAAO,OAAe,OAA2B;AACxD,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,OAAQ;AAC3D,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB;AAAA,EAC1C;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AACjD,SAAO;AACT;AAEA,SAAS,OAAO,OAAwB,OAA2B;AACjE,QAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC1D,MAAI,IAAI,MAAM,IAAI,qBAAwB;AACxC,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB;AAAA,EAC1C;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,aAAa,GAAG,GAAG,IAAI;AAChD,SAAO;AACT;AAaO,SAAS,aACd,kBACA,UACA,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,cAAc,GAAG,iBAAiB,QAAQ,GAAG,OAAO,UAAU,UAAU,CAAC;AAAA,IACtF;AAAA,EACF;AACF;AAUO,SAAS,cACd,mBACA,aACA,aAAwB,gBACH;AACrB,QAAM,IAAI,MAAM,kEAAkE;AACpF;AAMO,SAAS,oBACd,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,gBAAgB,CAAC;AAAA,IAC9B;AAAA,EACF;AACF;AAQO,SAAS,wBACd,SACA,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,qBAAqB,GAAG,QAAQ,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAwBO,IAAM,yBAAyB;AACtC,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAqC7B,SAAS,iBAAiB,MAAgB,QAAwB;AAChE,QAAM,KAAK,KAAK,aAAa,QAAQ,IAAI;AACzC,QAAM,KAAK,KAAK,aAAa,SAAS,GAAG,IAAI;AAC7C,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,UAAU;AACxB,WAAO,YAAY,MAAM;AAAA,EAC3B;AACA,SAAO;AACT;AAMO,SAAS,wBAAwB,MAAoC;AAC1E,MAAI,KAAK,SAAS,wBAAwB;AACxC,UAAM,IAAI;AAAA,MACR,kCAAkC,KAAK,MAAM,MAAM,sBAAsB;AAAA,IAC3E;AAAA,EACF;AAEA,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,QAAM,QAAQ,KAAK,aAAa,GAAG,IAAI;AACvC,MAAI,UAAU,oBAAoB;AAChC,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,KAAK,CAAC,MAAM,sBAAsB;AACpC,UAAM,IAAI,MAAM,4CAA4C,KAAK,CAAC,CAAC,EAAE;AAAA,EACvE;AAEA,QAAM,sBAAsB,IAAIA,WAAU,KAAK,SAAS,KAAK,GAAG,CAAC;AAEjE,SAAO;AAAA,IACL,SAAS,KAAK,CAAC;AAAA,IACf,MAAM,KAAK,CAAC;AAAA,IACZ,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IACrD,SAAS,IAAIA,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IAC5C,YAAY,KAAK,UAAU,IAAI,IAAI;AAAA,IACnC,YAAY,KAAK,EAAE;AAAA,IACnB,iBAAiB,iBAAiB,MAAM,EAAE;AAAA,IAC1C,aAAa,iBAAiB,MAAM,EAAE;AAAA,IACtC,gBAAgB,KAAK,aAAa,KAAK,IAAI;AAAA,IAC3C,iBAAiB,KAAK,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,IACA,eAAe;AAAA,IACf,UAAU,KAAK,YAAY,KAAK,IAAI;AAAA,EACtC;AACF;;;AErcA,SAAqB,aAAAC,kBAAiB;AAQtC,SAAS,GAAG,MAA4B;AACtC,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACnE;AAEA,SAAS,OAAO,MAAkB,KAAqB;AACrD,MAAI,OAAO,KAAK,QAAQ;AACtB,UAAM,IAAI,WAAW,kBAAkB,GAAG,0BAA0B,KAAK,MAAM,GAAG;AAAA,EACpF;AACA,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,aAAa,KAAK,IAAI;AACxC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,YAAY,KAAK,IAAI;AACvC;AAUA,SAAS,WAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAK,UAAU,KAAK,MAAM;AAChC,QAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AACpC,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,UAAU;AACxB,WAAO,YAAY,MAAM;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,SAAS,WAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAK,UAAU,KAAK,MAAM;AAChC,QAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AACpC,SAAQ,MAAM,MAAO;AACvB;AAsBA,IAAM,QAAgB;AAGf,IAAM,aAAa;AAG1B,IAAM,gBAAgB,KAAK;AAmE3B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAIxB,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAM7B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AAGtB,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAIxB,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AACvC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,kCAAkC;AACxC,IAAM,uBAAuB;AAK7B,IAAM,qCAAqC;AAC3C,IAAM,2BAA2B;AAUjC,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAIzB,IAAM,2BAA2B;AACjC,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB;AACxB,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,mCAAmC;AACzC,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAElC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,uCAAuC;AAC7C,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAElC,IAAM,wBAAwB;AAU9B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;AAG7B,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AAkBvC,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAKzB,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAEhC,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAGhC,IAAM,oBAAoB;AAI1B,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,oCAAoC;AAG1C,IAAM,8BAA8B;AAEpC,IAAM,mCAAmC;AACzC,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,+BAA+B;AAErC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AAEnC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAC7C,IAAM,gCAAgC;AACtC,IAAM,mCAAmC;AAEzC,IAAM,yCAAyC;AAC/C,IAAM,yCAAyC;AAO/C,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,oCAAoC;AAE1C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAK3C,IAAM,0BAA0B;AAIhC,IAAM,gCAAgC;AACtC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AAmBrC,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAGhC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AAErC,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAE1B,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAG5C,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,8BAA8B;AAWpC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,mCAAmC;AACzC,IAAM,uCAAuC;AAC7C,IAAM,yBAAyB;AAC/B,IAAM,+BAA+B;AACrC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AACnC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAC7C,IAAM,gCAAgC;AACtC,IAAM,mCAAmC;AACzC,IAAM,yCAAyC;AAE/C,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,oCAAoC;AAC1C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAC3C,IAAM,yCAAyC;AAI/C,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,+BAA+B;AACrC,IAAM,6BAA6B;AASnC,IAAM,4BAA4B;AAClC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,0BAA0B;AAChC,IAAM,gCAAgC;AACtC,IAAM,kCAAkC;AAkBxC,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAIlC,IAAM,6BAAiC;AACvC,IAAM,0BAAiC;AACvC,IAAM,uBAAiC;AACvC,IAAM,sBAAiC;AACvC,IAAM,+BAAiC;AACvC,IAAM,mCAAmC;AAIzC,IAAM,8BAAiC;AACvC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,wBAAiC;AACvC,IAAM,8BAAiC;AACvC,IAAM,oCAAoC;AAE1C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAC3C,IAAM,iCAAiC;AACvC,IAAM,yCAAyC;AAC/C,IAAM,kCAAkC;AACxC,IAAM,0CAA0C;AAIhD,IAAM,qBAAqB;AAC3B,IAAM,iCAAkC;AACxC,IAAM,oCAAoC;AAC1C,IAAM,0BAAkC;AACxC,IAAM,0BAAkC;AAIxC,IAAM,2BAAkC;AACxC,IAAM,iCAAkC;AAExC,IAAM,oCAAoC;AAG1C,IAAM,0BAAkC;AACxC,IAAM,gCAAkC;AACxC,IAAM,wCAAwC;AAG9C,IAAM,2BAAkC;AAGxC,IAAM,eAAe,oBAAI,IAAoB;AAyB7C,IAAM,oBAA8B;AACpC,IAAM,sBAA8B;AACpC,IAAM,2BAA8B;AAEpC,IAAM,sBAA8B;AAGpC,IAAM,yBAA8B;AAGpC,IAAM,wBAA8B;AACpC,IAAM,0BAA8B;AACpC,IAAM,+BAA+B;AAGrC,IAAM,0BAAkC;AACxC,IAAM,uBAAkC;AACxC,IAAM,sBAAkC;AACxC,IAAM,+BAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,8BAAkC;AACxC,IAAM,6BAAkC;AACxC,IAAM,yBAAkC;AACxC,IAAM,iCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,wBAAkC;AACxC,IAAM,8BAAkC;AACxC,IAAM,gCAAkC;AACxC,IAAM,oCAAoC;AAC1C,IAAM,iCAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,gCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,sCAAsC;AAC5C,IAAM,kCAAkC;AACxC,IAAM,uCAAuC;AAG7C,IAAM,2BAAoC;AAC1C,IAAM,iCAAoC;AAC1C,IAAM,gCAAoC;AAE1C,IAAM,oCAAoC;AAC1C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,oCAAoC;AAC1C,IAAM,0BAAmC;AACzC,IAAM,gCAAmC;AACzC,IAAM,wCAAwC;AAC9C,IAAM,8BAAmC;AACzC,IAAM,gCAAmC;AACzC,IAAM,iCAAmC;AACzC,IAAM,kCAAmC;AACzC,IAAM,sCAAsC;AAC5C,IAAM,iCAAmC;AACzC,IAAM,+BAAmC;AACzC,IAAM,gCAAmC;AAKzC,IAAM,qCAAqC;AAC3C,IAAM,oCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,8BAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,4CAA4C;AAClD,IAAM,kCAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,qCAAqC;AAC3C,IAAM,sCAAsC;AAC5C,IAAM,0CAA0C;AAChD,IAAM,qCAAqC;AAC3C,IAAM,mCAAoC;AAC1C,IAAM,oCAAoC;AAG1C,IAAM,eAAe,oBAAI,IAAoB;AAO7C,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAEzB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAM/B,IAAM,kBAAkB;AAGxB,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,mCAAmC;AACzC,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAElC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,uCAAuC;AAC7C,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,kCAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,sCAAsC;AAC5C,IAAM,mCAAmC;AAKzC,IAAM,wBAAwB;AAc9B,IAAM,oBAAoB;AAI1B,IAAM,yBAAyB;AAIxB,IAAM,aAAa;AACnB,IAAM,wBAAwB;AAQrC,SAAS,gBACP,WACA,WACA,aACA,aAIA,aAAa,IACL;AACR,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,YAAY,cAAc,cAAc;AACjD;AAEA,IAAM,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI;AAGlC,IAAM,WAAW,oBAAI,IAAoB;AACzC,IAAM,WAAW,oBAAI,IAAoB;AAEzC,IAAM,kBAAkB,oBAAI,IAAoB;AAEhD,IAAM,YAAY,oBAAI,IAAoB;AAO1C,IAAM,WAAW,oBAAI,IAAoB;AAEzC,IAAM,YAAY,oBAAI,IAAoB;AAE1C,IAAM,cAAc,oBAAI,IAAoB;AAM5C,IAAM,aAAa,oBAAI,IAAoB;AAI3C,IAAM,qBAAqB,oBAAI,IAAoB;AAInD,IAAM,cAAc,oBAAI,IAAoB;AAC5C,IAAM,mBAAmB,oBAAI,IAAoB;AACjD,WAAW,KAAK,OAAO;AACrB,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AACxF,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AACxF,kBAAgB,IAAI,gBAAgB,sBAAsB,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AAGtG,YAAU,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,CAAC,GAAG,CAAC;AAE/F,mBAAiB,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE,GAAG,CAAC;AAGvG,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,GAAG,EAAE,GAAG,CAAC;AAG5F,YAAU,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE,GAAG,CAAC;AAGhG,cAAY,IAAI,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAGxG,aAAW,IAAI,gBAAgB,iBAAiB,wBAAwB,mBAAmB,GAAG,EAAE,GAAG,CAAC;AAGpG,qBAAmB,IAAI,gBAAgB,yBAAyB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAItH,cAAY,IAAI,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAExG,eAAa,IAAI,gBAAgB,mBAAmB,0BAA0B,qBAAqB,GAAG,EAAE,GAAG,CAAC;AAC9G;AAEA,aAAa,IAAI,gBAAgB,mBAAmB,0BAA0B,qBAAqB,MAAM,EAAE,GAAG,IAAI;AAElH,aAAa,IAAI,QAAQ,GAAG;AAO5B,IAAM,eAAe,CAAC,KAAK,MAAM,IAAI;AACrC,WAAW,KAAK,cAAc;AAC5B,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE;AACpC,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,IAAI;AAG1B,QAAM,eAAe,2BAA2B,cAAc,aAAa;AAC3E,QAAM,oBAAoB,KAAK,KAAK,eAAe,EAAE,IAAI;AACzD,QAAM,aAAa,oBAAoB,oBAAoB,IAAI,sBAAsB,sBAAsB,IAAI;AAC/G,eAAa,IAAI,YAAY,CAAC;AAG9B,QAAM,YAAY,+BAA+B,cAAc,aAAa;AAC5E,QAAM,iBAAiB,KAAK,KAAK,YAAY,CAAC,IAAI;AAClD,QAAM,UAAU,wBAAwB,iBAAiB,IAAI,0BAA0B,sBAAsB,IAAI;AACjH,eAAa,IAAI,SAAS,CAAC;AAC7B;AAeA,IAAM,wBAA6B;AACnC,IAAM,oBAA6B;AACnC,IAAM,wBAA6B;AACnC,IAAM,0BAA6B;AAOnC,IAAM,+BAAsC;AAS5C,IAAM,gCAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,oCAA4C;AAElD,IAAM,4CAA4C;AAClD,IAAM,8BAA4C;AAClD,IAAM,oCAA4C;AAClD,IAAM,4CAA4C;AAClD,IAAM,oCAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,sCAA4C;AAClD,IAAM,kCAA4C;AAClD,IAAM,0CAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,yCAA4C;AAClD,IAAM,mCAA4C;AAClD,IAAM,oCAA4C;AAsBlD,IAAM,eAAe,oBAAI,IAAoB;AAAA,EAC3C,CAAC,OAAO,EAAE;AAAA;AAAA,EACV,CAAC,OAAO,GAAG;AAAA;AAAA,EACX,CAAC,QAAQ,IAAI;AAAA;AAAA,EACb,CAAC,SAAS,IAAI;AAAA;AAChB,CAAC;AAeD,SAAS,kBAAkB,aAAqB,UAA8B;AAE5E,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa,+BAA+B;AAClD,QAAM,cAAc,aAAa;AACjC,QAAM,cAAc,cAAc;AAClC,QAAM,cAAc,cAAc,cAAc;AAChD,QAAM,iBAAiB,cAAc,cAAc;AACnD,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACvD,QAAM,cAAc,wBAAwB;AAK5C,QAAM,OAAO;AAAA,IAAkB;AAAA;AAAA,IAA6C;AAAA,EAAK;AAEjF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,iBAAiB;AAAA;AAAA,IAEjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAElB,wBAAwB;AAAA;AAAA,IAExB,mBAAmB;AAAA,EACrB;AACF;AAMA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC/F,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,YAAY,uBAAuB,cAAc,KAAK,IAAI;AAChE,QAAM,cAAc,KAAK,KAAK,YAAY,CAAC,IAAI;AAC/C,QAAM,QAAQ,uBAAuB,cAAc,IAAI;AACvD,cAAY,IAAI,OAAO,CAAC;AAC1B;AAEA,IAAM,iBAAiB,oBAAI,IAAoB;AAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC/F,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,YAAY,uBAAuB,cAAc,KAAK,IAAI;AAChE,QAAM,cAAc,KAAK,KAAK,YAAY,CAAC,IAAI;AAC/C,QAAM,QAAQ,uBAAuB,cAAc,IAAI;AACvD,iBAAe,IAAI,OAAO,CAAC;AAC7B;AAOO,IAAM,gBAAgB,OAAO,OAAO;AAAA,EACzC,OAAO,EAAE,aAAa,KAAM,UAAU,OAAW,OAAO,SAAU,aAAa,kCAAkC;AAAA,EACjH,OAAO,EAAE,aAAa,MAAM,UAAU,SAAW,OAAO,SAAU,aAAa,oCAAoC;AACrH,CAAU;AAQH,IAAM,iBAAgH,CAAC;AAC9H,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE;AAC3F,iBAAe,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,uBAAuB;AACzH;AACA,OAAO,OAAO,cAAc;AAQrB,IAAM,kBAAiH,CAAC;AAC/H,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,iBAAiB,wBAAwB,mBAAmB,GAAG,EAAE;AAC9F,kBAAgB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,iCAAiC;AACpI;AACA,OAAO,OAAO,eAAe;AAQtB,IAAM,mBAAkH,CAAC;AAChI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE;AACjG,mBAAiB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,2BAA2B;AAC/H;AACA,OAAO,OAAO,gBAAgB;AAM9B,SAAS,YAAY,SAAgB,aAAqB,mBAAwC;AAChG,QAAM,OAAO,YAAY;AACzB,QAAM,YAAY,sBAAsB,OAAO,gBAAgB;AAC/D,QAAM,aAAa,CAAC,QAAQ,sBAAsB;AAKlD,QAAM,YAAY,OAAO,uBAAuB;AAChD,QAAM,kBAAkB,aAAa,qCAChC,OAAO,uBAAuB;AACnC,QAAM,cAAc,OAAO,kBAAkB;AAC7C,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AAEpC,QAAM,iBAAiB,kBAAkB,cAAc,aAAa;AACpE,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL;AAAA,IACA,WAAW,OAAO,gBAAgB;AAAA,IAClC,cAAc,OAAO,gBAAgB;AAAA,IACrC,WAAW,OAAO,gBAAgB;AAAA,IAClC,aAAa,OAAO,kBAAkB;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB,OAAO,uBAAuB;AAAA,IAC/C,YAAY,OAAO,iBAAiB;AAAA,IACpC,sBAAsB,OAAO,6BAA6B;AAAA,IAC1D,uBAAuB,OAAO,8BAA8B;AAAA,IAC5D,0BAA0B,OAAO,kCAAkC;AAAA,IACnE,yBAAyB,OAAO,iCAAiC;AAAA,IACjE,oBAAoB,OAAO,KAAK;AAAA,IAChC,wBAAwB,OAAO,gCAAgC;AAAA,IAC/D,4BAA4B,OAAO,oCAAoC;AAAA,IACvE,kBAAkB,OAAO,yBAAyB;AAAA,IAClD,iBAAiB,OAAO,KAAK;AAAA,IAC7B,kBAAkB,OAAO,KAAK;AAAA,IAC9B,eAAe,OAAO,sBAAsB;AAAA,IAC5C,oBAAoB,OAAO,4BAA4B;AAAA,IACvD,oBAAoB,OAAO,2BAA2B;AAAA,IACtD,mBAAmB,OAAO,0BAA0B;AAAA,IACpD,yBAAyB,OAAO,iCAAiC;AAAA,IACjE,4BAA4B,OAAO,oCAAoC;AAAA,IACvE,sBAAsB,OAAO,6BAA6B;AAAA,IAC1D,wBAAwB,OAAO,gCAAgC;AAAA,IAC/D,+BAA+B,OAAO,sCAAsC;AAAA,IAC5E,8BAA8B,OAAO,sCAAsC;AAAA,IAC3E,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,wBAAwB,OAAO,iCAAiC;AAAA,IAChE,0BAA0B,OAAO,KAAK;AAAA,IACtC,6BAA6B,OAAO,KAAK;AAAA,IACzC,0BAA0B,OAAO,KAAK;AAAA,IACtC,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc,aAAa,2BAA2B;AAAA,IAEtD,uBAAuB,CAAC;AAAA,IACxB,4BAA4B,OAAO,KAAK;AAAA,IACxC,gCAAgC,OAAO,KAAK;AAAA,EAC9C;AACF;AAgBA,SAAS,eAAe,aAAqB,aAAa,GAAe;AACvE,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA,IACjB;AAAA,IACA,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA;AAAA,IAC5B,gCAAgC;AAAA;AAAA,EAClC;AACF;AAOA,SAAS,cAAc,aAAiC;AACtD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAQA,SAAS,eAAe,aAAiC;AACvD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAUA,SAAS,gBAAgB,aAAiC;AACxD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA;AAAA,IAEZ,sBAAsB;AAAA;AAAA,IACtB,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA;AAAA,IACf,oBAAoB;AAAA;AAAA,IACpB,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAWA,SAAS,gBAAgB,aAAiC;AACxD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA,IACZ,sBAAsB;AAAA;AAAA,IACtB,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA;AAAA,IACf,oBAAoB;AAAA;AAAA,IACpB,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAOO,IAAM,0BAAyH,CAAC;AACvI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,yBAAyB,yBAAyB,oBAAoB,GAAG,EAAE;AACxG,0BAAwB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,wCAAwC;AACnJ;AACA,OAAO,OAAO,uBAAuB;AAO9B,IAAM,mBAAkH,CAAC;AAChI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE;AACjG,mBAAiB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,iBAAiB;AACrH;AACA,OAAO,OAAO,gBAAgB;AAQvB,IAAM,oBAAmH,CAAC;AACjI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC1H,QAAM,OAAO,gBAAgB,mBAAmB,0BAA0B,qBAAqB,GAAG,EAAE;AACpG,oBAAkB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,kBAAkB;AACvH;AACA,OAAO,OAAO,iBAAiB;AASxB,IAAM,oBAAmH,CAAC;AACjI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACrF,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,SAAS,+BAA+B,cAAc,IAAI,IAAI;AACpE,QAAM,cAAc,KAAK,KAAK,SAAS,CAAC,IAAI;AAC5C,QAAM,OAAO,wBAAwB,cAAc,IAAI,0BAA0B,sBAAsB,IAAI;AAC3G,oBAAkB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,kBAAkB;AACvH;AACA,OAAO,OAAO,iBAAiB;AAaxB,IAAM,oBAAmH,OAAO,OAAO;AAAA,EAC5I,OAAQ,EAAE,aAAa,IAAO,UAAU,OAAW,OAAO,SAAU,aAAa,sCAAsC;AAAA,EACvH,OAAQ,EAAE,aAAa,KAAO,UAAU,OAAW,OAAO,SAAU,aAAa,0EAAqE;AAAA,EACtJ,QAAQ,EAAE,aAAa,MAAO,UAAU,QAAW,OAAO,UAAU,aAAa,yCAAyC;AAAA,EAC1H,OAAQ,EAAE,aAAa,MAAO,UAAU,SAAW,OAAO,SAAU,aAAa,wCAAwC;AAC3H,CAAC;AAOD,SAAS,uBAAuB,aAAiC;AAC/D,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAEA,SAAS,iBAAiB,aAAqB,SAA8B;AAK3E,QAAM,WAAW,gBAAgB,kBAAkB,yBAAyB,oBAAoB,aAAa,EAAE;AAC/G,QAAM,QAAQ,YAAY,UAAa,YAAY;AACnD,QAAM,YAAY,QAAQ,uBAAuB;AACjD,QAAM,YAAY,QAAQ,uBAAuB;AACjD,QAAM,cAAc,QAAQ,yBAAyB;AACrD,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW,QAAQ,MAAM;AAAA,IACzB,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB,QAAQ,8BAA8B;AAAA,IACvD,YAAY,QAAQ,wBAAwB;AAAA;AAAA;AAAA,IAG5C,sBAAsB,QAAQ,6BAA6B;AAAA,IAC3D,uBAAuB,QAAQ,KAAK;AAAA;AAAA,IACpC,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,yBAAyB,QAAQ,6BAA6B;AAAA,IAC9D,oBAAoB,QAAQ,8BAA8B;AAAA,IAC1D,wBAAwB,QAAQ,gCAAgC;AAAA,IAChE,4BAA4B,QAAQ,oCAAoC;AAAA,IACxE,kBAAkB,QAAQ,yBAAyB;AAAA,IACnD,iBAAiB,QAAQ,wBAAwB;AAAA,IACjD,kBAAkB,QAAQ,yBAAyB;AAAA,IACnD,eAAe,QAAQ,sBAAsB;AAAA,IAC7C,oBAAoB,QAAQ,4BAA4B;AAAA,IACxD,oBAAoB,QAAQ,2BAA2B;AAAA,IACvD,mBAAmB,QAAQ,0BAA0B;AAAA,IACrD,yBAAyB,QAAQ,iCAAiC;AAAA,IAClE,4BAA4B,QAAQ,oCAAoC;AAAA,IACxE,sBAAsB,QAAQ,6BAA6B;AAAA,IAC3D,wBAAwB,QAAQ,gCAAgC;AAAA,IAChE,+BAA+B,QAAQ,sCAAsC;AAAA,IAC7E,8BAA8B,QAAQ,KAAK;AAAA;AAAA,IAC3C,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,wBAAwB,QAAQ,KAAK;AAAA;AAAA,IACrC,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,6BAA6B,QAAQ,KAAK;AAAA;AAAA,IAC1C,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA;AAAA,IAId,uBAAuB,CAAC;AAAA,IACxB,4BAA4B,QAAQ,KAAK;AAAA,IACzC,gCAAgC,QAAQ,KAAK;AAAA,EAC/C;AACF;AAMA,SAAS,mBAAmB,aAAiC;AAC3D,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA;AAAA,IAEZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA;AAAA,IAEZ,cAAc;AAAA;AAAA,IACd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAUA,SAAS,kBAAkB,aAAqB,SAA8B;AAE5E,QAAM,QAAQ,YAAY;AAC1B,QAAM,cAAc,QAAQ,4BAA4B;AACxD,QAAM,YAAY,QAAQ,wBAAwB;AAClD,QAAM,YAAY;AAElB,QAAM,qBAAqB,QAAQ,MAAM;AACzC,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,qBAAqB,cAAc,aAAa;AACvE,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY,QAAQ,MAAM;AAAA;AAAA,IAC1B,sBAAsB,QAAQ,MAAM;AAAA;AAAA,IACpC,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB,QAAQ,MAAM;AAAA;AAAA,IACvC,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe,QAAQ,MAAM;AAAA;AAAA,IAC7B,oBAAoB,QAAQ,MAAM;AAAA;AAAA,IAClC,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA;AAAA,IACjB;AAAA,IACA,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AASA,SAAS,kBAAkB,aAAqB,SAA6B;AAG3E,QAAM,SAAS,MAAM;AAEnB,UAAMC,eAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,UAAM,eAAe,2BAA2BA,eAAc,IAAI,cAAc;AAChF,UAAM,oBAAoB,KAAK,KAAK,eAAe,EAAE,IAAI;AACzD,UAAM,aAAa,oBAAoB,oBAAoB,cAAc,sBAAsB,sBAAsB,cAAc;AACnI,WAAO,YAAY;AAAA,EACrB,GAAG;AAEH,QAAM,YAAY,QAAQ,wBAAwB;AAClD,QAAM,cAAc,QAAQ,0BAA0B;AACtD,QAAM,YAAY,QAAQ,+BAA+B;AACzD,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,YAAY,QAAQ,IAAI;AAC9B,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,SAAS,IAAI;AAE/D,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY,QAAQ,MAAM;AAAA,IAC1B,sBAAsB,QAAQ,qCAAqC;AAAA,IACnE,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB,QAAQ,wCAAwC;AAAA,IACxE,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB,QAAQ,oCAAoC;AAAA,IAC7D,kBAAkB,QAAQ,qCAAqC;AAAA,IAC/D,eAAe,QAAQ,8BAA8B;AAAA,IACrD,oBAAoB,QAAQ,oCAAoC;AAAA,IAChE,oBAAoB;AAAA;AAAA,IACpB,mBAAmB,QAAQ,kCAAkC;AAAA,IAC7D,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB;AAAA,IACA,cAAc,QAAQ,MAAM;AAAA;AAAA,IAE5B,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOhC,mBAAmB,gBAAgB;AAAA,EACrC;AACF;AAuBA,SAAS,eAAe,QAAoB,SAA6B;AACvE,MAAI,OAAO,cAAc,SAAS;AAChC,UAAM,IAAI;AAAA,MACR,gCAAgC,OAAO,WAAW,0BAA0B,OAAO,mBAClE,OAAO,SAAS,gBAAgB,OAAO,WAAW,gBAAgB,OAAO,WAAW;AAAA,IACvG;AAAA,EACF;AACA,QAAM,YAAY,OAAO,YAAY,OAAO,kBAAkB,OAAO,cAAc;AACnF,MAAI,YAAY,SAAS;AACvB,UAAM,IAAI;AAAA,MACR,sCAAsC,SAAS,0BAA0B,OAAO;AAAA,IAClF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAiB,MAAsC;AAMtF,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,UAAU,eAAe,IAAI,OAAO;AAC1C,MAAI,YAAY,OAAW,QAAO,eAAe,mBAAmB,OAAO,GAAG,OAAO;AAGrF,QAAM,QAAQ,YAAY,IAAI,OAAO;AACrC,MAAI,UAAU,OAAW,QAAO,eAAe,iBAAiB,OAAO,OAAO,GAAG,OAAO;AAIxF,QAAM,QAAQ,mBAAmB,IAAI,OAAO;AAC5C,MAAI,UAAU,OAAW,QAAO,eAAe,uBAAuB,KAAK,GAAG,OAAO;AAOrF,QAAM,QAAQ,WAAW,IAAI,OAAO;AACpC,MAAI,UAAU,OAAW,QAAO,eAAe,gBAAgB,KAAK,GAAG,OAAO;AAG9E,QAAM,QAAQ,YAAY,IAAI,OAAO;AACrC,MAAI,UAAU,OAAW,QAAO,eAAe,gBAAgB,KAAK,GAAG,OAAO;AAI9E,QAAM,OAAO,UAAU,IAAI,OAAO;AAClC,MAAI,SAAS,OAAW,QAAO,eAAe,eAAe,IAAI,GAAG,OAAO;AAG3E,QAAM,MAAM,SAAS,IAAI,OAAO;AAChC,MAAI,QAAQ,OAAW,QAAO,eAAe,YAAY,GAAG,GAAG,GAAG,OAAO;AAKzE,QAAM,OAAO,UAAU,IAAI,OAAO;AAClC,MAAI,SAAS,QAAW;AACtB,QAAI,QAAQ,KAAK,UAAU,IAAI;AAC7B,YAAM,UAAU,UAAU,MAAM,CAAC;AACjC,UAAI,YAAY,EAAG,QAAO,eAAe,cAAc,IAAI,GAAG,OAAO;AAAA,IACvE;AACA,WAAO,eAAe,eAAe,MAAM,CAAC,GAAG,OAAO;AAAA,EACxD;AAKA,QAAM,QAAQ,iBAAiB,IAAI,OAAO;AAC1C,MAAI,UAAU,OAAW,QAAO,eAAe,eAAe,OAAO,EAAE,GAAG,OAAO;AAGjF,QAAM,MAAM,SAAS,IAAI,OAAO;AAChC,MAAI,QAAQ,OAAW,QAAO,eAAe,YAAY,GAAG,GAAG,GAAG,OAAO;AAGzE,QAAM,OAAO,gBAAgB,IAAI,OAAO;AAIxC,MAAI,SAAS,OAAW,QAAO,eAAe,YAAY,GAAG,MAAM,oBAAoB,GAAG,OAAO;AAEjG,SAAO;AACT;AAUO,SAAS,aAAa,SAAiB;AAC5C,QAAM,SAAS,iBAAiB,OAAO;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,EAAE,aAAa,OAAO,aAAa,aAAa,OAAO,aAAa,aAAa,OAAO,YAAY;AAC7G;AAKA,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,6BAA6B;AAGnC,IAAM,4BAA4B;AAClC,IAAM,6BAA6B;AACnC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,6BAA6B;AAMnC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,+BAA+B;AACrC,IAAM,2BAA2B;AACjC,IAAM,mCAAmC;AACzC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAKnC,IAAM,uCAAuC;AAC7C,IAAM,mCAAmC;AACzC,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAChC,IAAM,4CAA4C;AAClD,IAAM,mCAAmC;AAOzC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AACrB,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iBAAiB;AACvB,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAsLxB,IAAK,cAAL,kBAAKC,iBAAL;AACL,EAAAA,0BAAA,UAAO,KAAP;AACA,EAAAA,0BAAA,QAAK,KAAL;AAFU,SAAAA;AAAA,GAAA;AAqFZ,eAAsB,UACpB,YACA,YACA,eACqB;AACrB,QAAM,OAAO,MAAM,WAAW,eAAe,UAAU;AACvD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,2BAA2B,WAAW,SAAS,CAAC,EAAE;AAAA,EACpE;AACA,MAAI,iBAAiB,CAAC,KAAK,MAAM,OAAO,aAAa,GAAG;AACtD,UAAM,IAAI;AAAA,MACR,sBAAsB,WAAW,SAAS,CAAC,gBAAgB,KAAK,MAAM,SAAS,CAAC,iBAAiB,cAAc,SAAS,CAAC;AAAA,IAC3H;AAAA,EACF;AACA,SAAO,IAAI,WAAW,KAAK,IAAI;AACjC;AAMO,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAE9B,SAAS,yBAAyB,QAAsB,aAA6B;AAC1F,QAAM,SAAS,OAAO;AACtB,MAAI,WAAW,GAAI,QAAO;AAC1B,MAAI,OAAO,gBAAgB,GAAI,QAAO;AACtC,MAAI,UAAU,eAAgB,QAAO;AACrC,QAAM,UAAU,cAAc,OAAO,oBACjC,cAAc,OAAO,oBACrB;AACJ,MAAI,WAAW,OAAO,YAAa,QAAO;AAC1C,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAW,QAAQ,UAAW,OAAO;AAC3C,QAAM,SAAS,iBAAiB;AAChC,SAAO,SAAS,SAAS,SAAS;AACpC;AAMO,SAAS,UAAU,MAA0B;AAClD,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM,EAAE;AAAA,EAC3E;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,KAAK,SAAS,OAAO,EAAG,OAAM,IAAI,MAAM,+BAA+B;AAC3E,SAAO,UAAU,MAAM,IAAI;AAC7B;AAEO,SAAS,sBAAsB,MAA0B;AAC9D,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,wDAAwD,KAAK,MAAM,EAAE;AAAA,EACvF;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,KAAK,SAAS,OAAO,GAAI,OAAM,IAAI,MAAM,2CAA2C;AACxF,SAAO,UAAU,MAAM,OAAO,CAAC;AACjC;AASO,SAAS,YAAY,MAA8B;AACxD,MAAI,KAAK,SAAS,eAAe;AAC/B,UAAM,IAAI,MAAM,mCAAmC,KAAK,MAAM,MAAM,aAAa,EAAE;AAAA,EACrF;AAEA,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,MAAI,UAAU,OAAO;AACnB,UAAM,IAAI,MAAM,gCAAgC,MAAM,SAAS,EAAE,CAAC,SAAS,MAAM,SAAS,EAAE,CAAC,EAAE;AAAA,EACjG;AAEA,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,QAAM,OAAO,OAAO,MAAM,EAAE;AAC5B,QAAM,QAAQ,OAAO,MAAM,EAAE;AAC7B,QAAM,QAAQ,IAAIC,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAGjD,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,QAAM,OAAO,SAAS,OAAO,cAAc;AAC3C,QAAM,QAAQ,UAAU,MAAM,IAAI;AAClC,QAAM,oBAAoB,UAAU,MAAM,OAAO,CAAC;AAElD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAQ,mBAAmB;AAAA,IACtC,SAAS,QAAQ,OAAU;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA2DA,SAAS,kBAAkB,MAAkB,WAAiC;AAC5E,QAAM,mBAAmB;AACzB,MAAI,KAAK,SAAS,YAAY,kBAAkB;AAC9C,UAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,MAAM,YAAY,gBAAgB,EAAE;AAAA,EAC3G;AAEA,QAAM,IAAI;AACV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AACjE,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,oBAAoB,UAAU,MAAM,IAAI,EAAE;AAChD,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,qBAAqB,OAAO,MAAM,IAAI,GAAG;AAC/C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AACnC,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AACrE,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAKpD,QAAM,eAAe,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG;AACnD,QAAM,UAAU,aAAa,KAAK,OAAK,MAAM,CAAC,IAAI,IAAIA,WAAU,YAAY,IAAI;AAEhF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,2BAA2B;AAAA;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,aAAa;AAAA;AAAA,IACb,eAAe;AAAA,IACf,2BAA2B;AAAA,IAC3B,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C,WAAW,UAAU,MAAM,IAAI,GAAG;AAAA,IAClC,wBAAwB;AAAA;AAAA,IACxB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;AAyDA,SAAS,kBAAkB,MAAkB,WAAiC;AAC5E,QAAM,mBAAmB;AACzB,MAAI,KAAK,SAAS,YAAY,kBAAkB;AAC9C,UAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,MAAM,YAAY,gBAAgB,EAAE;AAAA,EAC3G;AAEA,QAAM,IAAI;AACV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AACjE,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,oBAAoB,UAAU,MAAM,IAAI,EAAE;AAChD,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,qBAAqB,OAAO,MAAM,IAAI,GAAG;AAC/C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AACnC,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AACrE,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AAEnD,QAAM,eAAe,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG;AACnD,QAAM,UAAU,aAAa,KAAK,OAAK,MAAM,CAAC,IAAI,IAAIA,WAAU,YAAY,IAAI;AAEhF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,2BAA2B;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,eAAe;AAAA,IACf,2BAA2B;AAAA,IAC3B,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C,WAAW,UAAU,MAAM,IAAI,GAAG;AAAA,IAClC,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;AAEO,SAAS,YAAY,MAAkB,YAA8C;AAC1F,MAAI,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,MAAM,OAAO;AACpD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,QAAM,SAAS,eAAe,SAAY,aAAa,iBAAiB,KAAK,QAAQ,IAAI;AACzF,QAAM,YAAY,SAAS,OAAO,eAAe;AACjD,QAAM,YAAY,SAAS,OAAO,YAAY;AAI9C,QAAM,WAAW,UAAU,OAAO,gBAAgB;AAClD,MAAI,UAAU;AACZ,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAKA,QAAM,WAAW,WAAW,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACjG,MAAI,UAAU;AACZ,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAIA,QAAM,mBAAmB;AACzB,QAAM,SAAS,YAAY,KAAK,IAAI,WAAW,gBAAgB;AAC/D,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,IAAI,MAAM,mCAAmC,KAAK,MAAM,MAAM,MAAM,EAAE;AAAA,EAC9E;AAEA,MAAI,MAAM;AAEV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AACjE,SAAO;AAEP,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAC9D,SAAO;AAEP,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAC9D,SAAO;AAEP,QAAM,oBAAoB,UAAU,MAAM,GAAG;AAC7C,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,qBAAqB,OAAO,MAAM,GAAG;AAC3C,SAAO;AAEP,QAAM,SAAS,OAAO,MAAM,GAAG;AAC/B,SAAO;AAEP,QAAM,YAAY,UAAU,MAAM,GAAG;AACrC,SAAO;AAGP,QAAM,sBAAsB,UAAU,MAAM,GAAG;AAC/C,SAAO;AAEP,QAAM,cAAc,UAAU,MAAM,GAAG;AACvC,SAAO;AAEP,QAAM,4BAA4B,WAAW,MAAM,GAAG;AACtD,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAQP,QAAM,cAAc,WAAW,MAAM,GAAG;AACxC,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,4BAA4B,UAAU,MAAM,GAAG;AACrD,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,iBAAiB,UAAU,MAAM,GAAG;AAC1C,SAAO;AAEP,QAAM,YAAY,WAAW,MAAM,GAAG;AACtC,SAAO;AAEP,QAAM,YAAY,WAAW,MAAM,GAAG;AACtC,SAAO;AAEP,QAAM,gBAAgB,WAAW,MAAM,GAAG;AAC1C,SAAO;AAGP,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAClE,SAAO;AAEP,QAAM,mBAAmB,UAAU,MAAM,GAAG;AAC5C,SAAO;AAEP,QAAM,qBAAqB,UAAU,MAAM,GAAG;AAC9C,SAAO;AAGP,QAAM,sBAAsB,UAAU,MAAM,GAAG;AAC/C,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAGP,QAAM,qBAAqB,UAAU,MAAM,GAAG;AAC9C,SAAO;AAEP,QAAM,YAAY,UAAU,MAAM,GAAG;AACrC,SAAO;AAGP,QAAM,YAAY,YAAY,YAAY;AAE1C,MAAI,yBAAyB;AAC7B,MAAI,mBAAmB;AACvB,MAAI,wBAAwB;AAC5B,MAAI,oBAAoB;AACxB,MAAI,cAAc;AAClB,MAAI,eAAe;AACnB,MAAI,wBAAwB;AAC5B,MAAI,cAAc;AAClB,MAAI,qBAAqB;AACzB,MAAI,mBAAmB;AAEvB,MAAI,aAAa,IAAI;AAMnB,wBAAoB,UAAU,MAAM,GAAG;AACvC,WAAO;AAEP,kBAAc,UAAU,MAAM,GAAG;AACjC,WAAO;AAEP,6BAAyB,OAAO,MAAM,GAAG,MAAM;AAC/C,WAAO;AACP,WAAO;AACP,uBAAmB,UAAU,MAAM,GAAG;AACtC,WAAO;AACP,WAAO;AACP,4BAAwB,UAAU,MAAM,GAAG;AAC3C,WAAO;AAEP,QAAI,aAAa,IAAI;AACnB,8BAAwB,UAAU,MAAM,GAAG;AAI3C,UAAI,aAAa,IAAI;AACnB,cAAM,SAAS,MAAM;AACrB,sBAAc,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC,GAAG,CAAC;AAClD,6BAAqB,UAAU,MAAM,SAAS,CAAC;AAE/C,2BAAmB,KAAK,SAAS,EAAE,IAAK,KAAK,SAAS,EAAE,KAAK,IAAM,KAAK,SAAS,EAAE,KAAK;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AAKA,MAAI,UAA4B;AAChC,QAAM,mBAAmB;AACzB,MAAI,aAAa,mBAAmB,MAAM,KAAK,UAAU,YAAY,mBAAmB,IAAI;AAC1F,UAAM,eAAe,KAAK,SAAS,YAAY,kBAAkB,YAAY,mBAAmB,EAAE;AAElG,QAAI,aAAa,KAAK,OAAK,MAAM,CAAC,GAAG;AACnC,gBAAU,IAAIA,WAAU,YAAY;AAAA,IACtC;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUO,SAAS,YAAY,MAAkB,YAA4C;AACxF,QAAM,SAAS,eAAe,SAAY,aAAa,iBAAiB,KAAK,QAAQ,IAAI;AACzF,QAAM,YAAY,SAAS,OAAO,YAAY;AAC9C,QAAM,YAAY,SAAS,OAAO,kBAAkB;AACpD,QAAM,aAAa,SAAS,OAAO,aAAa;AAChD,QAAM,OAAO,YAAY;AAIzB,QAAM,mBAAmB,cAAc,MAAM,MAAM;AACnD,MAAI,KAAK,SAAS,OAAO,kBAAkB;AACzC,UAAM,IAAI,MAAM,uCAAuC,KAAK,MAAM,MAAM,OAAO,gBAAgB,EAAE;AAAA,EACnG;AAIA,QAAM,iBAAiB,eAAe,sBAAsB,eAAe;AAC3E,QAAM,iBAAiB,WAAW,QAAQ,WAAW,UACnD,OAAO,cAAc,yBACrB,eAAe;AAKjB,QAAM,aAAa,CAAC,kBAAkB,WAAW,QAAQ,WAAW,UACjE,OAAO,cAAc,wBAAyB,eAAe;AAGhE,QAAM,SAAqB;AAAA,IACzB,mBAAmB,iBACf,UAAU,MAAM,OAAO,uBAAuB,IAC9C,iBACA,UAAU,MAAM,OAAO,uBAAuB,IAC9C,UAAU,MAAM,OAAO,wBAAwB;AAAA,IACnD,sBAAsB,iBAClB,UAAU,MAAM,OAAO,oCAAoC,IAC3D,iBACA,UAAU,MAAM,OAAO,CAAC,IACxB,UAAU,MAAM,OAAO,6BAA6B;AAAA,IACxD,kBAAkB,iBACd,UAAU,MAAM,OAAO,gCAAgC,IACvD,iBACA,UAAU,MAAM,OAAO,CAAC,IACxB,UAAU,MAAM,OAAO,yBAAyB;AAAA,IACpD,eAAe,iBACX,UAAU,MAAM,OAAO,6BAA6B,IACpD,iBACA,UAAU,MAAM,OAAO,EAAE,IACzB,UAAU,MAAM,OAAO,sBAAsB;AAAA,IACjD,aAAa,iBACT,UAAU,MAAM,OAAO,8BAA8B,IACrD,iBACA,UAAU,MAAM,OAAO,8BAA8B,IACrD,UAAU,MAAM,OAAO,uBAAuB;AAAA,IAClD,eAAe,iBACX,KACA,iBACA,WAAW,MAAM,OAAO,EAAE,IAC1B,WAAW,MAAM,OAAO,0BAA0B;AAAA;AAAA,IAEtD,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAEA,MAAI,gBAAgB;AAGlB,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,yBAAyB,UAAU,MAAM,OAAO,gCAAgC;AACvF,WAAO,oBAAoB,UAAU,MAAM,OAAO,6BAA6B;AAC/E,WAAO,oBAAoB,WAAW,MAAM,OAAO,6BAA6B;AAChF,WAAO,uBAAuB,UAAU,MAAM,OAAO,yCAAyC;AAC9F,WAAO,oBAAoB,WAAW,MAAM,OAAO,yBAAyB;AAC5E,WAAO,oBAAoB;AAC3B,WAAO,kBAAkB,WAAW,MAAM,OAAO,2BAA2B;AAC5E,WAAO,kBAAkB,WAAW,MAAM,OAAO,2BAA2B;AAC5E,WAAO,iBAAiB;AAAA,EAC1B,WAAW,gBAAgB;AAEzB,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,iBAAiB,WAAW,MAAM,OAAO,iCAAiC;AAGjF,WAAO,yBAAyB;AAChC,WAAO,wBAAyB;AAEhC,WAAO,yBAAyB,UAAU,MAAM,OAAO,EAAE;AACzD,WAAO,oBAAyB,UAAU,MAAM,OAAO,EAAE;AACzD,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,uBAAyB;AAChC,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,kBAAyB,WAAW,MAAM,OAAO,GAAG;AAC3D,WAAO,kBAAyB,WAAW,MAAM,OAAO,GAAG;AAAA,EAC7D,WAAW,YAAY;AAErB,WAAO,wBAAwB,WAAW,MAAM,OAAO,0BAA0B;AACjF,WAAO,yBAAyB,UAAU,MAAM,OAAO,0BAA0B;AACjF,WAAO,oBAAoB,UAAU,MAAM,OAAO,4BAA4B;AAC9E,WAAO,oBAAoB,WAAW,MAAM,OAAO,4BAA4B;AAC/E,WAAO,oBAAoB,WAAW,MAAM,OAAO,wBAAwB;AAC3E,WAAO,oBAAoB,WAAW,MAAM,OAAO,gCAAgC;AACnF,WAAO,kBAAkB,WAAW,MAAM,OAAO,0BAA0B;AAC3E,WAAO,kBAAkB,WAAW,MAAM,OAAO,0BAA0B;AAC3E,WAAO,iBAAiB,WAAW,MAAM,OAAO,0BAA0B;AAE1E,WAAO,OAAO,OAAO;AACrB,WAAO,OAAO,OAAO;AAAA,EACvB,WAAW,cAAc,KAAK;AAE5B,WAAO,yBAAyB,WAAW,MAAM,OAAO,yBAAyB;AACjF,WAAO,wBAAwB,WAAW,MAAM,OAAO,0BAA0B;AACjF,WAAO,yBAAyB,UAAU,MAAM,OAAO,8BAA8B;AACrF,WAAO,oBAAoB,UAAU,MAAM,OAAO,8BAA8B;AAChF,WAAO,oBAAoB,WAAW,MAAM,OAAO,8BAA8B;AACjF,WAAO,uBAAuB,UAAU,MAAM,OAAO,6BAA6B;AAClF,WAAO,oBAAoB,WAAW,MAAM,OAAO,0BAA0B;AAE7E,WAAO,OAAO,OAAO;AACrB,WAAO,OAAO,OAAO;AAAA,EACvB;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,MAA+B;AACzD,MAAI,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,MAAM,OAAO;AACpD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,oCAAoC;AAAA,EACnG;AACA,MAAI,KAAK,SAAS,OAAO,aAAa;AACpC,UAAM,IAAI,MAAM,gDAAgD,KAAK,MAAM,MAAM,OAAO,WAAW,GAAG;AAAA,EACxG;AAEA,QAAM,OAAO,OAAO;AAGpB,QAAM,WAAW,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACtF,QAAM,WAAW,CAAC,aAAa,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB,+BAA+B,OAAO,cAAc,qBAAqB,OAAO,cAAc;AAKlM,QAAM,WAAW,OAAO,gBAAgB;AACxC,MAAI,YAAY,UAAU;AACxB,UAAM,QAAQ,OAAO,cAAc,yBAAyB;AAE5D,UAAM,iBAAiB,WAAW,qCACV,QAAQ,qCAAqC;AACrE,UAAM,gBAAgB,WAAW,oCACT,QAAQ,oCAAoC;AACpE,UAAM,UAAU,WAAW,8BACT,QAAQ,8BAA8B;AACxD,UAAM,eAAe,WAAW,oCACR,QAAQ,oCAAoC;AACpE,UAAM,gBAAgB,WAAW,4CACT,QAAQ,4CAA4C;AAC5E,UAAM,YAAY,WAAW,sCACL,QAAQ,sCAAsC;AACtE,UAAM,iBAAiB,WAAW,0CACV,QAAQ,0CAA0C;AAC1E,UAAM,gBAAgB,WAAW,qCACT,QAAQ,qCAAqC;AACrE,UAAM,cAAc,WAAW,mCACP,QAAQ,mCAAmC;AACnE,UAAM,eAAe,WAAW,oCACR,QAAQ,oCAAoC;AAGpE,UAAM,mBAAmB,WAAW,MACR,QAAQ,MAAM;AAC1C,UAAM,oBAAoB,WAAW,MACT,QAAQ,MAAM;AAC1C,UAAM,uBAAuB,WAAW,4CACZ,QAAQ,MAAM;AAE1C,UAAM,mBAAmB,WAAW,yCACR,QAAQ,wCAAwC;AAC5E,UAAM,cAAc,WAAW,kCACH,QAAQ,kCAAkC;AACtE,UAAM,eAAe,WAAW,oCACJ,QAAQ,oCAAoC;AACxE,UAAM,gBAAgB,WAAW,qCACL,QAAQ,qCAAqC;AAEzE,UAAM,SAAS,WAAW,MAAM,OAAO,YAAY;AACnD,UAAM,UAAU,WAAW,MAAM,OAAO,aAAa;AAGrD,UAAM,YAAY,OAAO,kBAAkB,OAAO,cAAc;AAEhE,WAAO;AAAA,MACL,OAAO,WAAW,MAAM,IAAI;AAAA,MAC5B,eAAe;AAAA,QACb,SAAS,WAAW,MAAM,OAAO,EAAE;AAAA,QACnC,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,cAAc;AAAA,MAChB;AAAA,MACA,aAAa,UAAU,MAAM,OAAO,cAAc;AAAA,MAClD,mBAAmB;AAAA;AAAA,MACnB,iBAAiB;AAAA,MACjB,2BAA2B;AAAA;AAAA,MAC3B,eAAe;AAAA;AAAA,MACf,YAAY,OAAO,MAAM,OAAO,aAAa,MAAM,IAAI,IAAI;AAAA,MAC3D,eAAe,UAAU,MAAM,OAAO,gBAAgB;AAAA,MACtD,wBAAwB;AAAA,MACxB,mBAAmB,SAAS;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,MAAM,WAAW,MAAM,OAAO,OAAO;AAAA,MACrC,WAAW,WAAW,MAAM,OAAO,YAAY;AAAA,MAC/C,kBAAkB,WAAW,MAAM,OAAO,aAAa;AAAA,MACvD,WAAW;AAAA,MACX,UAAU,UAAU,MAAM,OAAO,WAAW;AAAA,MAC5C,oBAAoB;AAAA,MACpB,uBAAuB;AAAA,MACvB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,sBAAsB;AAAA,MACtB,qBAAqB;AAAA,MACrB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,eAAe,UAAU,MAAM,OAAO,cAAc;AAAA,MACpD,iBAAiB,UAAU,MAAM,OAAO,SAAS;AAAA,MACjD,eAAe;AAAA;AAAA;AAAA,MAGf,UAAU,WAAW,MAAM,OAAO,WAAW;AAAA,MAC7C,WAAW,WAAW,MAAM,OAAO,YAAY;AAAA,MAC/C,oBAAoB,UAAU,MAAM,OAAO,SAAS;AAAA,MACpD,YAAY,UAAU,MAAM,OAAO,aAAa;AAAA,MAChD,4BAA4B,WAAW,MAAM,OAAO,gBAAgB;AAAA,MACpE,6BAA6B,WAAW,MAAM,OAAO,iBAAiB;AAAA,MACtE,mBAAmB,UAAU,MAAM,OAAO,oBAAoB;AAAA,IAChE;AAAA,EACF;AAIA,QAAM,4BAA4B,WAC9B,WAAW,MAAM,OAAO,OAAO,uBAAuB,IACtD,UAAU,MAAM,OAAO,OAAO,uBAAuB;AAEzD,SAAO;AAAA,IACL,OAAO,WAAW,MAAM,IAAI;AAAA,IAC5B,eAAe;AAAA,MACb,SAAS,WAAW,MAAM,OAAO,OAAO,kBAAkB;AAAA;AAAA,MAE1D,YAAY,OAAO,wBACf,WAAW,MAAM,OAAO,OAAO,qBAAqB,EAAE,IACtD;AAAA,MACJ,iBAAiB,OAAO,wBACpB,WAAW,MAAM,OAAO,OAAO,0BAA0B,IACzD;AAAA,MACJ,cAAc,OAAO,wBACjB,UAAU,MAAM,OAAO,OAAO,8BAA8B,IAC5D;AAAA,IACN;AAAA,IACA,aAAa,UAAU,MAAM,OAAO,OAAO,oBAAoB;AAAA,IAC/D,mBAAmB,OAAO,yBAAyB,IAC7C,OAAO,4BAA4B,KAAK,OAAO,2BAA2B,OAAO,0BAA0B,IACzG,OAAO,UAAU,MAAM,OAAO,OAAO,qBAAqB,CAAC,IAC3D,WAAW,MAAM,OAAO,OAAO,qBAAqB,IACxD;AAAA,IACJ,iBAAiB,OAAO,4BAA4B,IAChD,UAAU,MAAM,OAAO,OAAO,wBAAwB,IAAI;AAAA,IAC9D;AAAA,IACA,eAAe,WACX,WAAW,MAAM,OAAO,OAAO,uBAAuB,IACtD;AAAA,IACJ,YAAY,WACP,OAAO,MAAM,OAAO,OAAO,0BAA0B,EAAE,MAAM,IAAI,IAAI,IACtE;AAAA,IACJ,eAAe,OAAO,0BAA0B,IAC5C,UAAU,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC5D,wBAAwB,OAAO,8BAA8B,IACzD,UAAU,MAAM,OAAO,OAAO,0BAA0B,IAAI;AAAA,IAChE,mBAAmB,OAAO,oBAAoB,IAC1C,WAAW,MAAM,OAAO,OAAO,gBAAgB,IAAI;AAAA,IACvD,QAAQ,OAAO,mBAAmB,IAC9B,WAAW,MAAM,OAAO,OAAO,eAAe,IAAI;AAAA,IACtD,SAAS,OAAO,oBAAoB,IAChC,WAAW,MAAM,OAAO,OAAO,gBAAgB,IAAI;AAAA,IACvD,MAAM,WAAW,MAAM,OAAO,OAAO,aAAa;AAAA,IAClD,WAAW,WAAW,MAAM,OAAO,OAAO,kBAAkB;AAAA,IAC5D,kBAAkB,WACd,WAAW,MAAM,OAAO,qCAAqC,IAC7D;AAAA,IACJ,WAAW,OAAO,sBAAsB,IACpC,UAAU,MAAM,OAAO,OAAO,kBAAkB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAClC,UAAU,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACvD,oBAAoB,OAAO,2BAA2B,IAClD,UAAU,MAAM,OAAO,OAAO,uBAAuB,IAAI;AAAA,IAC7D,uBAAuB,OAAO,8BAA8B,IACxD,UAAU,MAAM,OAAO,OAAO,0BAA0B,IAAI;AAAA,IAChE,aAAa,OAAO,wBAAwB,IACxC,UAAU,MAAM,OAAO,OAAO,oBAAoB,IAAI;AAAA,IAC1D,eAAe,OAAO,0BAA0B,IAC5C,UAAU,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC5D,sBAAsB,OAAO,iCAAiC,IAC1D,UAAU,MAAM,OAAO,OAAO,6BAA6B,IAAI;AAAA,IACnE,qBAAqB,OAAO,gCAAgC,IACxD,UAAU,MAAM,OAAO,OAAO,4BAA4B,IAAI;AAAA,IAClE,UAAU,OAAO,qBAAqB,IAClC,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAClC,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAAI,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IAC9F,eAAe,OAAO,0BAA0B,IAAI,WAAW,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC7G,iBAAiB,OAAO,4BAA4B,IAChD,KAAK,OAAO,OAAO,wBAAwB,MAAM,IACjD;AAAA,IACJ,oBAAoB,OAAO,+BAA+B,IACtD,UAAU,MAAM,OAAO,OAAO,2BAA2B,IAAI;AAAA,IACjE,iBAAiB,OAAO,4BAA4B,IAChD,UAAU,MAAM,OAAO,OAAO,wBAAwB,IAAI;AAAA,IAC9D,aAAa,OAAO,sBAAsB,IACtC,UAAU,MAAM,OAAO,OAAO,kBAAkB,IAAI;AAAA;AAAA;AAAA,IAGxD,eAAe,WACX,UAAU,MAAM,OAAO,OAAO,kBAAkB,EAAE,IAClD;AAAA,IACJ,kBAAkB,MAAM;AACtB,UAAI,OAAO,aAAa,GAAI,QAAO;AACnC,YAAM,KAAK,OAAO;AAClB,aAAO,UAAU,MAAM,OAAO,OAAO,kBAAkB,KAAK,CAAC;AAAA,IAC/D,GAAG;AAAA,IACH,gBAAgB,MAAM;AACpB,UAAI,OAAO,aAAa,GAAI,QAAO;AACnC,YAAM,KAAK,OAAO;AAClB,YAAM,aAAa,OAAO,kBAAkB,KAAK;AACjD,aAAO,UAAU,MAAM,OAAO,KAAK,MAAM,aAAa,KAAK,CAAC,IAAI,CAAC;AAAA,IACnE,GAAG;AAAA;AAAA,IAGH,UAAU;AAAA,IACV,WAAW;AAAA,IACX,oBAAoB;AAAA,IACpB,YAAY;AAAA,IACZ,4BAA4B;AAAA,IAC5B,6BAA6B;AAAA,IAC7B,mBAAmB;AAAA,EACrB;AACF;AASO,SAAS,iBAAiB,MAA4B;AAC3D,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,EAAE;AAE5E,QAAM,OAAO,OAAO,YAAY,OAAO;AACvC,MAAI,KAAK,SAAS,OAAO,OAAO,cAAc,GAAG;AAC/C,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,QAAM,OAAiB,CAAC;AACxB,WAAS,OAAO,GAAG,OAAO,OAAO,aAAa,QAAQ;AACpD,UAAM,OAAO,UAAU,MAAM,OAAO,OAAO,CAAC;AAC5C,QAAI,SAAS,GAAI;AACjB,aAAS,MAAM,GAAG,MAAM,IAAI,OAAO;AACjC,UAAK,QAAQ,OAAO,GAAG,IAAK,IAAI;AAC9B,aAAK,KAAK,OAAO,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,cAAc,MAAkB,KAAsB;AACpE,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,YAAa,QAAO;AAC3E,QAAM,OAAO,OAAO,YAAY,OAAO;AACvC,QAAM,OAAO,KAAK,MAAM,MAAM,EAAE;AAChC,QAAM,MAAM,MAAM;AAClB,QAAM,OAAO,UAAU,MAAM,OAAO,OAAO,CAAC;AAC5C,UAAS,QAAQ,OAAO,GAAG,IAAK,QAAQ;AAC1C;AAKO,SAAS,gBAAgB,SAAyB;AACvD,QAAM,SAAS,iBAAiB,OAAO;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,cAAc,UAAU,OAAO;AACrC,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO,KAAK,MAAM,cAAc,OAAO,WAAW;AACpD;AAKO,SAAS,aAAa,MAAkB,KAAsB;AACnE,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,EAAE;AAE5E,QAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,OAAO,QAAQ;AACtD,UAAM,IAAI,MAAM,+BAA+B,GAAG,UAAU,SAAS,CAAC,GAAG;AAAA,EAC3E;AAEA,QAAM,OAAO,OAAO,cAAc,MAAM,OAAO;AAC/C,MAAI,KAAK,SAAS,OAAO,OAAO,aAAa;AAC3C,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAeA,QAAM,WAAW,OAAO,gBAAgB,uBACvB,OAAO,gBAAgB,2BACvB,OAAO,gBAAgB;AACxC,QAAM,WAAW,CAAC,aAAa,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACpG,QAAM,YAAY,CAAC,YAAY,CAAC,YAAY,OAAO,gBAAgB,6BAA6B,OAAO,cAAc;AACrH,QAAM,UAAU,CAAC,YAAY,CAAC,YAAY,CAAC,cAAc,OAAO,cAAc,oBAAoB,OAAO,cAAc,0BAA0B,OAAO,gBAAgB,sBAAsB,OAAO,gBAAgB;AACrN,QAAM,QAAQ,CAAC,YAAY,CAAC,aAAa,OAAO,eAAe,OAAO,WAAW;AAEjF,MAAI,UAAU;AASZ,UAAM,QAAQ,OAAO,gBAAgB,2BACvB,OAAO,gBAAgB;AACrC,UAAM,KAAK,QAAQ,IAAI;AACvB,UAAM,KAAK,QAAQ,KAAK;AAExB,UAAMC,YAAW,OAAO,MAAM,OAAO,oBAAoB;AACzD,UAAMC,QAAOD,cAAa,IAAI,aAAiB;AAE/C,WAAO;AAAA,MACL,MAAAC;AAAA,MACA,WAAW;AAAA;AAAA,MACX,SAAS,WAAW,MAAM,OAAO,uBAAuB;AAAA,MACxD,KAAK,WAAW,MAAM,OAAO,sBAAsB,EAAE;AAAA,MACrD,aAAa,WAAW,MAAM,OAAO,+BAA+B,EAAE;AAAA,MACtE,qBAAqB;AAAA;AAAA,MACrB,oBAAoB;AAAA;AAAA,MACpB,cAAc,WAAW,MAAM,OAAO,mCAAmC,EAAE;AAAA,MAC3E,YAAY;AAAA;AAAA,MACZ,cAAc;AAAA;AAAA,MACd,gBAAgB,IAAIF,WAAU,KAAK,SAAS,OAAO,kCAAkC,IAAI,OAAO,kCAAkC,KAAK,EAAE,CAAC;AAAA,MAC1I,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,kCAAkC,IAAI,OAAO,kCAAkC,KAAK,EAAE,CAAC;AAAA,MAC1I,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,wBAAwB,IAAI,OAAO,wBAAwB,KAAK,EAAE,CAAC;AAAA,MAC7G,YAAY,WAAW,MAAM,OAAO,8BAA8B,EAAE;AAAA,MACpE,aAAa;AAAA;AAAA,MACb,iBAAiB;AAAA;AAAA,MACjB,qBAAqB;AAAA;AAAA,MACrB,kBAAkB;AAAA,MAClB,eAAe;AAAA,MACf,sBAAsB;AAAA,MACtB,gBAAgB;AAAA,MAChB,uBAAuB;AAAA;AAAA,MAGvB,OAAO,WAAW,MAAM,OAAO,yBAAyB,EAAE;AAAA,MAC1D,WAAW,WAAW,MAAM,OAAO,8BAA8B,EAAE;AAAA,MACnE,UAAU,WAAW,MAAM,OAAO,6BAA6B,EAAE;AAAA,MACjE,cAAc,UAAU,MAAM,OAAO,iCAAiC,EAAE;AAAA,MACxE,cAAc,OAAO,MAAM,OAAO,gCAAgC,EAAE,MAAM;AAAA,MAC1E,iBAAiB,WAAW,MAAM,OAAO,oCAAoC,EAAE;AAAA,MAC/E,cAAc,WAAW,MAAM,OAAO,iCAAiC,EAAE;AAAA,MACzE,gBAAgB,UAAU,MAAM,OAAO,mCAAmC,EAAE;AAAA,MAC5E,cAAc,UAAU,MAAM,OAAO,gCAAgC,EAAE;AAAA,MACvE,eAAe,WAAW,MAAM,OAAO,kCAAkC,EAAE;AAAA,MAC3E,gBAAgB,OAAO,MAAM,OAAO,kCAAkC,EAAE,MAAM;AAAA,MAC9E,mBAAmB,WAAW,MAAM,OAAO,sCAAsC,EAAE;AAAA,MACnF,gBAAgB,UAAU,MAAM,OAAO,kCAAkC,EAAE;AAAA,MAC3E,oBAAoB,UAAU,MAAM,OAAO,uCAAuC,EAAE;AAAA,IACtF;AAAA,EACF;AAEA,MAAI,UAAU;AAEZ,UAAMC,YAAW,OAAO,MAAM,OAAO,oBAAoB;AACzD,UAAMC,QAAOD,cAAa,IAAI,aAAiB;AAG/C,UAAM,cAAc,OAAO,MAAM,OAAO,kCAAkC;AAC1E,UAAM,sBAA4C,CAAC;AACnD,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,YAAY,OAAO,wCAAwC,IAAI;AACrE,0BAAoB,KAAK,KAAK,MAAM,WAAW,YAAY,EAAE,CAAC;AAAA,IAChE;AAEA,UAAM,uBAAuB,OAAO,MAAM,OAAO,sCAAsC,MAAM;AAC7F,UAAM,wBAAwB,OAAO,MAAM,OAAO,uCAAuC,MAAM;AAE/F,WAAO;AAAA,MACL,MAAAC;AAAA,MACA,WAAW,UAAU,MAAM,OAAO,0BAA0B;AAAA,MAC5D,SAAS,WAAW,MAAM,OAAO,uBAAuB;AAAA,MACxD,KAAK,WAAW,MAAM,OAAO,mBAAmB;AAAA,MAChD,aAAa,WAAW,MAAM,OAAO,4BAA4B;AAAA,MACjE,qBAAqB;AAAA;AAAA,MACrB,oBAAoB;AAAA;AAAA,MACpB,cAAc,WAAW,MAAM,OAAO,gCAAgC;AAAA,MACtE,YAAY,UAAU,MAAM,OAAO,2BAA2B;AAAA,MAC9D,cAAc;AAAA;AAAA,MACd,gBAAgB,IAAIF,WAAU,KAAK,SAAS,OAAO,iCAAiC,OAAO,kCAAkC,EAAE,CAAC;AAAA,MAChI,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,iCAAiC,OAAO,kCAAkC,EAAE,CAAC;AAAA,MAChI,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,uBAAuB,OAAO,wBAAwB,EAAE,CAAC;AAAA,MACnG,YAAY,WAAW,MAAM,OAAO,2BAA2B;AAAA,MAC/D,aAAa;AAAA;AAAA,MACb,iBAAiB,WAAW,MAAM,OAAO,iCAAiC;AAAA,MAC1E;AAAA,MACA,kBAAkB;AAAA,MAClB,eAAe,KAAK,MAAM,OAAO,gCAAgC,OAAO,iCAAiC,EAAE;AAAA,MAC3G;AAAA,MACA,gBAAgB,KAAK,MAAM,OAAO,iCAAiC,OAAO,kCAAkC,EAAE;AAAA,MAC9G;AAAA;AAAA,MAGA,OAAO;AAAA,MAAI,WAAW;AAAA,MAAI,UAAU;AAAA,MAAI,cAAc;AAAA,MACtD,cAAc;AAAA,MAAM,iBAAiB;AAAA,MAAM,cAAc;AAAA,MACzD,gBAAgB;AAAA,MAAM,cAAc;AAAA,MAAM,eAAe;AAAA,MACzD,gBAAgB;AAAA,MAAM,mBAAmB;AAAA,MAAM,gBAAgB;AAAA,MAAM,oBAAoB;AAAA,IAC3F;AAAA,EACF;AAGA,QAAM,mBAAmB,QAAQ,gCAAgC;AACjE,QAAM,iBAAmB,QAAQ,8BAAgC;AACjE,QAAM,kBAAoB,WAAW,YAAa,+BAAgC,QAAQ,+BAA+B;AACzH,QAAM,gBAAmB,YAAY,gCAAiC,UAAU,6BAA8B,QAAQ,6BAA6B;AACnJ,QAAM,kBAAoB,WAAW,YAAa,KAAM,QAAQ,+BAA+B;AAC/F,QAAM,iBAAmB,YAAY,oCAAqC,UAAU,iCAAkC,QAAQ,iCAAiC;AAC/J,QAAM,gBAAmB,YAAY,oCAAqC,UAAU,iCAAkC,QAAQ,iCAAiC;AAC/J,QAAM,gBAAmB,YAAY,gCAAiC,UAAU,6BAA8B,QAAQ,6BAA6B;AACnJ,QAAM,iBAAmB,YAAY,kCAAmC,UAAU,+BAAgC,QAAQ,+BAA+B;AAEzJ,QAAM,WAAW,OAAO,MAAM,OAAO,aAAa;AAClD,QAAM,OAAO,aAAa,IAAI,aAAiB;AAE/C,SAAO;AAAA,IACL;AAAA,IACA,WAAW,UAAU,MAAM,OAAO,mBAAmB;AAAA,IACrD,SAAS,WAAW,MAAM,OAAO,gBAAgB;AAAA,IACjD,KAAK,WAAW,MAAM,OAAO,YAAY;AAAA,IACzC,aAAa,QAAQ,WAAW,MAAM,OAAO,qBAAqB,IAAI,UAAU,MAAM,OAAO,qBAAqB;AAAA,IAClH,qBAAqB,UAAU,MAAM,OAAO,gBAAgB;AAAA,IAC5D,oBAAoB,WAAW,MAAM,OAAO,cAAc;AAAA,IAC1D,cAAc,WAAW,MAAM,OAAO,eAAe;AAAA,IACrD,YAAY,iBAAiB,IAAI,UAAU,MAAM,OAAO,aAAa,IAAI;AAAA;AAAA,IAEzE,cAAe,WAAW,YAAc,mBAAmB,IAAI,OAAO,UAAU,MAAM,OAAO,eAAe,CAAC,IAAI,KAAM,WAAW,MAAM,OAAO,eAAe;AAAA,IAC9J,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,gBAAgB,OAAO,iBAAiB,EAAE,CAAC;AAAA,IAC9F,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,eAAe,OAAO,gBAAgB,EAAE,CAAC;AAAA,IAC5F,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,OAAO,cAAc,OAAO,OAAO,eAAe,EAAE,CAAC;AAAA,IAC/F,YAAY,WAAW,MAAM,OAAO,aAAa;AAAA,IACjD,aAAa,UAAU,MAAM,OAAO,cAAc;AAAA,IAClD,iBAAiB;AAAA;AAAA,IACjB,qBAAqB;AAAA;AAAA,IACrB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,gBAAgB;AAAA,IAChB,uBAAuB;AAAA;AAAA,IAGvB,OAAO;AAAA,IAAI,WAAW;AAAA,IAAI,UAAU;AAAA,IAAI,cAAc;AAAA,IACtD,cAAc;AAAA,IAAM,iBAAiB;AAAA,IAAM,cAAc;AAAA,IACzD,gBAAgB;AAAA,IAAM,cAAc;AAAA,IAAM,eAAe;AAAA,IACzD,gBAAgB;AAAA,IAAM,mBAAmB;AAAA,IAAM,gBAAgB;AAAA,IAAM,oBAAoB;AAAA,EAC3F;AACF;AAiBO,IAAM,YAAY;AAUlB,IAAM,uBAAuB;AAa7B,IAAM,kBAAkB;AAGxB,IAAM,eAAe;AAgCrB,IAAM,yBAAyB;AAoB/B,IAAM,gCAAgC;AAGtC,IAAM,+BAA+B;AAGrC,IAAM,iBAAiB;AAQvB,IAAM,uBAAuB,iBAAiB;AAM9C,IAAM,uBAAuB;AAC7B,IAAM,4BAA4B;AASlC,SAAS,oBAAoB,oBAAoC;AACtE,MAAI,CAAC,OAAO,UAAU,kBAAkB,KAAK,qBAAqB,GAAG;AACnE,UAAM,IAAI,MAAM,2EAA2E,kBAAkB,EAAE;AAAA,EACjH;AACA,SAAO,uBAAuB,uBAAuB,qBAAqB;AAC5E;AASO,IAAM,4BAA4B;AAwNlC,SAAS,sBAAsB,MAAkB,YAAoB,gBAAkC;AAC5G,QAAM,UAAU,YAAY;AAC5B,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,qDAAgD,OAAO,eAAe,KAAK,MAAM;AAAA,IACnF;AAAA,EACF;AAEA,QAAM,IAAI;AAGV,QAAM,aAAa,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAC7D,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAClE,QAAM,0BAA0B,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC3E,QAAM,wBAAwB,WAAW,MAAM,IAAI,EAAE;AACrD,QAAM,8BAA8B,WAAW,MAAM,IAAI,GAAG;AAC5D,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,kCAAkC,UAAU,MAAM,IAAI,GAAG;AAC/D,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,oCAAoC,WAAW,MAAM,IAAI,GAAG;AAClE,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AACvD,QAAM,gCAAgC,UAAU,MAAM,IAAI,GAAG;AAC7D,QAAM,gCAAgC,UAAU,MAAM,IAAI,GAAG;AAC7D,QAAM,yBAAyB,UAAU,MAAM,IAAI,GAAG;AACtD,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AACvD,QAAM,gCAAgC,OAAO,MAAM,IAAI,GAAG;AAC1D,QAAM,aAAa,OAAO,MAAM,IAAI,GAAG;AACvC,QAAM,iBAAiB,OAAO,MAAM,IAAI,GAAG;AAC3C,QAAM,iBAAiB,OAAO,MAAM,IAAI,GAAG;AAC3C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AAEnC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,iCAAiC,UAAU,MAAM,IAAI,GAAG;AAC9D,QAAM,4BAA4B,UAAU,MAAM,IAAI,GAAG;AACzD,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,wBAAwB,UAAU,MAAM,IAAI,GAAG;AACrD,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AAGvD,QAAMG,kBAAiB;AACvB,QAAM,iBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,mBAAe,KAAK,IAAIH,WAAU,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;AAAA,EAC5F;AAGA,QAAM,oBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIG,iBAAgB,KAAK;AACvC,sBAAkB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EACzD;AAGA,QAAM,wBAAkC,CAAC;AACzC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,0BAAsB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EAC7D;AAGA,QAAM,6BAA6B,UAAU,MAAM,IAAI,GAAG;AAC1D,QAAM,uCAAuC,UAAU,MAAM,IAAI,GAAG;AACpE,QAAM,wCAAwC,UAAU,MAAM,IAAI,GAAG;AACrE,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AAGvD,QAAM,uBAAuB,IAAIH,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAC1E,QAAM,0BAA0B,WAAW,MAAM,IAAI,GAAG;AACxD,QAAM,4BAA4B,WAAW,MAAM,IAAI,GAAG;AAK1D,QAAM,oBAAoB,WAAW,MAAM,IAAI,GAAG;AAClD,QAAM,sBAAsB,WAAW,MAAM,IAAI,GAAG;AACpD,QAAM,+BAA+B,WAAW,MAAM,IAAI,GAAG;AAC7D,QAAM,iCAAiC,WAAW,MAAM,IAAI,GAAG;AAC/D,QAAM,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAC/C,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAKjD,QAAM,2BAA2B,UAAU,MAAM,IAAI,6BAA6B;AAElF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA0EO,SAAS,2BAA2B,MAAkB,YAA2C;AACtG,QAAM,UAAU,aAAa;AAC7B,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,0DAAqD,OAAO,eAAe,KAAK,MAAM;AAAA,IACxF;AAAA,EACF;AAEA,QAAM,IAAI;AACV,QAAMG,kBAAiB;AAEvB,QAAM,iBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,mBAAe,KAAK,IAAIH,WAAU,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;AAAA,EAC5F;AAEA,QAAM,oBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIG,iBAAgB,KAAK;AACvC,sBAAkB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EACzD;AAEA,QAAM,wBAAkC,CAAC;AACzC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,0BAAsB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EAC7D;AAEA,SAAO;AAAA,IACL,YAAY,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9B,gBAAgB,OAAO,MAAM,IAAI,CAAC;AAAA,IAClC,gBAAgB,OAAO,MAAM,IAAI,CAAC;AAAA,IAClC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,IAC1B,WAAW,UAAU,MAAM,IAAI,CAAC;AAAA,IAChC,eAAe,UAAU,MAAM,IAAI,CAAC;AAAA,IACpC,wBAAwB,UAAU,MAAM,IAAI,EAAE;AAAA,IAC9C,yBAAyB,UAAU,MAAM,IAAI,EAAE;AAAA,IAC/C,sCAAsC,UAAU,MAAM,IAAI,EAAE;AAAA,IAC5D,uCAAuC,UAAU,MAAM,IAAI,EAAE;AAAA,IAC7D,oBAAoB,IAAIH,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC/D,mBAAmB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC9D,wBAAwB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,GAAG,CAAC;AAAA,IACpE,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,IAC9D,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAAA,IACzC,sBAAsB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC7C,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,IACnC,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAAA,IACzC,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC9C,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,IACnC,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC5C,yBAAyB,UAAU,MAAM,IAAI,GAAG;AAAA,IAChD,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,EAC3D;AACF;AAQO,SAAS,aAAa,MAA2B;AACtD,MAAI,KAAK,SAAS,GAAI,QAAO;AAC7B,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,SAAO,UAAU,aAAa,YAAY;AAC5C;AAcO,SAAS,mBAAmB,MAA2B;AAC5D,MAAI,KAAK,SAAS,eAAe,EAAG,QAAO;AAC3C,MAAI,CAAC,aAAa,IAAI,EAAG,QAAO;AAChC,SAAO,KAAK,YAAY,MAAM;AAChC;AAUA,IAAM,2BAA2B;AAMjC,IAAM,8BAA8B;AAUpC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AAkE9B,SAAS,sBAAsB,MAAoC;AACxE,QAAM,UAAU,uBAAuB;AACvC,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,0DAAqD,OAAO,eAAe,KAAK,MAAM;AAAA,IACxF;AAAA,EACF;AACA,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,uBAAuB;AAC5C,QAAM,mBAAmB,WAAW,MAAM,YAAY;AAGtD,QAAM,YAAY,uBAAuB;AACzC,QAAM,WAAW,KAAK;AAAA,KACnB,KAAK,SAAS,aAAa;AAAA,EAC9B;AAEA,MAAI,eAAe;AACnB,MAAI,gBAAgB;AACpB,QAAM,SAAqC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,UAAM,WAAW,YAAY,IAAI;AAGjC,UAAM,UACJ,WAAW,8BAA8B;AAC3C,UAAM,WACJ,WAAW,8BAA8B;AAG3C,QAAI,WAAW,KAAK,KAAK,OAAQ;AAEjC,UAAM,aAAa,WAAW,MAAM,OAAO;AAC3C,UAAM,cAAc,WAAW,MAAM,QAAQ;AAE7C,oBAAgB;AAChB,qBAAiB;AAEjB,QAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,aAAO,KAAK,EAAE,YAAY,GAAG,YAAY,YAAY,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,EAAE,kBAAkB,cAAc,eAAe,OAAO;AACjE;AAOA,IAAM,yBAAyB;AAC/B,IAAM,qBAAqB;AAC3B,IAAM,6BAA6B;AACnC,IAAM,yBAAyB;AAE/B,SAAS,0BACP,MACA,YACA,cACM;AACN,MAAI,KAAK,SAAS,wBAAwB;AACxC,UAAM,IAAI,MAAM,GAAG,UAAU,qBAAqB,KAAK,MAAM,MAAM,sBAAsB,GAAG;AAAA,EAC9F;AACA,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,MAAI,UAAU,WAAW;AACvB,UAAM,IAAI,MAAM,GAAG,UAAU,qBAAqB;AAAA,EACpD;AACA,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,MAAI,YAAY,sBAAsB;AACpC,UAAM,IAAI,MAAM,GAAG,UAAU,0BAA0B,OAAO,QAAQ,oBAAoB,GAAG;AAAA,EAC/F;AACA,QAAM,OAAO,OAAO,MAAM,EAAE;AAC5B,MAAI,SAAS,cAAc;AACzB,UAAM,IAAI,MAAM,GAAG,UAAU,+BAA+B,IAAI,QAAQ,YAAY,GAAG;AAAA,EACzF;AACF;AAIA,IAAM,oBAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,+BAAiC,oBAAoB;AAC3D,IAAM,0BAAiC,oBAAoB;AAC3D,IAAM,4BAAiC,oBAAoB;AAC3D,IAAM,yBAAiC,oBAAoB;AAC3D,IAAM,cAAiC,oBAAoB;AAC3D,IAAM,eAAiC;AACvC,IAAM,iBAAiC,cAAc;AACrD,IAAM,aAAiC,cAAc;AACrD,IAAM,sBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,4BAAiC,cAAc;AACrD,IAAM,2BAAiC,cAAc;AACrD,IAAM,qBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AAIrD,IAAM,cAAiC;AACvC,IAAM,cAAiC,cAAc;AACrD,IAAM,gBAAiC;AAUvC,IAAM,wBAAiC;AACvC,IAAM,wBAAiC,cAAc,gBAAgB;AACrE,IAAM,wBAAiC;AAEvC,IAAM,qBAAiC,wBAAwB,wBAAwB;AAmBvF,IAAM,wBAA2B;AACjC,IAAM,yBAA2B,4BAA4B;AAC7D,IAAM,yBAA2B,yBAAyB;AAC1D,IAAM,0BAA2B,yBAAyB;AAC1D,IAAM,yBAA2B,0BAA0B;AAmGpD,SAAS,kBAAkB,MAAgC;AAEhE,QAAM,sBAAsB,sBAAsB;AAClD,MAAI,KAAK,SAAS,qBAAqB;AACrC,UAAM,IAAI,MAAM,sCAAsC,KAAK,MAAM,MAAM,mBAAmB,GAAG;AAAA,EAC/F;AACA,4BAA0B,MAAM,qBAAqB,kBAAkB;AAGvE,QAAM,gBAAgB,IAAIA,WAAU,KAAK,SAAS,gCAAgC,iCAAiC,EAAE,CAAC;AACtH,QAAM,qBAAqB,IAAIA,WAAU,KAAK,SAAS,8BAA8B,+BAA+B,EAAE,CAAC;AACvH,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,yBAAyB,0BAA0B,EAAE,CAAC;AAG1G,QAAM,QAAQ,IAAIA,WAAU,KAAK,SAAS,cAAc,eAAe,EAAE,CAAC;AAC1E,QAAM,UAAU,WAAW,MAAM,cAAc;AAC/C,QAAM,MAAM,WAAW,MAAM,UAAU;AACvC,QAAM,cAAc,WAAW,MAAM,mBAAmB;AAExD,QAAM,qCAAqC,KAAK,UAAU,uBAAuB,KAC7E,WAAW,MAAM,oBAAoB,IAAI;AAC7C,QAAM,mCAAmC,KAAK,UAAU,4BAA4B,KAChF,WAAW,MAAM,yBAAyB,IAAI;AAClD,QAAM,6BAA6B,KAAK,UAAU,2BAA2B,KACzE,WAAW,MAAM,wBAAwB,IAAI;AACjD,QAAM,aAAa,KAAK,UAAU,qBAAqB,KACnD,WAAW,MAAM,kBAAkB,IAAI;AAC3C,QAAM,sBAAsB,KAAK,UAAU,uBAAuB,KAC9D,WAAW,MAAM,oBAAoB,IAAI;AAC7C,QAAM,cAAc,KAAK,UAAU,uBAAuB,IACtD,UAAU,MAAM,oBAAoB,IAAI;AAC5C,QAAM,eAAe,KAAK,UAAU,uBAAuB,IACvD,UAAU,MAAM,oBAAoB,IAAI;AAG5C,QAAM,OAA0B,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,UAAM,IAAI,cAAc,IAAI;AAC5B,QAAI,KAAK,SAAS,IAAI,YAAa;AACnC,SAAK,KAAK;AAAA,MACR,QAAQ,KAAK,CAAC,MAAM;AAAA,MACpB,YAAY,UAAU,MAAM,IAAI,CAAC;AAAA,MACjC,UAAU,UAAU,MAAM,IAAI,CAAC;AAAA,MAC/B,MAAM,KAAK,IAAI,EAAE;AAAA,MACjB,WAAW,WAAW,MAAM,IAAI,EAAE;AAAA,MAClC,QAAQ,WAAW,MAAM,IAAI,EAAE;AAAA,MAC/B,OAAO,WAAW,MAAM,IAAI,EAAE;AAAA,MAC9B,OAAO,WAAW,MAAM,IAAI,EAAE;AAAA,MAC9B,WAAW,UAAU,MAAM,IAAI,EAAE;AAAA,MACjC,YAAY,WAAW,MAAM,IAAI,EAAE;AAAA,MACnC,OAAO,WAAW,MAAM,IAAI,GAAG;AAAA,MAC/B,MAAM,WAAW,MAAM,IAAI,GAAG;AAAA,MAC9B,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,MACnC,QAAQ,KAAK,IAAI,GAAG,MAAM;AAAA,MAC1B,OAAO,KAAK,IAAI,GAAG,MAAM;AAAA,IAC3B,CAAC;AAAA,EACH;AAGA,QAAM,gBAA4C,CAAC;AACnD,WAAS,IAAI,GAAG,IAAI,uBAAuB,KAAK;AAC9C,UAAM,IAAI,wBAAwB,IAAI;AACtC,QAAI,KAAK,SAAS,IAAI,sBAAuB;AAC7C,kBAAc,KAAK;AAAA,MACjB,QAAQ,UAAU,MAAM,IAAI,CAAC;AAAA,MAC7B,qBAAqB,UAAU,MAAM,IAAI,CAAC;AAAA,MAC1C,qBAAqB,WAAW,MAAM,IAAI,EAAE;AAAA,MAC5C,sBAAsB,WAAW,MAAM,IAAI,EAAE;AAAA,MAC7C,kCAAkC,WAAW,MAAM,IAAI,EAAE;AAAA,MACzD,+BAA+B,WAAW,MAAM,IAAI,EAAE;AAAA,MACtD,6BAA6B,WAAW,MAAM,IAAI,EAAE;AAAA,MACpD,kCAAkC,WAAW,MAAM,IAAI,EAAE;AAAA,MACzD,+BAA+B,WAAW,MAAM,IAAI,GAAG;AAAA,MACvD,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAAA,MAC9C,wBAAwB,WAAW,MAAM,IAAI,GAAG;AAAA,MAChD,qCAAqC,WAAW,MAAM,IAAI,GAAG;AAAA,MAC7D,mCAAmC,WAAW,MAAM,IAAI,GAAG;AAAA,MAC3D,2CAA2C,WAAW,MAAM,IAAI,GAAG;AAAA,IACrE,CAAC;AAAA,EACH;AAEA,QAAM,iBAAiB,KAAK,UAAU,yBAAyB,KAC3D,IAAIA,WAAU,KAAK,SAAS,wBAAwB,yBAAyB,EAAE,CAAC,IAChFA,WAAU;AACd,QAAM,iBAAiB,KAAK,UAAU,yBAAyB,KAC3D,IAAIA,WAAU,KAAK,SAAS,wBAAwB,yBAAyB,EAAE,CAAC,IAChFA,WAAU;AACd,QAAM,kBAAkB,KAAK,UAAU,0BAA0B,KAC7D,IAAIA,WAAU,KAAK,SAAS,yBAAyB,0BAA0B,EAAE,CAAC,IAClFA,WAAU;AAMd,MAAI,iBAAiB;AACrB,MAAI,KAAK,UAAU,yBAAyB,GAAG;AAC7C,UAAM,aAAa,UAAU,MAAM,sBAAsB;AACzD,QAAI,aAAa,IAAI;AACnB,YAAM,IAAI;AAAA,QACR,kDAAkD,UAAU;AAAA,MAC9D;AAAA,IACF;AACA,qBAAiB,eAAe;AAAA,EAClC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWA,IAAM,0BAA0B;AAmCzB,SAAS,qBAAqB,MAAsC;AACzE,MAAI,KAAK,SAAS,yBAAyB;AACzC,UAAM,IAAI;AAAA,MACR,yCAAyC,KAAK,MAAM,MAAM,uBAAuB;AAAA,IACnF;AAAA,EACF;AACA,4BAA0B,MAAM,wBAAwB,0BAA0B;AAClF,QAAM,IAAI;AACV,SAAO;AAAA,IACL,aAAa,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAAA,IACvD,QAAQ,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IACnD,0BAA0B,WAAW,MAAM,IAAI,EAAE;AAAA,IACjD,2BAA2B,WAAW,MAAM,IAAI,EAAE;AAAA,IAClD,2BAA2B,WAAW,MAAM,IAAI,EAAE;AAAA,IAClD,OAAO,UAAU,MAAM,IAAI,GAAG;AAAA,IAC9B,yBAAyB,UAAU,MAAM,IAAI,GAAG;AAAA,IAChD,aAAa,UAAU,MAAM,IAAI,GAAG;AAAA,IACpC,2BAA2B,UAAU,MAAM,IAAI,GAAG;AAAA,IAClD,QAAQ,UAAU,MAAM,IAAI,GAAG;AAAA,IAC/B,QAAQ,KAAK,IAAI,GAAG,MAAM;AAAA,IAC1B,SAAS,KAAK,IAAI,GAAG;AAAA,IACrB,MAAM,KAAK,IAAI,GAAG;AAAA,IAClB,UAAU,KAAK,IAAI,GAAG;AAAA,EACxB;AACF;AAQA,IAAM,sBAAsB;AA6BrB,SAAS,kBAAkB,MAAmC;AACnE,MAAI,KAAK,SAAS,qBAAqB;AACrC,UAAM,IAAI;AAAA,MACR,sCAAsC,KAAK,MAAM,MAAM,mBAAmB;AAAA,IAC5E;AAAA,EACF;AACA,4BAA0B,MAAM,qBAAqB,sBAAsB;AAC3E,QAAM,IAAI;AACV,SAAO;AAAA,IACL,UAAU,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAAA,IACpD,UAAU,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IACrD,QAAQ,WAAW,MAAM,IAAI,EAAE;AAAA,IAC/B,aAAa,UAAU,MAAM,IAAI,EAAE;AAAA,IACnC,SAAS,KAAK,IAAI,EAAE;AAAA,IACpB,MAAM,KAAK,IAAI,EAAE;AAAA,EACnB;AACF;AAKO,SAAS,iBAAiB,MAAuD;AACtF,QAAM,UAAU,iBAAiB,IAAI;AACrC,QAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,QAAM,eAAe,QAAQ,OAAO,SAAO,MAAM,MAAM;AACvD,QAAM,eAAe,QAAQ,SAAS,aAAa;AACnD,MAAI,eAAe,GAAG;AACpB,YAAQ;AAAA,MACN,oCAAoC,QAAQ,MAAM,2BAA2B,MAAM,2BAClE,YAAY;AAAA,IAC/B;AAAA,EACF;AACA,SAAO,aAAa,IAAI,UAAQ;AAAA,IAC9B;AAAA,IACA,SAAS,aAAa,MAAM,GAAG;AAAA,EACjC,EAAE;AACJ;;;ACp1JA,SAAS,aAAAI,kBAAiB;AAE1B,IAAM,cAAc,IAAI,YAAY;AAUpC,SAAS,MAAM,OAA2B;AACxC,MACE,OAAO,UAAU,YACjB,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,QAAQ,OACR;AACA,UAAM,IAAI,MAAM,sDAAsD,KAAK,EAAE;AAAA,EAC/E;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE;AAAA,IAAU;AAAA,IAAG;AAAA;AAAA,IAAyB;AAAA,EAAI;AACnE,SAAO;AACT;AASO,SAAS,qBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC;AAAA,IAC5C;AAAA,EACF;AACF;AAYO,IAAM,8BAA8B,IAAIA;AAAA,EAC7C;AACF;AAWO,IAAM,oCAAoC,IAAIA;AAAA,EACnD;AACF;AAyCO,SAAS,qBACd,WACA,QACA,MACqB;AACrB,QAAM,CAAC,cAAc,IAAI,qBAAqB,WAAW,MAAM;AAC/D,SAAO,iCAAiC,gBAAgB,IAAI;AAC9D;AAmBO,SAAS,iCACd,gBACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,eAAe,QAAQ;AAAA,MACvB,kCAAkC,QAAQ;AAAA,MAC1C,KAAK,QAAQ;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AA8CO,SAAS,0BACd,WACA,QACA,MACqB;AACrB,QAAM,CAAC,gBAAgB,kBAAkB,IAAI,qBAAqB,WAAW,MAAM;AACnF,QAAM,CAAC,YAAY,cAAc,IAAI;AAAA,IACnC;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,EAChB;AACF;AAOO,SAAS,sBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,eAAe,GAAG,KAAK,QAAQ,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,IAAM,mBAAmB;AAMlB,SAAS,YACd,WACA,MACA,OACqB;AACrB,MACE,OAAO,UAAU,YACjB,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,QAAQ,kBACR;AACA,UAAM,IAAI;AAAA,MACR,gDAAgD,gBAAgB,UAAU,KAAK;AAAA,IACjF;AAAA,EACF;AACA,QAAM,SAAS,IAAI,WAAW,CAAC;AAC/B,MAAI,SAAS,OAAO,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AACpD,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,IAAI,GAAG,KAAK,QAAQ,GAAG,MAAM;AAAA,IACjD;AAAA,EACF;AACF;AAOO,IAAM,sBAAsB,IAAIA;AAAA,EACrC;AACF;AAGO,IAAM,0BAA0B,IAAIA;AAAA,EACzC;AACF;AAGO,IAAM,0BAA0B,IAAIA;AAAA,EACzC;AACF;AAOO,IAAM,8BAA8B,IAAIA;AAAA,EAC7C;AACF;AAUO,IAAM,oBAAoB;AAoB1B,SAAS,qBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,iBAAiB,GAAG,KAAK,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAyBO,SAAS,sBACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,UAAU,GAAG,YAAY,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAsBO,SAAS,mBACd,WACA,UACA,UACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,eAAe;AAAA,MAClC,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAuBO,SAAS,sBACd,WACA,aACA,WACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,mBAAmB;AAAA,MACtC,YAAY,QAAQ;AAAA,MACpB,MAAM,SAAS;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;AAqBO,SAAS,eACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,WAAW,GAAG,YAAY,QAAQ,CAAC;AAAA,IACvD;AAAA,EACF;AACF;AAyBO,SAAS,kBACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,cAAc,GAAG,YAAY,QAAQ,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AAqCO,SAAS,sBACd,WACA,QACA,UACA,eACA,aACA,YACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,SAAS;AAAA,MAC5B,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,uBAAuB,WAA2B;AACzD,MAAI,IAAI,UAAU,KAAK;AACvB,MAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,IAAI,GAAG;AAC5C,QAAI,EAAE,MAAM,CAAC;AAAA,EACf;AACA,SAAO;AACT;AAOA,IAAM,cAAc;AAEb,SAAS,wBAAwB,WAAwC;AAC9E,QAAM,aAAa,uBAAuB,SAAS;AACnD,MAAI,CAAC,YAAY,KAAK,UAAU,GAAG;AACjC,UAAM,IAAI;AAAA,MACR,4EAA4E,WAAW,WAAW,KAAK,+BAA+B,WAAW,SAAS,QAAQ;AAAA,IAAO;AAAA,EAC7K;AACA,QAAM,SAAS,IAAI,WAAW,EAAE;AAChC,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,WAAO,CAAC,IAAI,SAAS,WAAW,UAAU,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;AAAA,EACjE;AACA,QAAM,WAAW,IAAI,WAAW,CAAC;AACjC,SAAOC,WAAU;AAAA,IACf,CAAC,UAAU,MAAM;AAAA,IACjB;AAAA,EACF;AACF;;;AChkBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA,oBAAAC;AAAA,OACK;AAOP,eAAsB,OACpB,OACA,MACA,qBAAqB,OACrB,iBAA4BA,mBACR;AACpB,SAAO,0BAA0B,MAAM,OAAO,oBAAoB,cAAc;AAClF;AAMO,SAAS,WACd,OACA,MACA,qBAAqB,OACrB,iBAA4BA,mBACjB;AACX,SAAO,8BAA8B,MAAM,OAAO,oBAAoB,cAAc;AACtF;AAOA,eAAsB,kBACpB,YACA,SACA,iBAA4BA,mBACV;AAClB,SAAO,WAAW,YAAY,SAAS,QAAW,cAAc;AAClE;;;AC/CA,SAAqB,aAAAC,kBAAiB;;;ACoBtC,SAAS,aAAAC,kBAAiB;AA2B1B,IAAM,kBAAuC;AAAA,EAC3C,EAAE,aAAa,gDAAgD,QAAQ,YAAY,MAAM,qBAAqB;AAChH;AAUA,IAAM,iBAAsC;AAAA;AAAA;AAG5C;AAKA,IAAM,kBAAwD;AAAA,EAC5D,SAAS;AAAA,EACT,QAAQ;AACV;AAMA,IAAM,eAAqD;AAAA,EACzD,SAAS,CAAC;AAAA,EACV,QAAQ,CAAC;AACX;AAoBO,SAAS,iBAAiB,SAAuC;AACtE,QAAM,UAAU,gBAAgB,OAAO,KAAK,CAAC;AAC7C,QAAM,OAAO,aAAa,OAAO,KAAK,CAAC;AAEvC,MAAI,KAAK,WAAW,EAAG,QAAO,CAAC,GAAG,OAAO;AAGzC,QAAM,OAAO,oBAAI,IAA+B;AAChD,aAAW,SAAS,SAAS;AAC3B,SAAK,IAAI,MAAM,aAAa,KAAK;AAAA,EACnC;AACA,aAAW,SAAS,MAAM;AACxB,SAAK,IAAI,MAAM,aAAa,KAAK;AAAA,EACnC;AACA,SAAO,CAAC,GAAG,KAAK,OAAO,CAAC;AAC1B;AAyBO,SAAS,sBACd,SACA,SACM;AACN,QAAM,WAAW,aAAa,OAAO;AACrC,QAAM,OAAO,IAAI,IAAI,SAAS,IAAI,OAAK,EAAE,WAAW,CAAC;AAErD,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAa;AACxB,QAAI,KAAK,IAAI,MAAM,WAAW,EAAG;AAEjC,QAAI;AACF,UAAIA,WAAU,MAAM,WAAW;AAAA,IACjC,QAAQ;AACN,cAAQ;AAAA,QACN,yDAAyD,MAAM,WAAW;AAAA,MAC5E;AACA;AAAA,IACF;AACA,SAAK,IAAI,MAAM,WAAW;AAC1B,aAAS,KAAK,KAAK;AAAA,EACrB;AACF;AASO,SAAS,mBAAmB,SAAyB;AAC1D,MAAI,SAAS;AACX,iBAAa,OAAO,IAAI,CAAC;AAAA,EAC3B,OAAO;AACL,iBAAa,UAAU,CAAC;AACxB,iBAAa,SAAS,CAAC;AAAA,EACzB;AACF;;;ADnJA,IAAM,uBAAuB;AA8C7B,IAAM,cAAc,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AASnF,IAAM,kBAAkB,IAAI,WAAW,CAAC,GAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AA4BhF,IAAM,aAAa;AAAA,EACxB,OAAQ,kBAAkB,OAAO;AAAA,EACjC,QAAQ,kBAAkB,QAAQ;AAAA,EAClC,OAAQ,kBAAkB,OAAO;AACnC;AAGO,IAAM,gBAAgB;AAAA,EAC3B,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAW,OAAO,SAAU,aAAa,2BAAwB;AAAA,EACxG,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAW,OAAO,UAAU,aAAa,6BAA0B;AAAA,EAC1G,OAAQ,EAAE,aAAa,MAAM,UAAU,QAAW,OAAO,SAAU,aAAa,6BAA0B;AAC5G;AAgBO,IAAM,iBAAiB;AAAA,EAC5B,OAAQ,EAAE,aAAa,IAAM,UAAU,OAAY,OAAO,SAAU,aAAa,wBAAwB;AAAA,EACzG,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAY,OAAO,SAAU,aAAa,yBAAyB;AAAA,EAC1G,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAY,OAAO,UAAU,aAAa,2BAA2B;AAAA,EAC5G,OAAQ,EAAE,aAAa,MAAM,UAAU,SAAY,OAAO,SAAU,aAAa,2BAA2B;AAC9G;AAcO,IAAM,wBAAwB;AAAA,EACnC,OAAQ,EAAE,aAAa,IAAM,UAAU,OAAY,OAAO,SAAU,aAAa,uCAAuC;AAAA,EACxH,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAY,OAAO,SAAU,aAAa,wCAAwC;AAAA,EACzH,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAY,OAAO,UAAU,aAAa,0CAA0C;AAAA,EAC3H,OAAQ,EAAE,aAAa,MAAM,UAAU,SAAY,OAAO,SAAU,aAAa,0CAA0C;AAC7H;AAGO,IAAM,gBAAgB;AAStB,IAAM,6BAA6B;AAiBnC,SAAS,aAAa,aAA6B;AAExD,QAAM,gBAAgB;AACtB,QAAMC,wBAAuB;AAC7B,QAAM,kBAAkB;AACxB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiBA,wBAAuB,cAAc,aAAa;AACzE,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,gBAAgB,cAAc,cAAc;AACrD;AAWO,SAAS,eAAe,aAA6B;AAC1D,QAAM,gBAAgB;AACtB,QAAM,uBAAuB;AAC7B,QAAM,kBAAkB;AACxB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,uBAAuB,cAAc,aAAa;AACzE,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,gBAAgB,cAAc,cAAc;AACrD;AAUO,SAAS,sBAAsB,UAAkB,gBAAiC;AACvF,SAAO,aAAa;AACtB;AAGA,IAAM,iBAAiB;AAAA,EACrB,GAAG,OAAO,OAAO,UAAU,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EAChD,GAAG,OAAO,OAAO,aAAa,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACnD,GAAG,OAAO,OAAO,cAAc,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACpD,GAAG,OAAO,OAAO,qBAAqB,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EAC3D,GAAG,OAAO,OAAO,cAAc,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACpD,GAAG,OAAO,OAAO,gBAAgB,EAAE,IAAI,OAAK,EAAE,QAAQ;AACxD;AAGA,IAAM,iBAAiB,WAAW,MAAM;AAGxC,IAAM,sBAAsB;AAE5B,SAASC,IAAG,MAA4B;AACtC,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACnE;AACA,SAASC,WAAU,MAAkB,KAAqB;AACxD,SAAOD,IAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AACA,SAASE,WAAU,MAAkB,KAAqB;AACxD,SAAOF,IAAG,IAAI,EAAE,aAAa,KAAK,IAAI;AACxC;AACA,SAASG,WAAU,MAAkB,KAAqB;AACxD,SAAOH,IAAG,IAAI,EAAE,YAAY,KAAK,IAAI;AACvC;AACA,SAASI,YAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAKF,WAAU,KAAK,MAAM;AAChC,QAAM,KAAKA,WAAU,KAAK,SAAS,CAAC;AACpC,SAAQ,MAAM,MAAO;AACvB;AACA,SAASG,YAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAKH,WAAU,KAAK,MAAM;AAChC,QAAM,KAAKA,WAAU,KAAK,SAAS,CAAC;AACpC,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,SAAU,QAAO,YAAY,MAAM;AACnD,SAAO;AACT;AAUO,SAAS,iBACd,MACA,QACA,cAAsB,MACT;AACb,QAAM,OAAO,CAAC,UAAU,OAAO,YAAY;AAC3C,QAAM,OAAO,SAAS,OAAO,YAAY;AACzC,QAAM,YAAY,SAAS,OAAO,kBAAkB;AAEpD,QAAM,SAAS,OAAO;AACtB,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,IAAI,MAAM,+CAA+C,KAAK,MAAM,MAAM,MAAM,EAAE;AAAA,EAC1F;AAGA,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,aAAa,YAAY,cAAc;AAC7C,QAAM,mBAAmB,KAAK,MAAM,aAAa,KAAK,CAAC,IAAI;AAE3D,QAAM,iBAAiB,KAAK,UAAU,OAAO,aAAa;AAC1D,QAAM,gBAAgB,KAAK,UAAU,OAAO,mBAAmB;AAE/D,MAAI,MAAM;AASR,WAAO;AAAA,MACL,OAAOE,YAAW,MAAM,OAAO,CAAC;AAAA,MAChC,eAAe;AAAA,QACb,SAASA,YAAW,MAAM,OAAO,EAAE;AAAA,QACnC,YAAYA,YAAW,MAAM,OAAO,EAAE;AAAA,QACtC,iBAAiB;AAAA,QACjB,cAAc;AAAA,MAChB;AAAA,MACA,aAAaF,WAAU,MAAM,OAAO,GAAG;AAAA,MACvC,mBAAmBG,YAAW,MAAM,OAAO,GAAG;AAAA,MAC9C,iBAAiBH,WAAU,MAAM,OAAO,GAAG;AAAA,MAC3C,2BAA2BC,WAAU,MAAM,OAAO,GAAG;AAAA,MACrD,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,eAAeD,WAAU,MAAM,OAAO,GAAG;AAAA,MACzC,wBAAwBA,WAAU,MAAM,OAAO,GAAG;AAAA,MAClD,mBAAmBE,YAAW,MAAM,OAAO,GAAG;AAAA,MAC9C,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAMA,YAAW,MAAM,OAAO,GAAG;AAAA,MACjC,WAAWA,YAAW,MAAM,OAAO,GAAG;AAAA,MACtC,kBAAkB;AAAA,MAClB,WAAWH,WAAU,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUA,WAAU,MAAM,OAAO,GAAG;AAAA,MACpC,oBAAoBC,WAAU,MAAM,OAAO,GAAG;AAAA,MAC9C,uBAAuBA,WAAU,MAAM,OAAO,GAAG;AAAA,MACjD,aAAaD,WAAU,MAAM,OAAO,GAAG;AAAA,MACvC,eAAeA,WAAU,MAAM,OAAO,GAAG;AAAA,MACzC,sBAAsBC,WAAU,MAAM,OAAO,GAAG;AAAA,MAChD,qBAAqBA,WAAU,MAAM,OAAO,GAAG;AAAA,MAC/C,UAAUG,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUD,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUA,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,aAAa;AAAA;AAAA,MACb,eAAe;AAAA,MACf,UAAU;AAAA,MAAI,WAAW;AAAA,MAAI,oBAAoB;AAAA,MAAI,YAAY;AAAA,MACjE,4BAA4B;AAAA,MAAI,6BAA6B;AAAA,MAAI,mBAAmB;AAAA,MACpF,iBAAiB,iBAAiBH,WAAU,MAAM,OAAO,UAAU,IAAI;AAAA,MACvE,eAAe,gBAAgBC,WAAU,MAAM,OAAO,gBAAgB,IAAI;AAAA,IAC5E;AAAA,EACF;AAmBA,MAAI,WAAW,MAAM;AACnB,UAAM,IAAI;AAEV,UAAM,wBAAwB,EAAE,8BAA8B,KAAK,EAAE,kCAAkC;AAMvG,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAID,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAIC,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAIC,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,SAAS,CAAC,QAAyB,OAAO,IAAIC,YAAW,MAAM,OAAO,GAAG,IAAI;AACnF,UAAM,SAAS,CAAC,QAAyB,OAAO,IAAIC,YAAW,MAAM,OAAO,GAAG,IAAI;AACnF,WAAO;AAAA,MACL,OAAOD,YAAW,MAAM,OAAO,CAAC;AAAA,MAChC,eAAe;AAAA,QACb,SAASA,YAAW,MAAM,OAAO,EAAE,kBAAkB;AAAA,QACrD,YAAYA,YAAW,MAAM,OAAO,EAAE,qBAAqB,EAAE;AAAA,QAC7D,iBAAiB,wBAAwBA,YAAW,MAAM,OAAO,EAAE,0BAA0B,IAAI;AAAA,QACjG,cAAc,wBAAwBH,WAAU,MAAM,OAAO,EAAE,8BAA8B,IAAI;AAAA,MACnG;AAAA,MACA,aAAaC,WAAU,MAAM,OAAO,EAAE,oBAAoB;AAAA;AAAA;AAAA;AAAA,MAI1D,mBAAmB,EAAE,yBAAyB,IACxC,EAAE,4BAA4B,KAAK,EAAE,2BAA2B,EAAE,0BAA0B,IAC1F,OAAOC,WAAU,MAAM,OAAO,EAAE,qBAAqB,CAAC,IACtDE,YAAW,MAAM,OAAO,EAAE,qBAAqB,IACnD;AAAA,MACJ,iBAAiB,MAAM,EAAE,wBAAwB;AAAA,MACjD,2BAA2B,MAAM,EAAE,uBAAuB;AAAA,MAC1D,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,eAAe,MAAM,EAAE,sBAAsB;AAAA,MAC7C,wBAAwB,MAAM,EAAE,0BAA0B;AAAA,MAC1D,mBAAmB,OAAO,EAAE,gBAAgB;AAAA,MAC5C,QAAQ,OAAO,EAAE,eAAe;AAAA,MAChC,SAAS,OAAO,EAAE,gBAAgB;AAAA,MAClC,MAAMD,YAAW,MAAM,OAAO,EAAE,aAAa;AAAA,MAC7C,WAAWA,YAAW,MAAM,OAAO,EAAE,kBAAkB;AAAA,MACvD,kBAAkB;AAAA,MAClB,WAAW,MAAM,EAAE,kBAAkB;AAAA,MACrC,UAAU,MAAM,EAAE,iBAAiB;AAAA,MACnC,oBAAoB,MAAM,EAAE,uBAAuB;AAAA,MACnD,uBAAuB,MAAM,EAAE,0BAA0B;AAAA,MACzD,aAAa,MAAM,EAAE,oBAAoB;AAAA,MACzC,eAAe,MAAM,EAAE,sBAAsB;AAAA,MAC7C,sBAAsB,MAAM,EAAE,6BAA6B;AAAA,MAC3D,qBAAqB,MAAM,EAAE,4BAA4B;AAAA,MACzD,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,eAAe,OAAO,EAAE,sBAAsB;AAAA,MAC9C,iBAAiB,EAAE,4BAA4B,IAAI,KAAK,OAAO,EAAE,wBAAwB,MAAM,IAAI;AAAA,MACnG,oBAAoB,MAAM,EAAE,2BAA2B;AAAA,MACvD,iBAAiB,MAAM,EAAE,wBAAwB;AAAA,MACjD,aAAa,MAAM,EAAE,kBAAkB;AAAA,MACvC,eAAe;AAAA,MACf,UAAU;AAAA,MACV,WAAW;AAAA,MACX,oBAAoB;AAAA,MACpB,YAAY;AAAA,MACZ,4BAA4B;AAAA,MAC5B,6BAA6B;AAAA,MAC7B,mBAAmB;AAAA,MACnB,iBAAiB,iBAAiBH,WAAU,MAAM,OAAO,UAAU,IAAI;AAAA,MACvE,eAAe,gBAAgBC,WAAU,MAAM,OAAO,gBAAgB,IAAI;AAAA,IAC5E;AAAA,EACF;AAIA,QAAM,IAAI,MAAM,oDAAoD,IAAI,GAAG;AAC7E;AA8FA,SAAS,iBAAiB,KAAuB;AAC/C,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,SACE,IAAI,SAAS,KAAK,KAClB,IAAI,YAAY,EAAE,SAAS,YAAY,KACvC,IAAI,YAAY,EAAE,SAAS,mBAAmB;AAElD;AAGA,SAAS,WAAW,SAAyB;AAC3C,QAAM,OAAO,KAAK,MAAM,UAAU,CAAC;AACnC,SAAO,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,UAAU,OAAO,EAAE;AAC/D;AAQA,eAAsB,gBACpB,YACA,WACA,UAAkC,CAAC,GACN;AAC7B,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,qBAAqB,CAAC,KAAO,KAAO,KAAO,IAAM;AAAA,IACjD,mBAAmB;AAAA,EACrB,IAAI;AAmBJ,QAAM,gBAAgB;AAAA,IACpB,GAAG,OAAO,OAAO,UAAU;AAAA;AAAA,IAC3B,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,gBAAgB;AAAA;AAAA,IACjC,GAAG,OAAO,OAAO,aAAa;AAAA,IAC9B,GAAG,OAAO,OAAO,cAAc;AAAA,IAC/B,GAAG,OAAO,OAAO,qBAAqB;AAAA,IACtC,GAAG,OAAO,OAAO,aAAa;AAAA,IAC9B,GAAG,OAAO,OAAO,cAAc;AAAA,IAC/B,GAAG,OAAO,OAAO,eAAe;AAAA,IAChC,GAAG,OAAO,OAAO,gBAAgB;AAAA,IACjC,GAAG,OAAO,OAAO,uBAAuB;AAAA,EAC1C;AACA,QAAM,aAAa,oBAAI,IAAuD;AAC9E,aAAW,QAAQ,eAAe;AAChC,UAAM,WAAW,WAAW,IAAI,KAAK,QAAQ;AAC7C,QAAI,CAAC,YAAY,KAAK,cAAc,SAAS,aAAa;AACxD,iBAAW,IAAI,KAAK,UAAU,IAAI;AAAA,IACpC;AAAA,EACF;AACA,QAAM,YAAY,CAAC,GAAG,WAAW,OAAO,CAAC;AAEzC,MAAI,cAA0B,CAAC;AAM/B,iBAAe,mBACb,MACqB;AACrB,aAAS,UAAU,GAAG,WAAW,mBAAmB,QAAQ,WAAW;AACrE,UAAI;AACF,cAAM,UAAU,MAAM,WAAW,mBAAmB,WAAW;AAAA,UAC7D,SAAS,CAAC,EAAE,UAAU,KAAK,SAAS,CAAC;AAAA,UACrC,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,QACtD,CAAC;AACD,eAAO,QAAQ,IAAI,YAAU,EAAE,GAAG,OAAO,aAAa,KAAK,aAAa,UAAU,KAAK,SAAS,EAAE;AAAA,MACpG,SAAS,KAAK;AACZ,YAAI,iBAAiB,GAAG,KAAK,UAAU,mBAAmB,QAAQ;AAChE,gBAAM,QAAQ,WAAW,mBAAmB,OAAO,CAAC;AACpD,kBAAQ;AAAA,YACN,0CAA0C,KAAK,QAAQ,YAAY,UAAU,CAAC,iBAAiB,KAAK;AAAA,UACtG;AACA,gBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,KAAK,CAAC;AAC3C;AAAA,QACF;AAEA,gBAAQ;AAAA,UACN,iDAAiD,KAAK,QAAQ,aAAa,UAAU,CAAC;AAAA,UACtF,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AACA,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,iBAAiB,QAAQ,kBAAkB,UAAU;AAC3D,QAAM,eAAe,UAAU,MAAM,GAAG,cAAc;AAGtD,QAAM,4BAA4B,KAAK,IAAI,GAAG,OAAO,SAAS,gBAAgB,IAAI,mBAAmB,CAAC;AAEtG,MAAI;AACF,QAAI,YAAY;AAEd,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAM,OAAO,aAAa,CAAC;AAC3B,cAAM,UAAU,MAAM,mBAAmB,IAAI;AAC7C,oBAAY,KAAK,GAAG,OAAO;AAC3B,YAAI,IAAI,aAAa,SAAS,GAAG;AAC/B,gBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,gBAAgB,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF,OAAO;AAGL,eAAS,SAAS,GAAG,SAAS,aAAa,QAAQ,UAAU,2BAA2B;AACtF,cAAM,QAAQ,aAAa,MAAM,QAAQ,SAAS,yBAAyB;AAC3E,cAAM,UAAU,MAAM;AAAA,UAAI,UACxB,WAAW,mBAAmB,WAAW;AAAA,YACvC,SAAS,CAAC,EAAE,UAAU,KAAK,SAAS,CAAC;AAAA,YACrC,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,UACtD,CAAC,EAAE;AAAA,YAAK,CAAAI,aACNA,SAAQ,IAAI,YAAU;AAAA,cACpB,GAAG;AAAA,cACH,aAAa,KAAK;AAAA,cAClB,UAAU,KAAK;AAAA,YACjB,EAAE;AAAA,UACJ;AAAA,QACF;AAEA,cAAM,UAAU,MAAM,QAAQ,WAAW,OAAO;AAChD,mBAAW,UAAU,SAAS;AAC5B,cAAI,OAAO,WAAW,aAAa;AACjC,uBAAW,SAAS,OAAO,OAAO;AAChC,0BAAY,KAAK,KAAiB;AAAA,YACpC;AAAA,UACF,OAAO;AACL,oBAAQ;AAAA,cACN;AAAA,cACA,OAAO,kBAAkB,QAAQ,OAAO,OAAO,UAAU,OAAO;AAAA,YAClE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAMA,QAAI;AACF,YAAM,aAAa,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAChE,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO,OAAO,KAAK,eAAe,EAAE,SAAS,QAAQ;AAAA,cACrD,UAAU;AAAA,YACZ;AAAA,UACF;AAAA,QACF;AAAA,QACA,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,MACtD,CAAC;AACD,iBAAW,KAAK,YAAY;AAC1B,oBAAY,KAAK,EAAE,GAAG,GAAG,aAAa,GAAG,UAAU,EAAE,QAAQ,KAAK,OAAO,CAAa;AAAA,MACxF;AAAA,IACF,QAAQ;AAAA,IAER;AAIA,QAAI,YAAY,WAAW,GAAG;AAC5B,cAAQ,KAAK,+EAA+E;AAG5F,YAAM,WAAW,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC9D,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AACD,oBAAc,CAAC,GAAG,QAAQ,EAAE,IAAI,OAAK;AACnC,cAAM,MAAM,EAAE,QAAQ,KAAK;AAC3B,cAAM,MAAM,iBAAiB,KAAK,IAAI,WAAW,EAAE,QAAQ,IAAI,CAAC;AAChE,eAAO,EAAE,GAAG,GAAG,aAAa,KAAK,eAAe,MAAM,UAAU,IAAI;AAAA,MACtE,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN;AAAA,MACA,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AACA,QAAI;AAEF,YAAM,WAAW,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC9D,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AACD,oBAAc,CAAC,GAAG,QAAQ,EAAE,IAAI,OAAK;AACnC,cAAM,MAAM,EAAE,QAAQ,KAAK;AAC3B,cAAM,MAAM,iBAAiB,KAAK,IAAI,WAAW,EAAE,QAAQ,IAAI,CAAC;AAChE,eAAO,EAAE,GAAG,GAAG,aAAa,KAAK,eAAe,MAAM,UAAU,IAAI;AAAA,MACtE,CAAC;AAAA,IACH,SAAS,WAAW;AAElB,cAAQ;AAAA,QACN;AAAA,QACA,qBAAqB,QAAQ,UAAU,UAAU;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAKA,MAAI,YAAY,WAAW,KAAK,QAAQ,YAAY;AAClD,YAAQ;AAAA,MACN;AAAA,IACF;AACA,QAAI;AACF,YAAM,YAAY,MAAM;AAAA,QACtB;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,EAAE,WAAW,QAAQ,aAAa;AAAA,MACpC;AACA,UAAI,UAAU,SAAS,GAAG;AACxB,eAAO;AAAA,MACT;AAEA,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,SAAS,QAAQ;AACf,cAAQ;AAAA,QACN;AAAA,QACA,kBAAkB,QAAQ,OAAO,UAAU;AAAA,MAC7C;AAAA,IAEF;AAAA,EACF;AAKA,MAAI,YAAY,WAAW,KAAK,QAAQ,SAAS;AAC/C,UAAM,gBAAgB,iBAAiB,QAAQ,OAAO;AACtD,QAAI,cAAc,SAAS,GAAG;AAC5B,cAAQ;AAAA,QACN,qEAAqE,cAAc,MAAM,kBAAkB,QAAQ,OAAO;AAAA,MAC5H;AACA,UAAI;AACF,eAAO,MAAM;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF,SAAS,WAAW;AAClB,gBAAQ;AAAA,UACN;AAAA,UACA,qBAAqB,QAAQ,UAAU,UAAU;AAAA,QACnD;AAAA,MAEF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN,qDAAqD,QAAQ,OAAO;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW;AAEjB,QAAM,UAA8B,CAAC;AAGrC,QAAM,cAAc,oBAAI,IAAY;AAEpC,aAAW,EAAE,QAAQ,SAAS,aAAa,SAAS,KAAK,UAAU;AACjE,UAAM,QAAQ,OAAO,SAAS;AAC9B,QAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,gBAAY,IAAI,KAAK;AACrB,UAAM,OAAO,IAAI,WAAW,QAAQ,IAAI;AAUxC,QAAI,mBAAmB,IAAI,GAAG;AAC5B,UAAI;AACF,cAAM,YAAY,sBAAsB,IAAI;AAC5C,gBAAQ,KAAK;AAAA,UACX,aAAa;AAAA,UACb;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,iDAAiD,KAAK;AAAA,UACtD,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAI,KAAK,CAAC,MAAM,YAAY,CAAC,GAAG;AAC9B,gBAAQ;AACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,MAAO;AAKZ,UAAM,SAAS,iBAAiB,UAAU,IAAI;AAE9C,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN,sCAAsC,KAAK,sCAAsC,QAAQ;AAAA,MAC3F;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,YAAY,MAAM,MAAM;AACvC,YAAM,SAAS,iBAAiB,MAAM,QAAQ,WAAW;AACzD,YAAM,SAAS,YAAY,MAAM,MAAM;AAEvC,cAAQ,KAAK,EAAE,aAAa,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjF,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,6CAA6C,OAAO,SAAS,CAAC;AAAA,QAC9D,eAAe,QAAQ,IAAI,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAwDA,eAAsB,oBACpB,YACA,WACA,WACA,UAAsC,CAAC,GACV;AAC7B,MAAI,UAAU,WAAW,EAAG,QAAO,CAAC;AAEpC,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,oBAAoB;AAAA,EACtB,IAAI;AAEJ,QAAM,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,GAAG,CAAC;AAI/D,QAAM,UAA2B,CAAC;AAElC,WAAS,SAAS,GAAG,SAAS,UAAU,QAAQ,UAAU,oBAAoB;AAC5E,UAAM,QAAQ,UAAU,MAAM,QAAQ,SAAS,kBAAkB;AAEjE,UAAM,WAAW,MAAM,WAAW,wBAAwB,KAAK;AAE/D,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,OAAO,SAAS,CAAC;AACvB,UAAI,QAAQ,KAAK,MAAM;AACrB,YAAI,CAAC,KAAK,MAAM,OAAO,SAAS,GAAG;AACjC,kBAAQ;AAAA,YACN,kCAAkC,MAAM,CAAC,EAAE,SAAS,CAAC,8BACxC,UAAU,SAAS,CAAC,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,UACjE;AACA;AAAA,QACF;AACA,gBAAQ,KAAK,EAAE,QAAQ,MAAM,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC;AAAA,MACpD;AAAA,IACF;AAGA,QAAI,oBAAoB,KAAK,SAAS,qBAAqB,UAAU,QAAQ;AAC3E,YAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,iBAAiB,CAAC;AAAA,IACzD;AAAA,EACF;AAGA,QAAM,UAA8B,CAAC;AAErC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAO;AACZ,UAAM,EAAE,QAAQ,MAAM,QAAQ,IAAI;AAClC,UAAM,OAAO,IAAI,WAAW,OAAO;AAKnC,QAAI,mBAAmB,IAAI,GAAG;AAC5B,UAAI;AACF,cAAM,YAAY,sBAAsB,IAAI;AAI5C,gBAAQ,KAAK;AAAA,UACX,aAAa;AAAA,UACb;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,qDAAqD,OAAO,SAAS,CAAC;AAAA,UACtE,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAI,KAAK,CAAC,MAAM,YAAY,CAAC,GAAG;AAC9B,gBAAQ;AACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,OAAO;AACV,cAAQ;AAAA,QACN,kCAAkC,OAAO,SAAS,CAAC;AAAA,MACrD;AACA;AAAA,IACF;AAGA,UAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN,kCAAkC,OAAO,SAAS,CAAC,sCAAsC,KAAK,MAAM;AAAA,MACtG;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,YAAY,MAAM,MAAM;AACvC,YAAM,SAAS,iBAAiB,MAAM,QAAQ,OAAO,WAAW;AAChE,YAAM,SAAS,YAAY,MAAM,MAAM;AAEvC,cAAQ,KAAK,EAAE,aAAa,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjF,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,iDAAiD,OAAO,SAAS,CAAC;AAAA,QAClE,eAAe,QAAQ,IAAI,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAqEA,eAAsB,sBACpB,YACA,WACA,YACA,UAAwC,CAAC,GACZ;AAC7B,QAAM,EAAE,YAAY,KAAQ,eAAe,IAAI;AAG/C,QAAM,OAAO,WAAW,QAAQ,QAAQ,EAAE;AAC1C,QAAM,MAAM,GAAG,IAAI;AAGnB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,KAAK;AAAA,MAC1B,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACtC,QAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,EACH,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AAEA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,wCAAwC,SAAS,MAAM,IAAI,SAAS,UAAU,SAAS,GAAG;AAAA,IAC5F;AAAA,EACF;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAM,aAAa,KAAK;AAExB,MAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW,GAAG;AACzD,YAAQ,KAAK,gDAAgD;AAC7D,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,YAAyB,CAAC;AAChC,aAAW,SAAS,YAAY;AAC9B,QAAI,CAAC,MAAM,gBAAgB,OAAO,MAAM,iBAAiB,SAAU;AACnE,QAAI;AACF,gBAAU,KAAK,IAAIC,WAAU,MAAM,YAAY,CAAC;AAAA,IAClD,QAAQ;AACN,cAAQ;AAAA,QACN,0DAA0D,MAAM,YAAY;AAAA,MAC9E;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,KAAK,0DAA0D;AACvE,WAAO,CAAC;AAAA,EACV;AAEA,UAAQ;AAAA,IACN,wCAAwC,UAAU,MAAM;AAAA,EAC1D;AAGA,SAAO,oBAAoB,YAAY,WAAW,WAAW,cAAc;AAC7E;AAqDA,eAAsB,+BACpB,YACA,WACA,SACA,UAAiD,CAAC,GACrB;AAC7B,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAGlC,QAAM,YAAyB,CAAC;AAChC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,eAAe,OAAO,MAAM,gBAAgB,SAAU;AACjE,QAAI;AACF,gBAAU,KAAK,IAAIA,WAAU,MAAM,WAAW,CAAC;AAAA,IACjD,QAAQ;AACN,cAAQ;AAAA,QACN,mEAAmE,MAAM,WAAW;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,KAAK,2EAA2E;AACxF,WAAO,CAAC;AAAA,EACV;AAEA,UAAQ;AAAA,IACN,6CAA6C,UAAU,MAAM;AAAA,EAC/D;AAEA,SAAO,oBAAoB,YAAY,WAAW,WAAW,QAAQ,cAAc;AACrF;;;AE1yCA,SAAqB,aAAAC,kBAAiB;AA6B/B,SAAS,cAAc,gBAA2C;AACvE,MAAI,eAAe,OAAO,mBAAmB,EAAG,QAAO;AACvD,MAAI,eAAe,OAAO,uBAAuB,EAAG,QAAO;AAC3D,MAAI,eAAe,OAAO,uBAAuB,EAAG,QAAO;AAC3D,SAAO;AACT;AAWO,SAAS,aACd,SACA,aACA,MACa;AACb,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO,kBAAkB,aAAa,IAAI;AAAA,IAC5C,KAAK;AACH,aAAO,qBAAqB,aAAa,IAAI;AAAA,IAC/C,KAAK;AACH,aAAO,iBAAiB,aAAa,IAAI;AAAA,EAC7C;AACF;AA0BO,SAAS,sBACd,SACA,MACA,WACA,UACA,YACQ;AACR,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,6DAA6D;AAK7F,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,4DAA4D;AAAA,MAC9E;AACA,aAAO,uBAAuB,MAAM,WAAW,UAAU,UAAU;AAAA,IACrE,KAAK;AACH,aAAO,0BAA0B,IAAI;AAAA,IACvC,KAAK;AAIH,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,gEAAgE;AAAA,MAClF;AACA,aAAO,0BAA0B,MAAM,SAAS,MAAM,SAAS,KAAK;AAAA,EACxE;AACF;AAYO,IAAM,2BAA2B;AA6BxC,eAAsB,kBACpB,YACA,MACiB;AACjB,QAAM,OAAO,MAAM,WAAW,eAAe,IAAI;AACjD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,iDAAiD,KAAK,SAAS,CAAC,EAAE;AAAA,EACpF;AACA,MAAI,KAAK,KAAK,UAAU,0BAA0B;AAChD,UAAM,IAAI;AAAA,MACR,8CAA8C,KAAK,KAAK,MAAM,oBAAoB,KAAK,SAAS,CAAC;AAAA,IACnG;AAAA,EACF;AACA,SAAO,KAAK,KAAK,wBAAwB;AAC3C;AAWO,IAAM,YAAY,IAAIC,WAAU,6CAA6C;AA2BpF,IAAM,mBAAmB;AAMzB,SAAS,kBAAkB,aAAwB,MAA+B;AAChF,MAAI,KAAK,SAAS,kBAAkB;AAClC,UAAM,IAAI,MAAM,iCAAiC,KAAK,MAAM,MAAM,gBAAgB,EAAE;AAAA,EACtF;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIA,WAAU,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA,IAC1C,WAAW,IAAIA,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC5C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,IAC7C,YAAY,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAChD;AACF;AAEA,IAAM,2BAA2B;AA0BjC,SAAS,uBACP,UACA,WACA,UACA,YACQ;AACR,MAAI,SAAS,SAAS,kBAAkB;AACtC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,MAAM,gBAAgB,EAAE;AAAA,EAC1F;AACA,MAAI,UAAU,KAAK,SAAS,0BAA0B;AACpD,UAAM,IAAI,MAAM,uCAAuC,UAAU,KAAK,MAAM,MAAM,wBAAwB,EAAE;AAAA,EAC9G;AACA,MAAI,UAAU,MAAM,SAAS,0BAA0B;AACrD,UAAM,IAAI,MAAM,wCAAwC,UAAU,MAAM,MAAM,MAAM,wBAAwB,EAAE;AAAA,EAChH;AACA,sBAAoB,YAAY,QAAQ,SAAS,IAAI;AACrD,sBAAoB,YAAY,SAAS,SAAS,KAAK;AAEvD,QAAM,SAAS,IAAI,SAAS,UAAU,KAAK,QAAQ,UAAU,KAAK,YAAY,UAAU,KAAK,UAAU;AACvG,QAAM,UAAU,IAAI,SAAS,UAAU,MAAM,QAAQ,UAAU,MAAM,YAAY,UAAU,MAAM,UAAU;AAE3G,QAAM,aAAaC,WAAU,QAAQ,EAAE;AACvC,QAAM,cAAcA,WAAU,SAAS,EAAE;AAEzC,MAAI,eAAe,GAAI,QAAO;AAO9B,QAAM,YAAY,OAAO,OAAO,SAAS,IAAI;AAC7C,QAAM,aAAa,OAAO,OAAO,SAAS,KAAK;AAC/C,QAAM,iBAAkB,cAAc,YAAY,YAAe,aAAa;AAE9E,QAAM,YAAY,IAAID,WAAU,SAAS,MAAM,IAAI,GAAG,CAAC;AACvD,MAAI,UAAU,OAAO,SAAS,GAAG;AAE/B,QAAI,eAAe,QAAW;AAC5B,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAQ,iBAAiB,aAAc;AAAA,EACzC;AAGA,SAAO;AACT;AAMA,IAAM,uBAAuB;AAM7B,SAAS,qBAAqB,aAAwB,MAA+B;AACnF,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,qCAAqC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EAC9F;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIA,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC3C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AACF;AAYA,IAAM,qBAAqB;AAE3B,SAAS,oBAAoB,SAAiB,OAAe,UAAwB;AACnF,MAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,KAAK,WAAW,oBAAoB;AAChF,UAAM,IAAI;AAAA,MACR,GAAG,OAAO,KAAK,KAAK,2BAA2B,QAAQ,0BAA0B,kBAAkB;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,0BAA0B,MAA0B;AAC3D,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EACzF;AACA,QAAME,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAErE,QAAM,YAAY,KAAK,GAAG;AAC1B,QAAM,YAAY,KAAK,GAAG;AAE1B,MAAI,YAAY,sBAAsB,YAAY,oBAAoB;AACpE,UAAM,IAAI;AAAA,MACR,wCAAwC,SAAS,KAAK,SAAS,UAAU,kBAAkB;AAAA,IAC7F;AAAA,EACF;AAEA,QAAM,eAAeC,YAAWD,KAAI,GAAG;AAEvC,MAAI,iBAAiB,GAAI,QAAO;AAUhC,QAAM,QAAQ,eAAe,eAAe;AAE5C,QAAM,cAAc,IAAI,YAAY;AACpC,QAAM,eAAe,cAAc;AAEnC,MAAI,gBAAgB,GAAG;AACrB,WAAQ,QAAQ,OAAO,OAAO,YAAY,KAAM;AAAA,EAClD,OAAO;AACL,WAAO,UAAU,MAAM,QAAQ,OAAO,OAAO,CAAC,YAAY;AAAA,EAC5D;AACF;AAwBA,IAAM,uBAAuB;AAW7B,SAAS,iBAAiB,aAAwB,MAA+B;AAC/E,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,qCAAqC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EAC9F;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIF,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC3C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AACF;AAYA,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAE1B,SAAS,0BACP,MACA,cACA,eACQ;AACR,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EACzF;AACA,sBAAoB,gBAAgB,QAAQ,YAAY;AACxD,sBAAoB,gBAAgB,SAAS,aAAa;AAC1D,QAAME,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAMrE,QAAM,UAAUA,IAAG,UAAU,IAAI,IAAI;AACrC,QAAM,WAAWA,IAAG,SAAS,IAAI,IAAI;AAErC,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,UAAU,cAAc;AAC1B,UAAM,IAAI,MAAM,yBAAyB,OAAO,gBAAgB,YAAY,EAAE;AAAA,EAChF;AACA,MAAI,KAAK,IAAI,QAAQ,IAAI,mBAAmB;AAC1C,UAAM,IAAI;AAAA,MACR,4BAA4B,KAAK,IAAI,QAAQ,CAAC,gBAAgB,iBAAiB;AAAA,IACjF;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,QAAM,OAAO,QAAS,OAAO,OAAO,IAAI,QAAS;AAEjD,QAAM,QAAQ,WAAW;AACzB,MAAI,MAAM,QAAQ,OAAO,CAAC,QAAQ,IAAI,OAAO,QAAQ;AAErD,MAAI,SAAS;AACb,MAAI,IAAI;AAER,SAAO,MAAM,IAAI;AACf,QAAI,MAAM,IAAI;AACZ,eAAU,SAAS,IAAK;AAAA,IAC1B;AACA,YAAQ;AACR,QAAI,MAAM,IAAI;AACZ,UAAK,IAAI,IAAK;AAAA,IAChB;AAAA,EACF;AASA,QAAM,OAAO,eAAe;AAE5B,MAAI,OAAO;AACT,QAAI,WAAW,GAAI,QAAO;AAE1B,UAAM,MAAM;AACZ,QAAI,QAAQ,GAAG;AACb,aAAQ,MAAM,OAAO,OAAO,IAAI,IAAK;AAAA,IACvC;AACA,WAAO,OAAO,SAAS,OAAO,OAAO,CAAC,IAAI;AAAA,EAC5C,OAAO;AAEL,QAAI,QAAQ,GAAG;AACb,aAAQ,SAAS,OAAO,OAAO,IAAI,IAAK;AAAA,IAC1C;AACA,WAAO,UAAU,iBAAqB,OAAO,OAAO,CAAC,IAAI;AAAA,EAC3D;AACF;AAOA,SAASD,WAAUC,KAAc,QAAwB;AACvD,QAAM,KAAK,OAAOA,IAAG,UAAU,QAAQ,IAAI,CAAC;AAC5C,QAAM,KAAK,OAAOA,IAAG,UAAU,SAAS,GAAG,IAAI,CAAC;AAChD,SAAO,KAAM,MAAM;AACrB;AAGA,SAASC,YAAWD,KAAc,QAAwB;AACxD,QAAM,KAAKD,WAAUC,KAAI,MAAM;AAC/B,QAAM,KAAKD,WAAUC,KAAI,SAAS,CAAC;AACnC,SAAO,KAAM,MAAM;AACrB;;;AClfA,IAAM,qBAAqB;AAG3B,IAAM,eAAe;AAGrB,IAAM,4BAA4B;AAOlC,IAAM,6BAA6B;AAMnC,IAAM,0BAA0B;AA4BhC,SAASE,QAAO,MAAkB,KAAqB;AACrD,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,eAAe,MAAkB,KAAqB;AAC7D,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,YAAY,KAAK,IAAI;AAC1F;AAEA,SAAS,gBAAgB,MAAkB,KAAqB;AAC9D,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,aAAa,KAAK,IAAI;AAC3F;AAEA,SAASC,WAAU,MAAkB,KAAqB;AACxD,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,UAAU,KAAK,IAAI;AACxF;AAWA,IAAM,mCAAmC;AAqBlC,SAAS,oBAAoB,MAAkB,SAA8C;AAClG,MAAI,KAAK,SAAS,oBAAoB;AACpC,UAAM,IAAI;AAAA,MACR,kCAAkC,KAAK,MAAM,yBAAyB,kBAAkB;AAAA,IAC1F;AAAA,EACF;AAEA,QAAM,WAAWD,QAAO,MAAM,yBAAyB;AACvD,MAAI,WAAW,cAAc;AAC3B,UAAM,IAAI;AAAA,MACR,iCAAiC,QAAQ,SAAS,YAAY;AAAA,IAChE;AAAA,EACF;AAYA,QAAM,SACH,eAAe,MAAM,0BAA0B,CAAC,KAAK,MACtD,gBAAgB,MAAM,uBAAuB;AAC/C,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,iCAAiC,MAAM;AAAA,IACzC;AAAA,EACF;AACA,QAAM,QAAQ;AAGd,QAAM,YAAYC,WAAU,MAAM,0BAA0B;AAE5D,MAAI,SAAS,wBAAwB,QAAW;AAI9C,QAAI,aAAa,GAAG;AAClB,YAAM,IAAI;AAAA,QACR,oDAAoD,SAAS;AAAA,MAC/D;AAAA,IACF;AACA,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,UAAM,MAAM,MAAM;AAIlB,UAAM,kBACJ,QAAQ,0BAA0B;AACpC,QAAI,MAAM,CAAC,iBAAiB;AAC1B,YAAM,IAAI;AAAA,QACR,+BAA+B,CAAC,GAAG,8BAA8B,eAAe;AAAA,MAElF;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,qBAAqB;AACrC,YAAM,IAAI;AAAA,QACR,uCAAuC,GAAG,cAAc,QAAQ,mBAAmB;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,UAAU,WAAW,YAAY,IAAI,YAAY,OAAU;AAC7E;AAOO,SAAS,uBAAuB,MAA2B;AAChE,MAAI;AACF,wBAAoB,IAAI;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AChNA,SAAqB,aAAAC,mBAAiB;AACtC,SAAS,oBAAAC,yBAAwB;AAK1B,IAAM,wBAAwB,IAAID;AAAA,EACvC;AACF;AAeA,eAAsB,mBACpB,YACA,MACoB;AACpB,QAAM,OAAO,MAAM,WAAW,eAAe,IAAI;AACjD,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,2BAA2B,KAAK,SAAS,CAAC,EAAE;AAEvE,MAAI,KAAK,MAAM,OAAOC,iBAAgB,EAAG,QAAOA;AAChD,MAAI,KAAK,MAAM,OAAO,qBAAqB,EAAG,QAAO;AAErD,QAAM,IAAI;AAAA,IACR,WAAW,KAAK,SAAS,CAAC,+BAA+B,KAAK,MAAM,SAAS,CAAC,0BACnDA,kBAAiB,SAAS,CAAC,qBACrC,sBAAsB,SAAS,CAAC;AAAA,EACnD;AACF;AAKO,SAAS,YAAY,gBAAoC;AAC9D,SAAO,eAAe,OAAO,qBAAqB;AACpD;AAKO,SAAS,gBAAgB,gBAAoC;AAClE,SAAO,eAAe,OAAOA,iBAAgB;AAC/C;;;AC/BA,SAAS,aAAAC,aAAW,iBAAAC,gBAAe,sBAAAC,qBAAoB,uBAAAC,4BAA2B;AAClF,SAAS,oBAAAC,mBAAkB,yBAAAC,8BAA6B;AAiCjD,IAAM,oBAAoB;AAAA,EAC/B,QAAQ;AAAA,EACR,SAAS;AACX;AACA,OAAO,OAAO,iBAAiB;AAG/B,IAAM,0BAA0B,IAAI,IAAY,OAAO,OAAO,iBAAiB,CAAC;AAYzE,SAAS,kBAAkB,SAA2C;AAI3E,MAAI,CAAC,SAAS;AACZ,UAAM,WAAW,QAAQ,kBAAkB;AAC3C,QAAI,UAAU;AAGZ,UACE,CAAC,wBAAwB,IAAI,QAAQ,KACrC,QAAQ,uCAAuC,MAAM,KACrD;AACA,cAAM,IAAI;AAAA,UACR,8CAA8C,QAAQ,2DACnC,CAAC,GAAG,uBAAuB,EAAE,KAAK,IAAI,CAAC;AAAA,QAG5D;AAAA,MACF;AACA,cAAQ;AAAA,QACN,0DAA0D,QAAQ;AAAA,MACpE;AACA,aAAO,IAAIC,YAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,kBACJ,YACC,MAAM;AACL,UAAM,IAAI,QAAQ,6BAA6B,GAAG,YAAY,KACpD,QAAQ,SAAS,GAAG,YAAY,KAAK;AAC/C,QAAI,MAAM,aAAa,MAAM,eAAgB,QAAO;AACpD,QAAI,MAAM,SAAU,QAAO;AAkB3B,UAAM,IAAI;AAAA,MACR;AAAA,IASF;AAAA,EACF,GAAG;AAEL,QAAM,KAAK,kBAAkB,eAAe;AAC5C,MAAI,CAAC,IAAI;AACP,UAAM,IAAI;AAAA,MACR,iCAAiC,eAAe;AAAA,IAElD;AAAA,EACF;AACA,SAAO,IAAIA,YAAU,EAAE;AACzB;AAUO,IAAM,mBAAmB,IAAIA,YAAU,kBAAkB,MAAM;AAkB/D,IAAM,WAAW;AAAA,EACtB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAed,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYd,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcb,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWzB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWxB,wBAAwB;AAAA;AAAA;AAAA,EAGxB,eAAe;AAAA;AAAA;AAAA,EAGf,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,uBAAuB;AAAA;AAAA;AAAA;AAAA,EAIvB,wBAAwB;AAAA;AAAA;AAAA;AAAA,EAIxB,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,iBAAiB;AAAA;AAAA,EAEjB,wBAAwB;AAAA;AAAA;AAAA,EAGxB,yBAAyB;AAAA;AAAA,EAEzB,YAAY;AAAA;AAAA,EAEZ,iBAAiB;AAAA;AAAA,EAEjB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcnB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAef,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYxB,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW1B,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAezB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBzB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYvB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAenB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAarB,kCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAalC,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY7B,2BAA2B;AAC7B;AACA,OAAO,OAAO,QAAQ;AAmBf,IAAM,eAAuC;AAAA,EAClD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AACA,OAAO,OAAO,YAAY;AAM1B,IAAMC,QAAO,IAAI,YAAY;AAGtB,SAAS,gBAAgB,MAAiB,WAAuB;AACtE,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,YAAY,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AACvF;AAGO,SAAS,qBAAqB,MAAiB,WAAuB;AAC3E,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,YAAY,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AACvF;AAGO,SAAS,iBAAiB,MAAiB,MAAiB,WAAuB;AACxF,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,eAAe,GAAG,KAAK,QAAQ,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AAC1G;AAMA,SAASC,WAAU,MAAkB,KAAqB;AACxD,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,SAAO,KAAK;AAAA,IAAa;AAAA;AAAA,IAAyB;AAAA,EAAI;AACxD;AAGA,SAASC,WAAU,MAAkB,KAAqB;AACxD,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,SAAO,KAAK;AAAA,IAAU;AAAA;AAAA,IAAyB;AAAA,EAAI;AACrD;AAEA,SAAS,qBACP,aACA,MACA,QACA,UACM;AACN,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AAC3C,QAAI,KAAK,SAAS,CAAC,MAAM,SAAS,CAAC,GAAG;AACpC,YAAM,IAAI,MAAM,GAAG,WAAW,wBAAwB;AAAA,IACxD;AAAA,EACF;AACF;AAMA,SAAS,MAAM,GAAgC;AAC7C,MAAI,OAAO,MAAM,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;AACrD,UAAM,IAAI,MAAM,iBAAiB,CAAC,oDAA+C;AAAA,EACnF;AAEA,QAAM,MAAM,OAAO,CAAC;AACpB,MAAI,MAAM,GAAI,OAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AAC7E,MAAI,MAAM,oBAAwB,OAAM,IAAI,MAAM,8BAA8B;AAChF,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,aAAa,GAAG,KAAK,IAAI;AAAI,SAAO;AAC/D;AAEA,SAAS,OAAO,GAAgC;AAC9C,MAAI,OAAO,MAAM,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;AACrD,UAAM,IAAI,MAAM,kBAAkB,CAAC,oDAA+C;AAAA,EACpF;AAEA,QAAM,MAAM,OAAO,CAAC;AACpB,MAAI,MAAM,GAAI,OAAM,IAAI,MAAM,2CAA2C,GAAG,EAAE;AAC9E,MAAI,OAAO,MAAM,QAAQ,GAAI,OAAM,IAAI,MAAM,gCAAgC;AAC7E,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,QAAM,OAAO,IAAI,SAAS,IAAI,MAAM;AAAI,OAAK,aAAa,GAAG,MAAM,qBAAqB,IAAI;AAC5F,OAAK,aAAa,GAAG,OAAO,KAAK,IAAI;AACrC,SAAO;AACT;AAEA,SAAS,MAAM,GAAuB;AACpC,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,MAAQ,OAAM,IAAI,MAAM,iDAAiD,CAAC,EAAE;AAAI,QAAM,MAAM,IAAI,WAAW,CAAC;AAAI,MAAI,SAAS,IAAI,MAAM,EAAE,UAAU,GAAG,GAAG,IAAI;AACtM,SAAO;AACT;AAGO,SAAS,oBAAoB,eAAgC,YAAyC;AAC3G,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,QAAQ,CAAC;AAAA,IAClC,MAAM,aAAa;AAAA,IACnB,MAAM,UAAU;AAAA,EAClB;AACF;AAGO,SAAS,mBAAmB,QAAqC;AACtE,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC;AACtE;AAGO,SAAS,oBAAoB,UAAuC;AACzE,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,QAAQ,CAAC,GAAG,MAAM,QAAQ,CAAC;AACzE;AAGO,SAAS,4BAA4B,QAAqC;AAC/E,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,gBAAgB,CAAC,GAAG,MAAM,MAAM,CAAC;AAC/E;AAGO,SAAS,wBACd,kBACA,eACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,YAAY,CAAC;AAAA,IACtC,IAAI,WAAW,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;AAAA,IACjD,MAAM,oBAAoB,EAAE;AAAA,IAC5B,IAAI,WAAW,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;AAAA,IAC9C,MAAM,iBAAiB,EAAE;AAAA,EAC3B;AACF;AAEA,SAAS,wBAAwB,MAAc,KAAoB;AACjE,QAAM,IAAI;AAAA,IACR,GAAG,IAAI,eAAe,GAAG;AAAA,EAC3B;AACF;AAWO,SAAS,wBAAwB,UAAiC;AACvE,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,YAAY,CAAC;AAAA,IACtC,SAAS,QAAQ;AAAA,EACnB;AACF;AAQO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,SAAS,WAAW,CAAC;AAC9C;AAUO,SAAS,mCAAmC,kBAA+C;AAChG,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAAA,IACjD,MAAM,gBAAgB;AAAA,EACxB;AACF;AAQO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AAQO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AASO,SAAS,2BAAuC;AACrD,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,mCAAmC,cAAqC;AACtF,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,iCAAiC,cAA2C;AAC1F,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,kCAAkC,QAAqC;AACrF,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,gCAA4C;AAC1D,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAGO,SAAS,2BAA2B,QAAqC;AAC9E,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,eAAe,CAAC;AAAA,IACzC,MAAM,MAAM;AAAA,EACd;AACF;AAGO,SAAS,kCAAkC,QAAqC;AACrF,SAAO,2BAA2B,MAAM;AAC1C;AAGO,SAAS,wBAAoC;AAClD,SAAO,IAAI,WAAW,CAAC,SAAS,UAAU,CAAC;AAC7C;AAGO,SAAS,2BAA2B,eAAgC,YAAyC;AAClH,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,eAAe,CAAC;AAAA,IACzC,MAAM,aAAa;AAAA,IACnB,MAAM,UAAU;AAAA,EAClB;AACF;AAGO,SAAS,6BACd,SACA,aACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,iBAAiB,CAAC;AAAA,IAC3C,IAAI,WAAW,CAAC,UAAU,IAAI,CAAC,CAAC;AAAA,IAChC,MAAM,WAAW;AAAA,EACnB;AACF;AAcO,SAAS,iCAAiC,kBAAsC;AACrF,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,qBAAqB,CAAC;AAAA,IAC/C,MAAM,gBAAgB;AAAA,EACxB;AACF;AAWO,SAAS,yBAAyB,QAAqC;AAC5E,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,aAAa,CAAC,GAAG,MAAM,MAAM,CAAC;AAC5E;AAaO,SAAS,+BAA2C;AACzD,SAAO,IAAI,WAAW,CAAC,SAAS,iBAAiB,CAAC;AACpD;AAsBO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AAyCO,SAAS,+BACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAkBO,SAAS,sCAAkD;AAChE,SAAO,IAAI,WAAW,CAAC,SAAS,wBAAwB,CAAC;AAC3D;AAkBO,SAAS,qCAAiD;AAC/D,SAAO,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAC1D;AAoCO,SAAS,wBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAmBO,SAAS,4BAAwC;AACtD,SAAO,IAAI,WAAW,CAAC,SAAS,cAAc,CAAC;AACjD;AA+BO,SAAS,uBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAuBO,SAAS,mCAAmC,QAAqC;AACtF,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAAA,IACjD,MAAM,MAAM;AAAA,EACd;AACF;AA2CO,SAAS,gCACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,QAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,SAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,WAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,WAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,eAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,cAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,kBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,cAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,mBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,EACrE;AACF;AAqBO,SAAS,mCAA+C;AAC7D,SAAO,IAAI,WAAW,CAAC,SAAS,qBAAqB,CAAC;AACxD;AA4BO,SAAS,8BACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAiDO,SAAS,+BACd,iBACA,YACA,mBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,mBAAmB,CAAC;AAAA,IAC7C,MAAM,eAAe;AAAA,IACrB,MAAM,UAAU;AAAA,IAChB,MAAM,iBAAiB;AAAA,EACzB;AACF;AAsBO,SAAS,4CACd,uBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,gCAAgC,CAAC;AAAA,IAC1D,OAAO,qBAAqB;AAAA,EAC9B;AACF;AAsBO,SAAS,uCACd,QACA,QACA,mBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,2BAA2B,CAAC;AAAA,IACrD,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,IACZ,MAAM,iBAAiB;AAAA,EACzB;AACF;AAqBO,SAAS,qCACd,iBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,yBAAyB,CAAC;AAAA,IACnD,MAAM,eAAe;AAAA,EACvB;AACF;AAiCO,SAAS,yBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAGO,IAAM,8BAA8B;AAGpC,IAAM,2CAA2C;AAuCjD,SAAS,yBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAGO,IAAM,sCAAsC;AAG5C,IAAM,oCAAoC;AAG1C,SAAS,mCACd,WACA,iBACA,gBACA,eACY;AACZ,OAAK;AACL,OAAK;AACL,OAAK;AACL,OAAK;AACL,SAAO,wBAAwB,sCAAsC,SAAS,uBAAuB;AACvG;AAuKO,IAAM,qBAAqB;AAe3B,IAAM,qBAAqB;AAiB3B,IAAM,qBAAqB;AAS3B,IAAM,kBAAkB;AACxB,IAAM,2BAA2B,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AAChG,IAAM,6BAA6B;AAsBnC,SAAS,gBAAgB,MAAkC;AAChE,QAAM,OAAO,KAAK,UAAU;AAC5B,QAAM,OAAO,CAAC,QAAQ,KAAK,UAAU;AACrC,QAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,UAAU;AAC9C,MAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM;AAC3B,UAAM,IAAI,MAAM,6BAA6B,KAAK,MAAM,MAAM,kBAAkB,EAAE;AAAA,EACpF;AAIA,QAAM,iBAAiB,OAAO,MAAM;AACpC,uBAAqB,aAAa,MAAM,gBAAgB,wBAAwB;AAChF,QAAM,UAAU,KAAK,iBAAiB,CAAC;AACvC,QAAM,kBAAkB,OAAO,IAAI,OAAO,IAAI;AAC9C,MAAI,YAAY,iBAAiB;AAC/B,UAAM,IAAI,MAAM,kCAAkC,OAAO,QAAQ,eAAe,EAAE;AAAA,EACpF;AAEA,QAAM,QAAQ,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAC1E,MAAI,MAAM;AACV,QAAM,gBAAgB,MAAM,GAAG,MAAM;AAAG,SAAO;AAC/C,QAAM,OAAO,MAAM,GAAG;AAAG,SAAO;AAChC,QAAM,qBAAqB,MAAM,GAAG;AAAG,SAAO;AAC9C,QAAM,mBAAmB,MAAM,GAAG,MAAM;AAAG,SAAO;AAClD,SAAO;AAEP,QAAM,OAAO,IAAIH,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAClE,QAAM,QAAQ,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AACnE,QAAM,iBAAiB,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAC5E,QAAM,SAAS,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AACpE,QAAM,QAAQ,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAEnE,QAAM,iBAAiBE,WAAU,OAAO,GAAG;AAAG,SAAO;AACrD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,aAAaA,WAAU,OAAO,GAAG;AAAG,SAAO;AACjD,QAAM,eAAeA,WAAU,OAAO,GAAG;AAAG,SAAO;AACnD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,iBAAiBA,WAAU,OAAO,GAAG;AAAG,SAAO;AAErD,QAAM,oBAAoB,IAAIF,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAG/E,QAAM,kBAAkBE,WAAU,OAAO,GAAG;AAAG,SAAO;AACtD,QAAM,qBAAqBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACzD,QAAM,oBAAoBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACxD,QAAM,WAAW,MAAM,GAAG;AAAG,SAAO;AACpC,SAAO;AAIP,MAAI,eAAiC;AACrC,MAAI,QAAQ,MAAM;AAChB,UAAM,oBAAoB,MAAM,SAAS,KAAK,MAAM,EAAE;AAAG,WAAO;AAChE,mBAAe,kBAAkB,MAAM,OAAK,MAAM,CAAC,IAC/C,OACA,IAAIF,YAAU,iBAAiB;AAAA,EACrC;AAGA,QAAM,gBAAgB;AAKtB,QAAM,iBAAiB,MAAM,gBAAgB,CAAC,MAAM;AACpD,QAAM,aAAa,MAAM,gBAAgB,EAAE,MAAM;AACjD,QAAM,cAAcG,WAAU,OAAO,gBAAgB,EAAE;AACvD,QAAM,oBAAoBD,WAAU,OAAO,gBAAgB,EAAE;AAC7D,QAAM,eAAeA,WAAU,OAAO,gBAAgB,EAAE;AAGxD,QAAM,iBAAiB,MAAM,gBAAgB,EAAE,MAAM;AACrD,QAAM,gBAAgBA,WAAU,OAAO,gBAAgB,EAAE;AACzD,QAAM,gBAAgBA,WAAU,OAAO,gBAAgB,EAAE;AACzD,QAAM,mBAAmBC,WAAU,OAAO,gBAAgB,EAAE;AAI5D,QAAM,uBAAuBD,WAAU,OAAO,gBAAgB,EAAE;AAChE,QAAM,yBAAyBA,WAAU,OAAO,gBAAgB,EAAE;AAGlE,QAAM,qBAAqBA,WAAU,OAAO,gBAAgB,EAAE;AAC9D,QAAM,mBAAmB,MAAM,gBAAgB,EAAE,MAAM;AAMvD,QAAM,4BAA4B,OAC9BA,WAAU,OAAO,gBAAgB,EAAE,IACnC;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,IAAM,qBAAqB;AAC3B,IAAM,8BAA8B,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,CAAI,CAAC;AAC1G,IAAM,gCAAgC;AAyB/B,SAAS,iBAAiB,MAAqC;AACpE,MAAI,KAAK,SAAS,oBAAoB;AACpC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,kBAAkB,EAAE;AAAA,EACvF;AACA,uBAAqB,gBAAgB,MAAM,+BAA+B,2BAA2B;AACrG,SAAO;AAAA,IACL,eAAe,KAAK,CAAC,MAAM;AAAA,IAC3B,MAAM,KAAK,CAAC;AAAA,IACZ,MAAM,IAAIF,YAAU,KAAK,SAAS,GAAG,EAAE,CAAC;AAAA,IACxC,MAAM,IAAIA,YAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IACzC,iBAAiBE,WAAU,MAAM,EAAE;AAAA,IACnC,UAAUA,WAAU,MAAM,EAAE;AAAA,EAC9B;AACF;AA4DO,SAAS,iBACd,GACA,iBAA4BE,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAO,UAAU,MAAM,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC/D,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQC,eAAc,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IACtE,EAAE,QAAQC,qBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,EACnE;AACF;AASO,SAAS,gBACd,GACA,iBAA4BF,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,MAAM,UAAU,MAAM,YAAY,MAAM;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,KAAK;AAAA,IACjE,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,IACzD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,YAAY,UAAU,OAAO,YAAY,KAAK;AAAA,IAC1D,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQG,sBAAqB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQF,eAAc,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,EACxE;AACF;AASO,SAAS,iBACd,GACA,iBAA4BD,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,MAAM,UAAU,MAAM,YAAY,MAAM;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,IACzD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,KAAK;AAAA,IACjE,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,YAAY,UAAU,OAAO,YAAY,KAAK;AAAA,IAC1D,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQG,sBAAqB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AASO,SAAS,yBACd,GACA,iBAA4BH,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,QAAQ,UAAU,MAAM,YAAY,MAAM;AAAA,IACtD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,cAAc,UAAU,OAAO,YAAY,KAAK;AAAA,IAC5D,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,EAC/D;AACF;;;AC38DA,IAAM,8BACJ;AAiFF,SAAS,cAAc,KAAa,SAAyB;AAC3D,MAAI,YAAY,GAAI,QAAO;AAC3B,SAAQ,MAAM,SAAW;AAC3B;AAsBO,SAAS,eAAe,UAA+B;AAC5D,QAAM,SAAS,iBAAiB,SAAS,QAAQ,QAAQ;AACzD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACF,UAAM,SAAS,YAAY,QAAQ;AACnC,QAAI,OAAO,cAAc,GAAI,QAAO;AACpC,UAAM,SAAS,YAAY,UAAU,MAAM;AAC3C,QAAI,OAAO,cAAc,GAAI,QAAO;AACpC,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAyBA,eAAsB,wBACpB,YACA,MAC2B;AAC3B,QAAM,OAAO,MAAM,UAAU,YAAY,IAAI;AAC7C,SAAO,iBAAiB,IAAI;AAC9B;AAMO,SAAS,iBAAiB,UAAwC;AACvE,QAAM,SAAS,iBAAiB,SAAS,QAAQ,QAAQ;AAEzD,MAAI,YAAY;AAChB,MAAI,eAA+B;AACnC,MAAI;AACF,UAAM,SAAS,YAAY,QAAQ;AACnC,gBAAY,OAAO;AAInB,UAAM,cACJ,WAAW,QAAQ,OAAO,mBAAmB,KAAK,OAAO,oBAAoB;AAC/E,QAAI,aAAa;AAEf,qBAAe,OAAO,UAAU,OAAO,SAAS,UAAU;AAAA,IAC5D;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN;AAAA,MACA,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AAEA,MAAI,YAAY;AAChB,MAAI,cAAc;AAClB,MAAI,QAAQ;AACV,QAAI;AACF,YAAM,SAAS,YAAY,UAAU,MAAM;AAC3C,kBAAY,OAAO;AACnB,oBAAc,YAAY,MAAM,YAAY;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,WAAW,iBAAiB,QAAQ;AAG1C,QAAM,YAAiC,CAAC;AACxC,aAAW,EAAE,KAAK,QAAQ,KAAK,UAAU;AACvC,QAAI,QAAQ,sBAA2B;AACvC,QAAI,QAAQ,iBAAiB,GAAI;AAEjC,UAAM,OAAgB,QAAQ,eAAe,KAAK,SAAS;AAI3D,UAAM,SAAS,cAAc,QAAQ,KAAK,QAAQ,OAAO;AAEzD,cAAU,KAAK;AAAA,MACb;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,cAAc,QAAQ;AAAA,MACtB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,MACA,SAAS;AAAA;AAAA,IACX,CAAC;AAAA,EACH;AAGA,QAAM,QAAQ,UACX,OAAO,OAAK,EAAE,SAAS,MAAM,EAC7B,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK,CAAE;AAC1E,QAAM,QAAQ,CAAC,GAAG,MAAM;AAAE,MAAE,UAAU;AAAA,EAAG,CAAC;AAK1C,QAAM,SAAS,UACZ,OAAO,OAAK,EAAE,SAAS,OAAO,EAC9B,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK,CAAE;AAC1E,SAAO,QAAQ,CAAC,GAAG,MAAM;AAAE,MAAE,UAAU;AAAA,EAAG,CAAC;AAG3C,QAAM,SAAS,CAAC,GAAG,OAAO,GAAG,MAAM,EAAE;AAAA,IACnC,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK;AAAA,EAClE;AAEA,SAAO,EAAE,QAAQ,OAAO,QAAQ,aAAa,WAAW,WAAW,aAAa;AAClF;AAkBO,SAAS,oBACd,SACA,OACA,SACA,YACA,WACA,iBAA8B,CAAC,GACP;AACxB,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,YAAY,GAAG;AACjD,UAAM,IAAI;AAAA,MACR,sEAAsE,SAAS;AAAA,IACjF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,2BAA2B;AAC7C;AAmBO,SAAS,gBACd,SACA,YAC+B;AAC/B,MAAI,eAAe,OAAQ,QAAO,QAAQ,MAAM,CAAC;AACjD,MAAI,eAAe,QAAS,QAAO,QAAQ,OAAO,CAAC;AACnD,MAAI,QAAQ,iBAAiB,OAAQ,QAAO,QAAQ,MAAM,CAAC;AAC3D,MAAI,QAAQ,iBAAiB,QAAS,QAAO,QAAQ,OAAO,CAAC;AAC7D,SAAO,QAAQ,OAAO,CAAC;AACzB;AAsCA,eAAsB,oBACpB,YACA,QACA,MACA,QACA,WACA,YACA,gBAA6B,CAAC,GACU;AACxC,QAAM,UAAU,MAAM,wBAAwB,YAAY,IAAI;AAE9D,MAAI,CAAC,QAAQ,YAAa,QAAO;AAEjC,QAAM,SAAS,gBAAgB,SAAS,UAAU;AAElD,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,oBAAoB,QAAQ,MAAM,QAAQ,WAAW,OAAO,KAAK,aAAa;AACvF;AA0CA,IAAM,gBAAgB;AAwBf,SAAS,cACd,MACA,qBACiB;AAGjB,MAAI,mBAAmB,wBAAwB;AAC/C,MAAI,WAAW;AAEf,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,SAAS,SAAU;AAE9B,QAAI,wBAAwB,QAAW;AAErC,UAAI,KAAK,WAAW,WAAW,mBAAmB,SAAS,GAAG;AAC5D,2BAAmB;AACnB,mBAAW;AACX;AAAA,MACF;AACA,UACE,KAAK,WAAW,WAAW,mBAAmB,UAAU,KACxD,KAAK,WAAW,WAAW,mBAAmB,SAAS,GACvD;AACA,2BAAmB;AACnB;AAAA,MACF;AAEA,UAAI,kBAAkB;AACpB,YAAI,sBAAsB,KAAK,IAAI,GAAG;AACpC;AACA;AAAA,QACF;AACA,YAAI,mCAAmC,KAAK,IAAI,GAAG;AACjD,qBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,oBAAoB,WAAW,EAAG;AAAA,IACzC;AAGA,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,IACF;AACA,QAAI,CAAC,MAAO;AAEZ,QAAI;AACJ,QAAI;AACF,YAAM,OAAO,MAAM,CAAC,CAAC;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AAEA,QAAI,QAAQ,cAAe;AAE3B,QAAI;AACF,YAAM,YAAY,OAAO,OAAO,MAAM,CAAC,CAAC,CAAC;AACzC,YAAM,QAAQ,OAAO,MAAM,CAAC,CAAC;AAC7B,YAAM,WAAW,OAAO,MAAM,CAAC,CAAC;AAChC,YAAM,WAAW,OAAO,MAAM,CAAC,CAAC;AAEhC,YAAM,YAAa,YAAY,MAAO;AACtC,aAAO,EAAE,KAAK,WAAW,OAAO,UAAU;AAAA,IAC5C,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAyEA,eAAsB,iBACpB,SACA,MACA,UAAwB,OACD;AACvB,QAAM,UAAU,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS;AAChE,QAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;AACtC,QAAM,MAAM,GAAG,IAAI,0BAA0B,mBAAmB,OAAO,CAAC;AAExE,QAAM,MAAM,MAAM,QAAQ,GAAG;AAC7B,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,OAAO;AACX,QAAI;AAAE,aAAO,MAAM,IAAI,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAe;AACtD,UAAM,IAAI;AAAA,MACR,0BAA0B,IAAI,MAAM,SAAS,GAAG,GAAG,OAAO,WAAM,IAAI,KAAK,EAAE;AAAA,IAC7E;AAAA,EACF;AAEA,QAAM,OAAgB,MAAM,IAAI,KAAK;AAGrC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,QAAM,MAAM;AACZ,MAAI,CAAC,MAAM,QAAQ,IAAI,QAAQ,GAAG;AAChC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,MAAI,OAAO,IAAI,cAAc,WAAW;AACtC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,MAAI,OAAO,IAAI,gBAAgB,WAAW;AACxC,UAAM,IAAI,MAAM,gDAAgD,IAAI,WAAW,EAAE;AAAA,EACnF;AACA,MAAI,OAAO,IAAI,gBAAgB,UAAU;AACvC,UAAM,IAAI,MAAM,gDAAgD,IAAI,WAAW,EAAE;AAAA,EACnF;AACA,MAAI,OAAO,IAAI,cAAc,UAAU;AACrC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,MAAI,OAAO,IAAI,cAAc,UAAU;AACrC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,aAAW,SAAS,IAAI,UAAU;AAChC,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,UAAM,IAAI;AACV,QAAI,OAAO,EAAE,QAAQ,YAAY,CAAC,OAAO,UAAU,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG;AACtE,YAAM,IAAI,MAAM,0CAA0C,EAAE,GAAG,EAAE;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AACT;;;AC5lBA,SAAS,SAAS,MAAkB,KAAqB;AACvD,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AAC9E,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,YAAY,MAAkB,KAAqB;AAC1D,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AACjF,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI;AAC9E;AAEA,SAAS,YAAY,MAAkB,KAAqB;AAC1D,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AACjF,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;AACjF;AAEA,SAAS,aAAa,MAAkB,KAAqB;AAC3D,MAAI,MAAM,KAAK,KAAK,OAAQ,OAAM,IAAI,MAAM,kCAAkC,GAAG,EAAE;AACnF,QAAMI,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,EAAE;AAC9D,QAAM,KAAKA,IAAG,aAAa,GAAG,IAAI;AAClC,QAAM,KAAKA,IAAG,aAAa,GAAG,IAAI;AAClC,SAAQ,MAAM,MAAO;AACvB;AAOO,IAAM,uBAAuB;AAE7B,IAAM,6BAA6B;AAEnC,IAAM,qBAAqB;AAE3B,IAAM,kCAAkC;AAGxC,IAAM,6BAA6B;AAEnC,IAAM,8BAA8B;AAEpC,IAAM,+BAA+B;AAErC,IAAM,yBAAyB;AAGtC,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,YAAY;AAGX,IAAM,uBAAuB;AAQ7B,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,0CAAA,WAAQ,KAAR;AACA,EAAAA,0CAAA,WAAQ,KAAR;AACA,EAAAA,0CAAA,aAAU,KAAV;AACA,EAAAA,0CAAA,cAAW,KAAX;AAJU,SAAAA;AAAA,GAAA;AAQL,SAAS,wBAAwB,QAAwB;AAC9D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,WAAW,MAAM;AAAA,EAC5B;AACF;AA+HO,SAAS,yBACd,QACA,KACS;AAET,MAAI,IAAI,SAAS,qBAAsB,QAAO;AAE9C,MAAI,OAAO,SAAS,KAAK,OAAO,UAAU,IAAI,uBAAwB,QAAO;AAE7E,MAAI,OAAO,WAAW,cAA2B,QAAO;AACxD,SAAO,IAAI,WAAW,OAAO;AAC/B;AAsCO,SAAS,uBACd,MACA,OAAmC,CAAC,GACV;AAC1B,QAAM,UAAU,uBAAuB;AACvC,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,2DAAsD,OAAO,eAAe,KAAK,MAAM;AAAA,IACzF;AAAA,EACF;AACA,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW;AACjB,QAAM,OAAO,SAAS,MAAM,WAAW,kBAAkB;AACzD,QAAM,oBAAoB,YAAY,MAAM,WAAW,0BAA0B;AACjF,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,WAAW,uBAAuB;AAAA,EACpC;AAIA,QAAM,YACJ,KAAK,cAAc,SAAY,KAAK,OAAO,KAAK,SAAS;AAC3D,MAAI,YAAY,IAAI;AAClB,UAAM,IAAI,MAAM,+DAA+D,SAAS,EAAE;AAAA,EAC5F;AACA,QAAM,UAAU,YAAY,oBAAoB,YAAY;AAE5D,QAAM,YAAY,WAAW;AAC7B,QAAM,qBAAqB,KAAK;AAAA,IAC9B;AAAA,IACA,KAAK,OAAO,KAAK,SAAS,aAAa,yBAAyB;AAAA,EAClE;AACA,QAAM,wBAAwB,KAAK,IAAI,gBAAgB,kBAAkB;AACzE,QAAM,yBAAyB,wBAAwB;AAEvD,QAAM,MAAkC,EAAE,MAAM,SAAS,uBAAuB;AAChF,QAAM,UAA8B,CAAC;AAErC,WAAS,aAAa,GAAG,aAAa,uBAAuB,cAAc;AACzE,UAAM,aACJ,YAAY,aAAa,4BAA4B;AACvD,eAAW,QAAQ,CAAC,QAAQ,OAAO,GAAY;AAC7C,YAAM,YACJ,cACC,SAAS,SAAS,8BAA8B;AACnD,UAAI,YAAY,yBAAyB,KAAK,OAAQ;AAEtD,YAAM,SAAS,aAAa,KAAK,SAAS,UAAU,IAAI;AACxD,YAAM,SAAS,SAAS,MAAM,YAAY,SAAS;AACnD,YAAM,aAAa,YAAY,MAAM,YAAY,cAAc;AAC/D,YAAM,SAAS,WAAW,iBAA6B,WAAW;AAElE,YAAM,SAA2B;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,YAAY,MAAM,YAAY,YAAY;AAAA,QACpD,yBAAyB,aAAa,MAAM,YAAY,iBAAiB;AAAA,QACzE,uBAAuB,aAAa,MAAM,YAAY,eAAe;AAAA,QACrE,0BAA0B,aAAa,MAAM,YAAY,kBAAkB;AAAA,QAC3E,0BAA0B,aAAa,MAAM,YAAY,kBAAkB;AAAA,QAC3E,wBAAwB,aAAa,MAAM,YAAY,kBAAkB;AAAA,QACzE;AAAA,QACA;AAAA,QACA,YAAY,wBAAwB,MAAM;AAAA,QAC1C;AAAA,QACA,WAAW;AAAA,MACb;AACA,aAAO,YAAY,yBAAyB,QAAQ,GAAG;AACvD,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAyBO,SAAS,4BACd,MACA,OAAmC,CAAC,GAC1B;AACV,SAAO,uBAAuB,MAAM,IAAI,EACrC,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,EACjC,IAAI,CAAC,MAAM,EAAE,MAAM;AACxB;;;AC7bA;AAAA,EACE,cAAAC;AAAA,OAGK;AA2NP,eAAsB,eACpB,UACA,YAAoB,KACM;AAK1B,QAAM,QAAQ,YAAY,IAAI;AAC9B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,UAAU;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ,CAAC,EAAE,YAAY,YAAY,CAAC;AAAA,MACtC,CAAC;AAAA,MACD,QAAQ,YAAY,QAAQ,SAAS;AAAA,IACvC,CAAC;AACD,UAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,KAAK;AACtD,QAAI,CAAC,IAAI,IAAI;AACX,aAAO,EAAE,UAAU,SAAS,OAAO,WAAW,MAAM,GAAG,OAAO,QAAQ,IAAI,MAAM,GAAG;AAAA,IACrF;AACA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAI,MAAM,SAAS,OAAO,MAAM,WAAW,UAAU;AACnD,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,MAAM;AAAA,QACN,OAAO,MAAM,OAAO,WAAW;AAAA,MACjC;AAAA,IACF;AACA,WAAO,EAAE,UAAU,SAAS,MAAM,WAAW,MAAM,KAAK,OAAO;AAAA,EACjE,SAAS,KAAK;AACZ,UAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,KAAK;AACtD,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,MAAM;AAAA,MACN,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD;AAAA,EACF;AACF;AAeA,SAAS,mBAAmB,KAAuD;AACjF,MAAI,QAAQ,MAAO,QAAO;AAC1B,QAAM,IAAI,OAAO,CAAC;AAClB,SAAO;AAAA,IACL,YAAY,EAAE,cAAc;AAAA,IAC5B,aAAa,EAAE,eAAe;AAAA,IAC9B,YAAY,EAAE,cAAc;AAAA,IAC5B,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7D,sBAAsB,EAAE,wBAAwB,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,EACrE;AACF;AAEA,SAAS,kBAAkB,IAAmD;AAC5E,MAAI,OAAO,OAAO,SAAU,QAAO,EAAE,KAAK,GAAG;AAC7C,SAAO;AACT;AAEA,SAAS,cAAc,IAA+B;AACpD,MAAI,GAAG,MAAO,QAAO,GAAG;AACxB,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,GAAG,EAAE;AAAA,EACzB,QAAQ;AACN,WAAO,GAAG,IAAI,MAAM,GAAG,EAAE;AAAA,EAC3B;AACF;AAEA,SAAS,YAAY,KAAc,OAA0B;AAC3D,MAAI,CAAC,IAAK,QAAO;AAKjB,QAAM,UAAW,KAA4B;AAC7C,MAAI,YAAY,gBAAgB,YAAY,eAAgB,QAAO;AACnE,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,IAAI,OAAO,aAAa,IAAI,WAAW;AACvD,QAAI,QAAQ,KAAK,GAAG,EAAG,QAAO;AAAA,EAChC;AAEA,QAAM,QAAQ,IAAI,YAAY;AAC9B,MACE,MAAM,SAAS,YAAY,KAC3B,MAAM,SAAS,mBAAmB,KAClC,MAAM,SAAS,aAAa,KAC5B,MAAM,SAAS,qBAAqB,KACpC,MAAM,SAAS,YAAY,KAC3B,MAAM,SAAS,cAAc,KAC7B,MAAM,SAAS,gBAAgB,KAC/B,MAAM,SAAS,SAAS,KACxB,MAAM,SAAS,SAAS;AAAA;AAAA;AAAA,EAIxB,MAAM,SAAS,cAAc,GAC7B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,aAAa,SAAiB,QAAqC;AAC1E,QAAM,MAAM,KAAK;AAAA,IACf,OAAO,cAAc,KAAK,IAAI,GAAG,OAAO;AAAA,IACxC,OAAO;AAAA,EACT;AACA,MAAI,OAAO,iBAAiB,EAAG,QAAO;AACtC,QAAM,OAAO,KAAK,MAAM,MAAM,CAAC;AAC/B,SAAO,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,EAAE;AAC3D;AAEA,SAAS,YAAe,IAAY,SAA8D;AAChG,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,GAAG,WAAW;AAC5C,YAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE;AAAA,EACzD,CAAC;AACD,SAAO,EAAE,SAAS,QAAQ,MAAM,aAAa,KAAM,EAAE;AACvD;AAGA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAMA,SAAS,UAAU,KAAqB;AACtC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,YAAY;AAClB,eAAW,KAAK,CAAC,GAAG,EAAE,aAAa,KAAK,CAAC,GAAG;AAC1C,UAAI,UAAU,KAAK,CAAC,GAAG;AACrB,UAAE,aAAa,IAAI,GAAG,KAAK;AAAA,MAC7B;AAAA,IACF;AACA,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAyDO,IAAM,UAAN,MAAM,SAAQ;AAAA,EACF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAGT,UAAkB;AAAA;AAAA,EAG1B,OAAwB,sBAAsB;AAAA;AAAA,EAG9C,OAAwB,cAAc;AAAA,EAEtC,YAAY,QAAuB;AACjC,QAAI,CAAC,OAAO,aAAa,OAAO,UAAU,WAAW,GAAG;AACtD,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,SAAK,WAAW,OAAO,YAAY;AACnC,SAAK,cAAc,mBAAmB,OAAO,KAAK;AAClD,SAAK,mBAAmB,OAAO,oBAAoB;AACnD,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,kBAAkB,OAAO,mBAAmB;AAEjD,UAAM,aAAa,OAAO,cAAc;AAExC,SAAK,YAAY,OAAO,UAAU,IAAI,SAAO;AAC3C,YAAM,KAAK,kBAAkB,GAAG;AAChC,YAAM,aAA+B;AAAA,QACnC;AAAA,QACA,GAAG,GAAG;AAAA,MACR;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,YAAY,IAAIA,YAAW,GAAG,KAAK,UAAU;AAAA,QAC7C,OAAO,cAAc,EAAE;AAAA,QACvB,QAAQ,KAAK,IAAI,GAAG,GAAG,UAAU,CAAC;AAAA,QAClC,UAAU;AAAA,QACV,SAAS;AAAA,QACT,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,MAAM,KAAQ,IAAwD;AACpE,UAAM,cAAc,KAAK,cAAc,KAAK,YAAY,aAAa,IAAI;AACzE,QAAI;AAGJ,UAAM,iBAAiB,oBAAI,IAAY;AAEvC,UAAM,qBAAqB,cAAc,KAAK,UAAU;AACxD,QAAI,kBAAkB;AAEtB,aAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,UAAI,EAAE,kBAAkB,mBAAoB;AAC5C,YAAM,QAAQ,KAAK,eAAe,cAAc;AAChD,UAAI,UAAU,IAAI;AAEhB;AAAA,MACF;AACA,YAAM,KAAK,KAAK,UAAU,KAAK;AAE/B,YAAM,UAAU,YAAe,KAAK,kBAAkB,+BAA+B,KAAK,gBAAgB,OAAO,GAAG,KAAK,GAAG;AAC5H,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,UAChC,GAAG,GAAG,UAAU;AAAA,UAChB,QAAQ;AAAA,QACV,CAAC;AAGD,WAAG,WAAW;AACd,WAAG,UAAU;AACb,WAAG,iBAAiB;AACpB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,oBAAY;AACZ,WAAG;AAEH,YAAI,GAAG,YAAY,SAAQ,qBAAqB;AAC9C,aAAG,UAAU;AACb,aAAG,iBAAiB,GAAG,kBAAkB,KAAK,IAAI;AAClD,cAAI,KAAK,SAAS;AAChB,oBAAQ;AAAA,cACN,sBAAsB,GAAG,KAAK,2BAA2B,GAAG,QAAQ;AAAA,YACtE;AAAA,UACF;AAAA,QACF;AAEA,cAAM,YAAY,KAAK,cACnB,YAAY,KAAK,KAAK,YAAY,oBAAoB,IACtD;AAEJ,YAAI,CAAC,WAAW;AAEd,cAAI,KAAK,aAAa,cAAc,KAAK,UAAU,SAAS,GAAG;AAC7D,2BAAe,IAAI,KAAK;AAExB;AACA,gBAAI,eAAe,QAAQ,KAAK,UAAU,OAAQ;AAClD;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAGA,YAAI,KAAK,SAAS;AAChB,kBAAQ;AAAA,YACN,gCAAgC,GAAG,KAAK,aAAa,UAAU,CAAC,IAAI,WAAW;AAAA,YAC/E,eAAe,QAAQ,IAAI,UAAU;AAAA,UACvC;AAAA,QACF;AAGA,YAAI,KAAK,aAAa,cAAc,KAAK,UAAU,SAAS,GAAG;AAC7D,yBAAe,IAAI,KAAK;AAAA,QAC1B;AAGA,YAAI,UAAU,cAAc,KAAK,KAAK,aAAa;AACjD,gBAAM,QAAQ,aAAa,SAAS,KAAK,WAAW;AACpD,gBAAM,MAAM,KAAK;AAAA,QACnB;AAAA,MACF,UAAE;AACA,gBAAQ,OAAO;AAAA,MACjB;AAAA,IACF;AAGA,SAAK,sBAAsB;AAE3B,UAAM,aAAa,IAAI,MAAM,kCAAkC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,gBAA4B;AAC1B,UAAM,MAAM,KAAK,eAAe;AAChC,QAAI,QAAQ,IAAI;AAEd,WAAK,sBAAsB;AAC3B,aAAO,KAAK,UAAU,CAAC,EAAE;AAAA,IAC3B;AACA,WAAO,KAAK,UAAU,GAAG,EAAE;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,YAAY,YAAoB,KAAmC;AACvE,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,KAAK,UAAU,IAAI,OAAO,OAAO;AAC/B,cAAM,SAAS,MAAM,eAAe,GAAG,OAAO,KAAK,SAAS;AAC5D,WAAG,gBAAgB,OAAO;AAC1B,WAAG,UAAU,OAAO;AACpB,YAAI,OAAO,SAAS;AAClB,aAAG,WAAW;AACd,aAAG,iBAAiB;AAAA,QACtB;AACA,eAAO,WAAW,UAAU,OAAO,QAAQ;AAC3C,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,UAAU,OAAO,QAAM,GAAG,OAAO,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAMG;AACD,WAAO,KAAK,UAAU,IAAI,SAAO;AAAA,MAC/B,OAAO,GAAG;AAAA,MACV,KAAK,UAAU,GAAG,OAAO,GAAG;AAAA,MAC5B,SAAS,GAAG;AAAA,MACZ,UAAU,GAAG;AAAA,MACb,eAAe,GAAG;AAAA,IACpB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,eAAe,SAA+B;AAGpD,QAAI,KAAK,kBAAkB,GAAG;AAC5B,YAAM,MAAM,KAAK,IAAI;AACrB,iBAAW,MAAM,KAAK,WAAW;AAC/B,YAAI,CAAC,GAAG,WAAW,GAAG,mBAAmB,UAAc,MAAM,GAAG,kBAAmB,KAAK,iBAAiB;AACvG,aAAG,UAAU;AACb,aAAG,WAAW;AACd,aAAG,iBAAiB;AACpB,cAAI,KAAK,SAAS;AAChB,oBAAQ,KAAK,sBAAsB,GAAG,KAAK,mBAAmB,KAAK,eAAe,oBAAoB;AAAA,UACxG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,UAClB,IAAI,CAAC,IAAI,OAAO,EAAE,IAAI,EAAE,EAAE,EAC1B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAE,SAAS,IAAI,CAAC,CAAE;AAEzD,QAAI,QAAQ,WAAW,GAAG;AAExB,YAAM,YAAY,KAAK,UACpB,IAAI,CAAC,GAAG,MAAM,CAAC,EACf,OAAO,OAAK,CAAE,SAAS,IAAI,CAAC,CAAE;AACjC,aAAO,UAAU,SAAS,IAAI,UAAU,CAAC,IAAI;AAAA,IAC/C;AAEA,QAAI,KAAK,aAAa,YAAY;AAEhC,aAAO,QAAQ,CAAC,EAAE;AAAA,IACpB;AAGA,UAAM,cAAc,QAAQ,OAAO,CAAC,KAAK,EAAE,GAAG,MAAM,MAAM,GAAG,QAAQ,CAAC;AACtE,SAAK,WAAW,KAAK,UAAU,KAAK;AAEpC,QAAI,aAAa;AACjB,eAAW,EAAE,IAAI,EAAE,KAAK,SAAS;AAC/B,oBAAc,GAAG;AACjB,UAAI,KAAK,UAAU,WAAY,QAAO;AAAA,IACxC;AAEA,WAAO,QAAQ,QAAQ,SAAS,CAAC,EAAE;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAA8B;AACpC,UAAM,eAAe,KAAK,UAAU,OAAO,QAAM,GAAG,OAAO,EAAE;AAC7D,QAAI,eAAe,SAAQ,aAAa;AACtC,UAAI,KAAK,SAAS;AAChB,gBAAQ,KAAK,iEAA4D;AAAA,MAC3E;AACA,iBAAW,MAAM,KAAK,WAAW;AAC/B,WAAG,UAAU;AACb,WAAG,WAAW;AACd,WAAG,iBAAiB;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;AA6BA,eAAsB,UACpB,IACA,QACY;AACZ,QAAM,WAAW,mBAAmB,MAAM,KAAK;AAAA,IAC7C,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,sBAAsB,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,EAC3C;AAEA,MAAI;AACJ,QAAM,cAAc,SAAS,aAAa;AAE1C,WAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,KAAK;AACZ,kBAAY;AAEZ,UAAI,CAAC,YAAY,KAAK,SAAS,oBAAoB,GAAG;AACpD,cAAM;AAAA,MACR;AAEA,UAAI,UAAU,cAAc,GAAG;AAC7B,cAAM,QAAQ,aAAa,SAAS,QAAQ;AAC5C,cAAM,MAAM,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,IAAI,MAAM,mCAAmC;AAClE;AAOO,IAAM,YAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACp0BA;AAAA,EAGE;AAAA,EACA;AAAA,EAKA;AAAA,OACK;AAOP,IAAM,oBAAoB;AAAA,EACxB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AACb;AAQA,SAAS,yBAAyB,YAAgC;AAWhE,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,aAAO,kBAAkB;AAAA,EAC7B;AACF;AAQA,SAAS,gBACP,UACA,UACS;AACT,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,kBAAkB,QAAQ,KAAK,yBAAyB,QAAQ;AACzE;AAWO,SAAS,QAAQ,QAA+C;AACrE,SAAO,IAAI,uBAAuB;AAAA,IAChC,WAAW,OAAO;AAAA,IAClB,MAAM,OAAO;AAAA;AAAA;AAAA,IAGb,MAAM,OAAO;AAAA,EACf,CAAC;AACH;AAkCA,IAAM,yBAAyB;AAMxB,IAAM,+BAA+B,MAAM;AAElD,IAAM,uBAAuB,KAAK;AAClC,IAAM,uBAAuB,MAAM;AAEnC,eAAsB,eACpB,QACmB;AACnB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,EACnB,IAAI;AAIJ,QAAM,sBAAsB,eAAe,WAAW,cAAc;AAEpE,MAAI,OAAO,aAAa,WAAW;AACjC,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AAEA,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,MAAI,qBAAqB,QAAW;AAClC,QACE,OAAO,qBAAqB,YAC5B,CAAC,OAAO,UAAU,gBAAgB,KAClC,mBAAmB,KACnB,mBAAmB,wBACnB;AACA,YAAM,IAAI;AAAA,QACR,8CAA8C,sBAAsB;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,mBAAmB,GAAG;AACxB,QACE,OAAO,mBAAmB,YAC1B,CAAC,OAAO,UAAU,cAAc,KAChC,iBAAiB,SAAS,KAC1B,iBAAiB,wBACjB,iBAAiB,sBACjB;AACA,YAAM,IAAI;AAAA,QACR,sDAAsD,oBAAoB,KAAK,oBAAoB;AAAA,MACrG;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,IAAI,YAAY;AAK3B,MAAI,mBAAmB,GAAG;AACxB,OAAG,IAAI,qBAAqB,iBAAiB,EAAE,OAAO,eAAe,CAAC,CAAC;AAAA,EACzE;AAGA,MAAI,qBAAqB,QAAW;AAClC,OAAG;AAAA,MACD,qBAAqB,oBAAoB;AAAA,QACvC,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,KAAG,IAAI,EAAE;AACT,QAAM,kBAAkB,MAAM,WAAW,mBAAmB,mBAAmB;AAC/E,KAAG,kBAAkB,gBAAgB;AACrC,KAAG,WAAW,QAAQ,CAAC,EAAE;AAEzB,MAAI,UAAU;AACZ,QAAI;AACF,SAAG,KAAK,GAAG,OAAO;AAClB,YAAM,SAAS,MAAM,WAAW,oBAAoB,IAAI,OAAO;AAC/D,YAAM,OAAO,OAAO,MAAM,QAAQ,CAAC;AACnC,UAAI,MAAqB;AACzB,UAAI;AAEJ,UAAI,OAAO,MAAM,KAAK;AACpB,cAAM,SAAS,mBAAmB,IAAI;AACtC,YAAI,QAAQ;AACV,gBAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,iBAAO,OAAO;AAAA,QAChB,OAAO;AACL,gBAAM,KAAK,UAAU,OAAO,MAAM,GAAG;AAAA,QACvC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM,OAAO,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,OAAO,MAAM,iBAAiB;AAAA,MAC/C;AAAA,IACF,SAAS,GAAY;AACnB,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM;AAAA,QACN,KAAK;AAAA,QACL,MAAM,CAAC;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAuB;AAAA,IAC3B,eAAe;AAAA,IACf,qBAAqB;AAAA,EACvB;AAIA,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,WAAW,gBAAgB,IAAI,SAAS,OAAO;AAAA,EACnE,SAAS,GAAY;AACnB,UAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,WAAO;AAAA,MACL,WAAW;AAAA,MACX,MAAM;AAAA,MACN,KAAK;AAAA,MACL,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AAKA,QAAM,aAAa,wBAAwB,cAAc,cAAc;AAEvE,MAAI;AACF,UAAM,eAAe,MAAM,WAAW;AAAA,MACpC;AAAA,QACE;AAAA,QACA,WAAW,gBAAgB;AAAA,QAC3B,sBAAsB,gBAAgB;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,WAAW,eAAe,WAAW;AAAA,MACxD,YAAY;AAAA,MACZ,gCAAgC;AAAA,IAClC,CAAC;AAED,UAAM,OAAO,QAAQ,MAAM,eAAe,CAAC;AAC3C,QAAI,MAAqB;AACzB,QAAI;AAEJ,QAAI,aAAa,MAAM,KAAK;AAC1B,YAAM,SAAS,mBAAmB,IAAI;AACtC,UAAI,QAAQ;AACV,cAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,eAAO,OAAO;AAAA,MAChB,OAAO;AACL,cAAM,KAAK,UAAU,aAAa,MAAM,GAAG;AAAA,MAC7C;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,QAAQ,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,GAAY;AAUnB,UAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC5D,0BAA0B;AAAA,MAC5B,CAAC;AAMD,UAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,oBAAoB,mBAAmB,GAAG;AACzF,cAAM,SAAS,MAAM,WAAW,eAAe,WAAW;AAAA,UACxD,YAAY;AAAA,UACZ,gCAAgC;AAAA,QAClC,CAAC;AACD,cAAM,OAAO,QAAQ,MAAM,eAAe,CAAC;AAC3C,YAAI,MAAqB;AACzB,YAAI;AACJ,YAAI,OAAO,MAAM,KAAK;AACpB,gBAAM,SAAS,mBAAmB,IAAI;AACtC,cAAI,QAAQ;AACV,kBAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,mBAAO,OAAO;AAAA,UAChB,OAAO;AACL,kBAAM,KAAK,UAAU,OAAO,MAAM,GAAG;AAAA,UACvC;AAAA,QACF;AACA,eAAO;AAAA,UACL;AAAA;AAAA;AAAA;AAAA,UAIA,MAAM,QAAQ,QAAQ,OAAO,MAAM;AAAA,UACnC;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,OAAO;AAGhB,cAAM,WAAW,OAAO,MAAM,sBAAsB;AACpD,eAAO;AAAA,UACL;AAAA,UACA,MAAM,OAAO,MAAM;AAAA,UACnB,KACE,gCAAgC,OAAO,iCAA4B,QAAQ,UACnE,mBAAmB,0EACR,SAAS;AAAA,UAC9B,MAAM,CAAC;AAAA,QACT;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAGR;AACA,WAAO;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN,KAAK,gCAAgC,OAAO,qEAAgE,SAAS;AAAA,MACrH,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,aAAa,QAAkB,UAA2B;AACxE,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,KAAK;AACd,UAAM,KAAK,UAAU,OAAO,GAAG,EAAE;AACjC,QAAI,OAAO,MAAM;AACf,YAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AAAA,IACnC;AACA,QAAI,OAAO,kBAAkB,QAAW;AACtC,YAAM,KAAK,kBAAkB,OAAO,cAAc,eAAe,CAAC,EAAE;AAAA,IACtE;AACA,QAAI,OAAO,KAAK,SAAS,GAAG;AAC1B,YAAM,KAAK,OAAO;AAClB,aAAO,KAAK,QAAQ,CAAC,QAAQ,MAAM,KAAK,KAAK,GAAG,EAAE,CAAC;AAAA,IACrD;AAAA,EACF,OAAO;AACL,UAAM,KAAK,cAAc,OAAO,SAAS,EAAE;AAC3C,UAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AACjC,QAAI,OAAO,kBAAkB,QAAW;AACtC,YAAM,KAAK,kBAAkB,OAAO,cAAc,eAAe,CAAC,EAAE;AAAA,IACtE;AACA,QAAI,OAAO,cAAc,eAAe;AACtC,YAAM,KAAK,4CAA4C,OAAO,SAAS,EAAE;AAAA,IAC3E;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC1XA,SAAS,aAAAC,aAAmC,eAAAC,oBAAmB;AAaxD,IAAM,wBAAwB,IAAID;AAAA,EACvC;AACF;AAGO,IAAM,4BAA4B;AAOlC,IAAM,gCAAgC;AAMtC,IAAM,yBAAyB,oBAAI,IAAI;AAAA,EAC5C;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF,CAAU;AAiBH,SAAS,wBAAwB,IAAqC;AAC3E,SAAO,GAAG,UAAU,OAAO,qBAAqB;AAClD;AA0BO,SAAS,kBAAkB,OAAyB;AACzD,QAAM,MAAM,oBAAoB,KAAK;AACrC,MAAI,CAAC,IAAK,QAAO;AAGjB,MAAI,IAAI,SAAS,yBAAyB,EAAG,QAAO;AAGpD,MAAI,wCAAwC,KAAK,GAAG,EAAG,QAAO;AAG9D,MAAI,wBAAwB,KAAK,GAAG,KAAK,oBAAoB,KAAK,GAAG,EAAG,QAAO;AAE/E,SAAO;AACT;AAYO,SAAS,0BAA0B,MAAyB;AACjE,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO;AAEjC,MAAI,kBAAkB;AAEtB,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,SAAS,SAAU;AAG9B,QAAI,KAAK,SAAS,WAAW,yBAAyB,SAAS,GAAG;AAChE;AACA;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,WAAW,yBAAyB,UAAU,GAAG;AACjE,UAAI,kBAAkB,EAAG;AACzB;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,WAAW,yBAAyB,SAAS,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAwBO,SAAS,4BACd,cACA,qBAC0B;AAI1B,MAAI,qBAAqB;AACvB,UAAM,kBAAkB,aAAa;AAAA,MACnC,CAAC,OAAO,GAAG,UAAU,OAAO,mBAAmB;AAAA,IACjD;AACA,QAAI,CAAC,iBAAiB;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,aAAa,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC;AACjE;AAuBO,SAAS,+BACd,aACA,qBACa;AAGb,MAAI,qBAAqB;AACvB,UAAM,kBAAkB,YAAY,aAAa;AAAA,MAC/C,CAAC,OAAO,GAAG,UAAU,OAAO,mBAAmB;AAAA,IACjD;AACA,QAAI,CAAC,gBAAiB,QAAO;AAAA,EAC/B;AAEA,QAAM,gBAAgB,YAAY,aAAa,KAAK,uBAAuB;AAC3E,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,QAAQ,IAAIC,aAAY;AAC9B,QAAM,kBAAkB,YAAY;AACpC,QAAM,WAAW,YAAY;AAE7B,aAAW,MAAM,YAAY,cAAc;AACzC,QAAI,CAAC,wBAAwB,EAAE,GAAG;AAChC,YAAM,IAAI,EAAE;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,4BACd,SACQ;AACR,QAAM,eAAe,MAAM,QAAQ,OAAO,IAAI,UAAU,QAAQ;AAChE,SAAO,aAAa,OAAO,uBAAuB,EAAE;AACtD;AAWO,IAAM,0BACX;AAgBK,SAAS,wBAAwB,OAA+B;AACrE,MAAI,kBAAkB,KAAK,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAMA,SAAS,oBAAoB,OAA+B;AAC1D,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,iBAAiB,MAAO,QAAO,MAAM;AACzC,MAAI,OAAO,UAAU,YAAY,aAAa,OAAO;AACnD,WAAO,OAAQ,MAA+B,OAAO;AAAA,EACvD;AACA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACrUO,SAAS,eACd,cACA,YACA,aACQ;AACR,MAAI,iBAAiB,MAAM,gBAAgB,GAAI,QAAO;AACtD,QAAM,SAAS,eAAe,KAAK,CAAC,eAAe;AACnD,QAAM,OACJ,eAAe,KACX,cAAc,aACd,aAAa;AACnB,SAAQ,OAAO,SAAU;AAC3B;AAMO,SAAS,gBACd,YACA,SACA,cACA,sBACQ;AACR,MAAI,iBAAiB,MAAM,eAAe,GAAI,QAAO;AACrD,QAAM,SAAS,eAAe,KAAK,CAAC,eAAe;AAEnD,QAAM,mBAAoB,UAAU,WAAc;AAElD,MAAI,eAAe,IAAI;AACrB,UAAM,WAAY,mBAAmB,UAAW,SAAS;AACzD,UAAM,MAAM,aAAa;AACzB,WAAO,MAAM,KAAK,MAAM;AAAA,EAC1B,OAAO;AAIL,QAAI,wBAAwB,OAAQ,QAAO;AAC3C,UAAM,WAAY,mBAAmB,UAAW,SAAS;AACzD,WAAO,aAAa;AAAA,EACtB;AACF;AAMO,SAAS,wBACd,UACA,QACA,SACA,UACA,QACA,WACQ;AACR,MAAI,aAAa,MAAM,WAAW,MAAM,YAAY,GAAI,QAAO;AAC/D,QAAM,SAAS,UAAU,KAAK,CAAC,UAAU;AACzC,QAAM,YAAY,cAAc,SAAS,SAAS,CAAC;AAInD,QAAM,YAAa,WAAW,SAAU;AACxC,MAAI;AACJ,MAAI,cAAc,QAAQ;AACxB,oBAAgB,WAAW;AAAA,EAC7B,OAAO;AAIL,UAAM,aAAa,WAAW;AAC9B,oBAAgB,aAAa,KAAK,aAAa;AAAA,EACjD;AACA,SAAO,gBAAgB,eAAe,QAAQ,WAAW,QAAQ;AACnE;AAKO,SAAS,kBACd,UACA,eACQ;AACR,SAAQ,WAAW,gBAAiB;AACtC;AA4BO,SAAS,qBACd,UACA,QACQ;AACR,MAAI,OAAO,mBAAmB,GAAI,QAAO,OAAO;AAChD,MAAI,OAAO,iBAAiB,MAAM,YAAY,OAAO,eAAgB,QAAO,OAAO;AACnF,MAAI,YAAY,OAAO,eAAgB,QAAO,OAAO;AACrD,SAAO,OAAO;AAChB;AAQO,SAAS,yBACd,UACA,QACQ;AACR,QAAM,SAAS,qBAAqB,UAAU,MAAM;AACpD,MAAI,YAAY,MAAM,UAAU,GAAI,QAAO;AAC3C,UAAQ,WAAW,SAAS,SAAS;AACvC;AAqBO,SAAS,gBACd,UACA,QAC0B;AAC1B,MAAI,OAAO,UAAU,MAAM,OAAO,gBAAgB,MAAM,OAAO,eAAe,IAAI;AAChF,WAAO,CAAC,UAAU,IAAI,EAAE;AAAA,EAC1B;AACA,QAAM,WAAW,OAAO,QAAQ,OAAO,cAAc,OAAO;AAC5D,MAAI,OAAO,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,aAAa,IAAI;AAC1E,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,MAAI,aAAa,QAAQ;AACvB,UAAM,IAAI,MAAM,sDAAsD,QAAQ,EAAE;AAAA,EAClF;AAEA,QAAM,KAAM,WAAW,OAAO,QAAS;AACvC,QAAM,WAAY,WAAW,OAAO,cAAe;AACnD,QAAM,UAAU,WAAW,KAAK;AAChC,SAAO,CAAC,IAAI,UAAU,OAAO;AAC/B;AAUO,SAAS,kBACd,WACA,SACQ;AACR,MAAI,YAAY,GAAI,QAAO;AAC3B,QAAM,YAAa,YAAY,SAAW;AAI1C,QAAM,cAAc,OAAO,OAAO,gBAAgB;AAClD,MAAI,YAAY,YAAa,QAAO,OAAO,mBAAmB;AAC9D,MAAI,YAAY,CAAC,YAAa,QAAO,EAAE,OAAO,mBAAmB;AACjE,SAAO,OAAO,SAAS,IAAI;AAC7B;AAKO,SAAS,2BACd,UACA,eACA,WACQ;AACR,MAAI,aAAa,GAAI,QAAO;AAC5B,QAAM,YAAa,WAAW,gBAAiB;AAC/C,MAAI,cAAc,OAAQ,QAAO,WAAW;AAI5C,QAAM,aAAa,WAAW;AAC9B,SAAO,aAAa,KAAK,aAAa;AACxC;AAEA,IAAM,kBAAkB,OAAO,OAAO,gBAAgB;AACtD,IAAM,kBAAkB,OAAO,CAAC,OAAO,gBAAgB;AAKhD,SAAS,6BACd,uBACQ;AAGR,MAAI,wBAAwB,gBAAiB,QAAO;AACpD,MAAI,wBAAwB,gBAAiB,QAAO;AACpD,QAAM,aAAa,OAAO,qBAAqB;AAC/C,QAAM,eAAe,MAAM,KAAK,KAAK,KAAK;AAC1C,SAAQ,aAAa,eAAgB;AACvC;AAKO,SAAS,sBACd,UACA,kBACQ;AACR,SAAQ,WAAW,mBAAoB;AACzC;AAWO,SAAS,mBAAmB,kBAAkC;AACnE,MAAI,oBAAoB,IAAI;AAC1B,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAIA,SAAO,MAAQ,OAAO,gBAAgB;AACxC;AAaO,SAAS,wBAAwB,kBAAkC;AACxE,MAAI,oBAAoB,IAAI;AAC1B,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AACA,SAAO,SAAS;AAClB;;;AC3QO,SAAS,6BACd,cACA,aACA,iBACA,mBACQ;AAER,MAAI,sBAAsB,MAAM,oBAAoB,GAAI,QAAO;AAC/D,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,UAAU,cAAc,kBAC1B,cAAc,kBACd;AAGJ,MAAI,WAAW,kBAAmB,QAAO;AAGzC,SAAQ,eAAe,UAAW;AACpC;AAoBO,SAAS,yBACd,kBACA,cACA,aACA,iBACA,mBACQ;AAIR,QAAM,SAAS,wBAAwB,gBAAgB;AAGvD,MAAI,sBAAsB,MAAM,oBAAoB,GAAI,QAAO,OAAO,MAAM;AAC5E,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY,GAAI,QAAO;AAG3B,QAAM,eAAe,OAAQ,SAAS,WAAY,YAAY;AAC9D,SAAO,KAAK,IAAI,GAAG,YAAY;AACjC;AAgBO,SAAS,6BACd,kBACA,cACA,aACA,iBACA,mBACQ;AACR,QAAM,SAAS,wBAAwB,gBAAgB;AACvD,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,WAAW;AACpB;;;ACxHA,SAAS,aAAAC,mBAAiB;AAG1B,IAAMC,WAAU;AAChB,IAAM,UAAU,OAAO,sBAAsB;AAC7C,IAAM,UAAU,OAAO,sBAAsB;AAC7C,IAAM,UAAU,OAAO,qBAAqB;AAC5C,IAAM,YAAY,MAAM,QAAQ;AAChC,IAAM,WAAW,EAAE,MAAM;AACzB,IAAM,YAAY,MAAM,QAAQ;AAEzB,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACkB,OAChB,SACA;AACA,UAAM,WAAW,KAAK,KAAK,OAAO,EAAE;AAHpB;AAIhB,SAAK,OAAO;AAAA,EACd;AACF;AAMA,IAAM,kBAAkB;AAMxB,IAAMC,kBAAiB;AAUhB,SAAS,yBAAyB,OAAe,OAAuB;AAC7E,QAAM,IAAI,MAAM,KAAK;AACrB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,IAAI,KAAK,yBAAyB;AAAA,EACrE;AACA,MAAI,CAAC,gBAAgB,KAAK,CAAC,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAoBO,SAAS,WAAW,KAAa,QAAwB;AAC9D,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,CAACA,gBAAe,KAAK,CAAC,GAAG;AAC3B,UAAM,IAAI;AAAA,MACR,GAAG,MAAM,MAAM,GAAG;AAAA,IAEpB;AAAA,EACF;AACA,SAAO,OAAO,CAAC;AACjB;AAKO,SAAS,kBAAkB,OAAe,OAA0B;AACzE,MAAI;AACF,WAAO,IAAIF,YAAU,KAAK;AAAA,EAC5B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IAEX;AAAA,EACF;AACF;AAKO,SAAS,cAAc,OAAe,OAAuB;AAClE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,OAAOC,QAAO,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAcA,QAAO,mBAAmB,CAAC;AAAA,IAC3C;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;AAKO,SAAS,eAAe,OAAe,OAAuB;AACnE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,MAAM,OAAO,CAAC;AAEpB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,6BAA6B,GAAG,EAAE;AAAA,EACrE;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aAAa,OAAe,OAAuB;AACjE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,MAAM,OAAO,CAAC;AAEpB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,6BAA6B,GAAG,EAAE;AAAA,EACrE;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,MAAI;AAEJ,MAAI;AACF,UAAM,WAAW,OAAO,KAAK;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aAAa,OAAe,OAAuB;AACjE,MAAI;AAEJ,MAAI;AACF,UAAM,WAAW,OAAO,KAAK;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,QAAQ;AACf,UAAM,IAAI;AAAA,MACR;AAAA,MACA,gCAAgC,CAAC;AAAA,IACnC;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,SAAO,eAAe,OAAO,KAAK;AACpC;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,OAAOA,QAAO,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAcA,QAAO,mBAAmB,CAAC;AAAA,IAC3C;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;;;AC1NA,IAAM,6BAA6B;AAEnC,SAAS,SAAS,GAA0C;AAC1D,SAAO,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAChE;AAEA,SAAS,oBAAoB,SAAqC;AAChE,QAAM,UAAU,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO;AAC7C,MAAI,SAAS;AACX,UAAM,IAAI,IAAI,gBAAgB;AAC9B,MAAE,MAAM,QAAQ,MAAM;AACtB,WAAO,EAAE;AAAA,EACX;AACA,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO;AAC/C,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,IAAI,gBAAgB;AAC9B,MAAE,MAAM;AACR,WAAO,EAAE;AAAA,EACX;AACA,MAAI,OAAO,WAAW,EAAG,QAAO,OAAO,CAAC;AACxC,QAAM,OAAO,IAAI,gBAAgB;AACjC,aAAW,KAAK,QAAQ;AACtB,MAAE,iBAAiB,SAAS,MAAM,KAAK,MAAM,EAAE,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,EACxE;AACA,SAAO,KAAK;AACd;AAEA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,YAAY,WAAW,SAAS,CAAC;AAEpE,SAAS,sBAAsB,MAA8B;AAC3D,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO,CAAC;AAC7B,QAAM,WAAW,KAAK;AACtB,MAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO,CAAC;AACtC,QAAM,UAAyB,CAAC;AAEhC,aAAW,QAAQ,UAAU;AAC3B,QAAI,CAAC,SAAS,IAAI,EAAG;AACrB,QAAI,KAAK,YAAY,SAAU;AAC/B,UAAM,QAAQ,OAAO,KAAK,SAAS,EAAE,EAAE,YAAY;AACnD,QAAI,CAAC,kBAAkB,IAAI,KAAK,EAAG;AAEnC,QAAI,YAAY;AAChB,QAAI,SAAS,KAAK,SAAS,KAAK,OAAO,KAAK,UAAU,QAAQ,UAAU;AACtE,kBAAY,KAAK,UAAU;AAAA,IAC7B;AACA,QAAI,YAAY,IAAK;AAErB,QAAI,aAAa;AACjB,QAAI,YAAY,IAAW,cAAa;AAAA,aAC/B,YAAY,IAAS,cAAa;AAAA,aAClC,YAAY,IAAQ,cAAa;AAAA,aACjC,YAAY,IAAO,cAAa;AAEzC,UAAM,WAAW,KAAK;AACtB,UAAM,QACJ,OAAO,aAAa,YAAY,OAAO,aAAa,WAChD,WAAW,OAAO,QAAQ,CAAC,KAAK,IAChC;AAMN,QAAI,EAAE,QAAQ,GAAI;AAElB,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI,SAAS,KAAK,SAAS,KAAK,OAAO,KAAK,UAAU,WAAW,UAAU;AACzE,gBAAU,KAAK,UAAU;AAAA,IAC3B;AACA,QAAI,SAAS,KAAK,UAAU,KAAK,OAAO,KAAK,WAAW,WAAW,UAAU;AAC3E,iBAAW,KAAK,WAAW;AAAA,IAC7B;AAEA,UAAM,OAAO,KAAK;AAClB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS,OAAO,SAAS,WAAW,OAAO;AAAA,MAC3C;AAAA,MACA,WAAW,GAAG,OAAO,MAAM,QAAQ;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAChD,SAAO,QAAQ,MAAM,GAAG,EAAE;AAC5B;AAeA,SAAS,sBACP,MACA,MACiE;AACjE,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAG5B,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI,SAAS,KAAK,KAAK,MAAM,aAAa,UAAa,MAAM,aAAa,MAAM;AAC9E,UAAME,SAAQ,WAAW,OAAO,MAAM,QAAQ,CAAC,KAAK;AACpD,QAAIA,UAAS,EAAG,QAAO;AACvB,UAAM,YACJ,OAAO,MAAM,cAAc,YAAY,OAAO,SAAS,MAAM,SAAS,IAClE,MAAM,YACN;AACN,WAAO,EAAE,OAAAA,QAAO,YAAY,KAAK,UAAU;AAAA,EAC7C;AAGA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,CAAC,SAAS,GAAG,EAAG,QAAO;AAC3B,QAAM,WAAW,IAAI;AACrB,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AACxD,QAAM,QAAQ,WAAW,OAAO,QAAQ,CAAC,KAAK;AAC9C,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,aAAa;AACjB,MAAI,OAAO,IAAI,eAAe,SAAU,cAAa,IAAI;AACzD,SAAO,EAAE,OAAO,YAAY,WAAW,EAAE;AAC3C;AAMO,IAAM,oBAAsE;AAAA;AAAA,EAEjF,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,WAAW,MAAM,+CAA+C;AAAA;AAAA,EAE9I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,UAAU,MAAM,8CAA8C;AAAA;AAAA,EAE5I,oEAAoE,EAAE,QAAQ,KAAK,MAAM,+CAA+C;AAAA;AAAA,EAExI,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,UAAU,MAAM,8CAA8C;AAAA;AAAA,EAE5I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAC3I;AACA,OAAO,OAAO,iBAAiB;AAG/B,IAAM,oBAAoB,oBAAI,IAAgD;AAC9E,WAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAC9D,oBAAkB,IAAI,KAAK,MAAM,EAAE,QAAQ,QAAQ,KAAK,OAAO,CAAC;AAClE;AAMA,IAAM,2BAA2B;AAEjC,SAAS,gBAAgB,QAAmC;AAC1D,SAAO,UAAU,YAAY,QAAQ,wBAAwB;AAC/D;AAEA,eAAe,gBAAgB,MAAc,QAA8C;AACzF,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB,iDAAiD,mBAAmB,IAAI,CAAC;AAAA,MACzE;AAAA,QACE,QAAQ,gBAAgB,MAAM;AAAA,QAC9B,SAAS,EAAE,cAAc,iBAAiB;AAAA,MAC5C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,GAAI,QAAO,CAAC;AACtB,UAAM,OAAgB,MAAM,KAAK,KAAK;AACtC,WAAO,sBAAsB,IAAI;AAAA,EACnC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAMA,SAAS,iBAAiB,MAAkC;AAC1D,QAAM,QAAQ,kBAAkB,IAAI,IAAI;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,MAAM;AAAA,IACf,WAAW,GAAG,MAAM,MAAM;AAAA,IAC1B,WAAW;AAAA;AAAA,IACX,OAAO;AAAA;AAAA,IACP,YAAY;AAAA;AAAA,EACd;AACF;AAMA,eAAe,mBAAmB,MAAc,QAAmD;AACjG,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB,mCAAmC,mBAAmB,IAAI,CAAC;AAAA,MAC3D;AAAA,QACE,QAAQ,gBAAgB,MAAM;AAAA,QAC9B,SAAS,EAAE,cAAc,iBAAiB;AAAA,MAC5C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,GAAI,QAAO;AACrB,UAAM,OAAgB,MAAM,KAAK,KAAK;AACtC,UAAM,MAAM,sBAAsB,MAAM,IAAI;AAC5C,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW,GAAG,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA,MAI5B,WAAW,IAAI;AAAA,MACf,OAAO,IAAI;AAAA,MACX,YAAY;AAAA;AAAA,IACd;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,aACpB,MACA,QACA,SAC4B;AAC5B,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,gBAAgB,YAAY,QAAQ,SAAS;AACnD,QAAM,iBAAiB,SACnB,oBAAoB,CAAC,QAAQ,aAAa,CAAC,IAC3C;AAEJ,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpD,gBAAgB,MAAM,cAAc;AAAA,IACpC,mBAAmB,MAAM,cAAc;AAAA,EACzC,CAAC;AAcD,QAAM,2BAA2B;AAKjC,QAAM,6BAA6B;AACnC,MAAI,iBAAiB,cAAc,QAAQ,GAAG;AAa5C,UAAM,oBAAoB,cAAc,YAAY;AACpD,UAAM,aAAa,KAAK,IAAI,GAAG,cAAc,aAAa,0BAA0B;AACpF,QAAI,mBAAmB;AAKrB,iBAAW,OAAO,YAAY;AAC5B,cAAM,cAAc,IAAI,QAAQ,cAAc,SAAS;AACvD,cAAM,mBAAmB,KAAK,IAAI,IAAI,QAAQ,cAAc,KAAK,IAAI;AACrE,YAAI,mBAAmB,0BAA0B;AAC/C,cAAI,aAAa,KAAK,IAAI,IAAI,YAAY,UAAU;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,iBAAiB,IAAI;AAExC,QAAM,aAA4B,CAAC;AAGnC,MAAI,YAAY;AAKd,UAAM,WAAW,WAAW,CAAC,GAAG,SAAS;AACzC,UAAM,WAAW,eAAe,SAAS;AAWzC,QAAI,gBAAgB;AACpB,QAAI,eAAe;AACnB,QAAI,WAAW,KAAK,WAAW,GAAG;AAChC,YAAM,OAAO,WAAW,YAAY;AACpC,YAAM,YAAY,KAAK,IAAI,WAAW,QAAQ,IAAI;AAClD,UAAI,aAAa,0BAA0B;AACzC,wBAAgB;AAAA,MAClB,OAAO;AAGL,gBAAQ;AAAA,UACN,uCAAuC,QAAQ,kBAAkB,QAAQ,iBAC1D,YAAY,KAAK,QAAQ,CAAC,CAAC,OAAO,2BAA2B,GAAG;AAAA,QAEjF;AAAA,MACF;AAAA,IACF,WAAW,WAAW,KAAK,WAAW,GAAG;AACvC,sBAAgB,WAAW,IAAI,WAAW;AAC1C,qBAAe;AAAA,IACjB;AACA,QAAI,gBAAgB,GAAG;AACrB,iBAAW,QAAQ;AACnB,UAAI,cAAc;AAChB,mBAAW,aAAa,KAAK,IAAI,WAAW,YAAY,EAAE;AAAA,MAC5D;AACA,iBAAW,KAAK,UAAU;AAAA,IAC5B;AAAA,EACF;AAGA,aAAW,KAAK,GAAG,UAAU;AAG7B,MAAI,eAAe;AACjB,eAAW,KAAK,aAAa;AAAA,EAC/B;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAErD,SAAO;AAAA,IACL;AAAA,IACA,YAAY,WAAW,CAAC,KAAK;AAAA,IAC7B;AAAA,IACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AACF;","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file +{"version":3,"sources":["../src/abi/encode.ts","../src/abi/instructions.ts","../src/abi/accounts.ts","../src/abi/errors.ts","../src/abi/nft.ts","../src/config/program-ids.ts","../src/solana/slab.ts","../src/solana/pda.ts","../src/solana/ata.ts","../src/solana/discovery.ts","../src/solana/static-markets.ts","../src/solana/dex-oracle.ts","../src/solana/oracle.ts","../src/solana/token-program.ts","../src/solana/stake.ts","../src/solana/adl.ts","../src/solana/backing-bucket.ts","../src/solana/rpc-pool.ts","../src/runtime/tx.ts","../src/runtime/lighthouse.ts","../src/math/trading.ts","../src/math/warmup.ts","../src/validation.ts","../src/oracle/price-router.ts"],"sourcesContent":["import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst U8_MAX = 0xFF;\r\nconst U16_MAX = 0xFFFF;\r\nconst U32_MAX = 0xFFFFFFFF;\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\nfunction parseDecimalBigInt(val: unknown, fnName: string): bigint {\r\n if (typeof val === \"bigint\") return val;\r\n if (typeof val !== \"string\") {\r\n throw new Error(`${fnName}: value must be bigint or decimal integer string`);\r\n }\r\n if (!DECIMAL_INT_RE.test(val)) {\r\n throw new Error(`${fnName}: value must be a decimal integer string`);\r\n }\r\n return BigInt(val);\r\n}\r\n\r\n/**\r\n * Encode u8 (1 byte)\r\n */\r\nexport function encU8(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U8_MAX) {\r\n throw new Error(`encU8: value out of range (0..255), got ${val}`);\r\n }\r\n return new Uint8Array([val]);\r\n}\r\n\r\n/**\r\n * Encode u16 little-endian (2 bytes)\r\n */\r\nexport function encU16(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U16_MAX) {\r\n throw new Error(`encU16: value out of range (0..65535), got ${val}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u32 little-endian (4 bytes)\r\n */\r\nexport function encU32(val: number): Uint8Array {\r\n if (!Number.isInteger(val) || val < 0 || val > U32_MAX) {\r\n throw new Error(`encU32: value out of range (0..4294967295), got ${val}`);\r\n }\r\n const buf = new Uint8Array(4);\r\n new DataView(buf.buffer).setUint32(0, val, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u64 little-endian (8 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU64\");\r\n if (n < 0n) throw new Error(\"encU64: value must be non-negative\");\r\n if (n > 0xffff_ffff_ffff_ffffn) throw new Error(\"encU64: value exceeds u64 max\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i64 little-endian (8 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI64(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI64\");\r\n const min = -(1n << 63n);\r\n const max = (1n << 63n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI64: value out of range\");\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigInt64(0, n, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode u128 little-endian (16 bytes)\r\n * Input: bigint or string (decimal)\r\n */\r\nexport function encU128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encU128\");\r\n if (n < 0n) throw new Error(\"encU128: value must be non-negative\");\r\n const max = (1n << 128n) - 1n;\r\n if (n > max) throw new Error(\"encU128: value exceeds u128 max\");\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = n & 0xffff_ffff_ffff_ffffn;\r\n const hi = n >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode i128 little-endian (16 bytes), two's complement\r\n * Input: bigint or string (decimal, may be negative)\r\n */\r\nexport function encI128(val: bigint | string): Uint8Array {\r\n const n = parseDecimalBigInt(val, \"encI128\");\r\n const min = -(1n << 127n);\r\n const max = (1n << 127n) - 1n;\r\n if (n < min || n > max) throw new Error(\"encI128: value out of range\");\r\n\r\n // Convert to unsigned representation (two's complement)\r\n let unsigned = n;\r\n if (n < 0n) {\r\n unsigned = (1n << 128n) + n;\r\n }\r\n\r\n const buf = new Uint8Array(16);\r\n const view = new DataView(buf.buffer);\r\n const lo = unsigned & 0xffff_ffff_ffff_ffffn;\r\n const hi = unsigned >> 64n;\r\n view.setBigUint64(0, lo, true);\r\n view.setBigUint64(8, hi, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Encode a Solana public key into its fixed-width 32-byte ABI representation.\r\n *\r\n * Accepts a `PublicKey` instance or a base58 string. Runtime PublicKey-like\r\n * objects are validated before their bytes are returned so JavaScript callers\r\n * cannot provide malformed `toBytes()` output.\r\n *\r\n * @throws Error when the value is not PublicKey-like, when `toBytes()` does not\r\n * return a `Uint8Array`, or when the output length is not exactly 32 bytes.\r\n */\r\nexport function encPubkey(val: PublicKey | string): Uint8Array {\r\n try {\r\n const pk = typeof val === \"string\" ? new PublicKey(val) : val;\r\n\r\n if (pk == null || typeof (pk as { toBytes?: unknown }).toBytes !== \"function\") {\r\n throw new Error(\"value must be a PublicKey or base58 string\");\r\n }\r\n\r\n const bytes = pk.toBytes();\r\n\r\n if (!(bytes instanceof Uint8Array)) {\r\n throw new Error(\"toBytes() must return a Uint8Array\");\r\n }\r\n\r\n if (bytes.length !== 32) {\r\n throw new Error(`expected 32 bytes, got ${bytes.length}`);\r\n }\r\n\r\n return bytes;\r\n } catch (e: unknown) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`encPubkey: invalid public key \"${String(val)}\" — ${msg}`);\r\n }\r\n}\r\n\r\n/**\r\n * Encode a boolean as u8 (0 = false, 1 = true)\r\n */\r\nexport function encBool(val: boolean): Uint8Array {\r\n return encU8(val ? 1 : 0);\r\n}\r\n\r\n/**\r\n * Concatenate multiple Uint8Arrays (replaces Buffer.concat)\r\n */\r\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\r\n const totalLen = arrays.reduce((sum, a) => sum + a.length, 0);\r\n const result = new Uint8Array(totalLen);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n encU8,\r\n encU16,\r\n encU32,\r\n encU64,\r\n encI64,\r\n encU128,\r\n encI128,\r\n encPubkey,\r\n concatBytes,\r\n} from \"./encode.js\";\r\n\r\n/**\r\n * Instruction tags — exact match to Rust ix::Instruction::decode arm in the\r\n * v17 converged wrapper (percolator-prog @v17-convergence, source\r\n * src/v16_program.rs). Tags are gappy; every absent tag rejects with\r\n * InvalidInstructionData.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Tags 37-73 are COMPLETELY different (toly renumbered 37-64, fork LP-vault\r\n * moved 65-71→74-80, fork NFT-B3 kept 72/73, toly claimed 65-69).\r\n * - Tag 32 UpdateAuthority: v17 has NO kind byte — just new_pubkey[32].\r\n * - Tag 57 is now WithdrawInsuranceAsset{asset_index:u16, amount:u128}.\r\n * - Tag 5 PermissionlessCrank: funding_rate_e9 arg MUST be hardcoded 0n by\r\n * all callers — the program hard-rejects nonzero.\r\n * - Domain fields: u8→u16 everywhere.\r\n */\r\nexport const IX_TAG = {\r\n // ── Core (tags 0-13) — byte-identical to v17 ─────────────────────────────\r\n InitMarket: 0,\r\n InitPortfolio: 1,\r\n /** @alias InitUser @since v12.x alias, canonical name is InitPortfolio in v17 */\r\n InitUser: 1,\r\n /** @deprecated v17 has no LP role in the wrapper; matchers run as third-party programs. */\r\n InitLP: 2,\r\n Deposit: 3,\r\n /** @alias DepositCollateral @since v12.x alias */\r\n DepositCollateral: 3,\r\n Withdraw: 4,\r\n /** @alias WithdrawCollateral @since v12.x alias */\r\n WithdrawCollateral: 4,\r\n /**\r\n * PermissionlessCrank (tag 5).\r\n *\r\n * CRITICAL: The on-chain decoder reads funding_rate_e9 (i128) at bytes [4..20]\r\n * and hard-rejects nonzero with InvalidInstructionData. SDK callers MUST use\r\n * encodePermissionlessCrank() which hardcodes fundingRateE9=0n. Do NOT\r\n * construct the payload manually and omit this field — that produces a\r\n * malformed instruction (missing bytes).\r\n */\r\n PermissionlessCrank: 5,\r\n /** @alias KeeperCrank @since v12.x alias */\r\n KeeperCrank: 5,\r\n TradeNoCpi: 6,\r\n LiquidateAtOracle: 7,\r\n ClosePortfolio: 8,\r\n /** @alias CloseAccount @since v12.x alias */\r\n CloseAccount: 8,\r\n TopUpInsurance: 9,\r\n TradeCpi: 10,\r\n /** @deprecated tag 11 has no decode arm in v17 wrapper */\r\n SetRiskThreshold: 11,\r\n /** @deprecated tag 12 has no decode arm in v17 wrapper */\r\n UpdateAdmin: 12,\r\n CloseSlab: 13,\r\n ResolveMarket: 19,\r\n // ── Backing/insurance domain ops (24, 28, 30, 41, 50, 52, 53, 54, 56, 57) ──\r\n TopUpBackingBucket: 24,\r\n ConvertReleasedPnl: 28,\r\n CloseResolved: 30,\r\n /**\r\n * UpdateAuthority (tag 32) — v17 wire: tag(1) + new_pubkey[32].\r\n *\r\n * BREAKING vs v12.18.x: NO kind byte in v17. The kind byte was removed;\r\n * tag 32 now ONLY rotates the single marketauth key. Per-asset authority\r\n * rotation uses tag 65 (UpdateAssetAuthority).\r\n */\r\n UpdateAuthority: 32,\r\n ConfigureHybridOracle: 34,\r\n ConfigureEwmaMark: 35,\r\n PushEwmaMark: 36,\r\n UpdateLiquidationFeePolicy: 37,\r\n ConfigurePermissionlessResolve: 38,\r\n ResolveStalePermissionless: 39,\r\n UpdateAssetLifecycle: 40,\r\n WithdrawInsurance: 41,\r\n CureAndCancelClose: 42,\r\n ForfeitRecoveryLeg: 43,\r\n RebalanceReduce: 44,\r\n FinalizeResetSide: 45,\r\n ClaimResolvedPayoutTopup: 46,\r\n RefineResolvedUnreceiptedBound: 47,\r\n SyncMaintenanceFee: 48,\r\n UpdateMaintenanceFeePolicy: 49,\r\n WithdrawBackingBucket: 50,\r\n UpdateBackingFeePolicy: 51,\r\n WithdrawBackingBucketEarnings: 52,\r\n SyncBackingDomainLedger: 53,\r\n SyncInsuranceLedger: 54,\r\n UpdateTradeFeePolicy: 55,\r\n TopUpInsuranceDomain: 56,\r\n /**\r\n * WithdrawInsuranceAsset (tag 57) — v17 wire: tag(1) + asset_index(u16) + amount(u128).\r\n *\r\n * Replaces the v12.x gap at tag 57. Withdraws from a specific asset's\r\n * insurance fund. asset_index is u16 (domain u8→u16 migration).\r\n */\r\n WithdrawInsuranceAsset: 57,\r\n UpdateFeeRedirectPolicy: 58,\r\n UpdateMarketInitFeePolicy: 59,\r\n UpdateBaseUnitMints: 60,\r\n SwapSecondaryForPrimary: 61,\r\n ConfigureAuthMark: 62,\r\n PushAuthMark: 63,\r\n ForceCloseAbandonedAsset: 64,\r\n // ── v17 auth-overhaul toly tags (65-69) — FREE range in v12.x ────────────\r\n /**\r\n * UpdateAssetAuthority (tag 65) — per-asset authority rotation.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * kind values (matches v16_program.rs ASSET_AUTH_* constants, lines 5246-5250):\r\n * 0 = ASSET_ADMIN — asset_admin (burnable when asset_index != 0)\r\n * 1 = INSURANCE — insurance_authority\r\n * 2 = INSURANCE_OPERATOR — insurance_operator\r\n * 3 = BACKING_BUCKET — backing_bucket_authority\r\n * 4 = ORACLE — oracle_authority\r\n *\r\n * NOTE: The stake program uses kind=0 (ASSET_AUTH_ADMIN) targeting asset_index=0.\r\n * See stake-program docs.\r\n */\r\n UpdateAssetAuthority: 65,\r\n /**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+exec_price(u64)+fee_bps(u64)]×n\r\n */\r\n BatchTradeNoCpi: 66,\r\n /**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI trade in one instruction.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16)+size_q(i128)+fee_bps(u64)+limit_price(u64)]×n\r\n */\r\n BatchTradeCpi: 67,\r\n /**\r\n * SetMatcherConfig (tag 68) — enable/disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n */\r\n SetMatcherConfig: 68,\r\n /**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart after stale/stuck state.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 19 bytes.\r\n */\r\n RestartAssetOracle: 69,\r\n // ── Fork NFT / B-3 (tags 72/73) — kept from v16 ─────────────────────────\r\n /**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n */\r\n TransferPortfolioOwnership: 72,\r\n /**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n */\r\n SetNftProgramId: 73,\r\n // ── Fork LP-vault (tags 74-80; moved from 65-71 to avoid toly collision) ──\r\n /**\r\n * CreateLpVault (tag 74).\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 15 bytes.\r\n */\r\n CreateLpVault: 74,\r\n /**\r\n * DepositToLpVault (tag 75).\r\n * Wire: tag(1) + amount(u128) = 17 bytes.\r\n */\r\n DepositToLpVault: 75,\r\n /**\r\n * RequestRedeemLpShares (tag 76).\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n */\r\n RequestRedeemLpShares: 76,\r\n /**\r\n * ExecuteRedemption (tag 77).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n ExecuteRedemption: 77,\r\n /**\r\n * LpVaultCrankFees (tag 78).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n LpVaultCrankFees: 78,\r\n /**\r\n * SetLpVaultPaused (tag 79).\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n */\r\n SetLpVaultPaused: 79,\r\n /**\r\n * CloseLpVault (tag 80).\r\n * Wire: tag(1) = 1 byte.\r\n */\r\n CloseLpVault: 80,\r\n // ── Legacy aliases retained for source-compat (do NOT assign new tags) ────\r\n /** @deprecated v12.x alias. Use DepositToLpVault(75) in v17. */\r\n LpVaultDeposit: 75,\r\n /** @deprecated v12.x alias. Use RequestRedeemLpShares(76) in v17 — NOTE: wire format changed. */\r\n LpVaultWithdraw: 76,\r\n // ── v12.x-only tags — NOT in v17 decoder. Encoders that use these throw removedInstruction(). ──\r\n /** @deprecated v12.x tag 14. Removed in v17. */\r\n UpdateConfig: 14,\r\n /** @deprecated v12.x tag 15. Removed in v17. */\r\n SetMaintenanceFee: 15,\r\n /** @deprecated v12.x tag 16. Removed in v17. */\r\n SetOraclePriceCap: 16,\r\n /** @deprecated v12.x tag 17. Removed in v17. */\r\n AdminForceClose: 17,\r\n /** @deprecated v12.x tag 18. Removed in v17. */\r\n UpdateRiskParams: 18,\r\n /** @deprecated v12.x tag 20. Removed in v17. */\r\n SetPythOracle: 20,\r\n /** @deprecated v12.x tag 21. Removed in v17. */\r\n RenounceAdmin: 21,\r\n /** @deprecated v12.x tag 22. Removed in v17. */\r\n SetInsuranceWithdrawPolicy: 22,\r\n /** @deprecated v12.x tag 23. Removed in v17 — v17 uses WithdrawInsuranceLimited=23 from toly. */\r\n WithdrawInsuranceLimited: 23,\r\n /** @deprecated v12.x tag 25. Removed in v17. */\r\n FundMarketInsurance: 25,\r\n /** @deprecated v12.x tag 26. Removed in v17. */\r\n SetInsuranceIsolation: 26,\r\n /** @deprecated v12.x tag 27. Removed in v17. */\r\n DepositFeeCredits: 27,\r\n /** @deprecated v12.x tag 29. Removed in v17 — v17 uses ResolveStalePermissionless=39. */\r\n ResolvePermissionless: 29,\r\n /** @deprecated v12.x tag 30. Removed in v17 — v17 reuses 30 for CloseResolved (different wire). */\r\n ForceCloseResolved: 30,\r\n /** @deprecated v12.x tag 33. Removed in v17. */\r\n UpdateInsurancePolicy: 33,\r\n /** @deprecated v12.x tag 36. Removed in v12.17. */\r\n UnresolveMarket: 36,\r\n /** @deprecated v12.x tag 43. Removed in v17 — v17 uses 43 for ChallengeSettlement (different wire). */\r\n ChallengeSettlement: 43,\r\n /** @deprecated v12.x tag 44. Removed in v17 — v17 uses 44 for RebalanceReduce (different wire). */\r\n ResolveDispute: 44,\r\n /** @deprecated v12.x tag 45. Removed in v17 — v17 uses 45 for FinalizeResetSide. */\r\n DepositLpCollateral: 45,\r\n /** @deprecated v12.x tag 46. Removed in v17 — v17 uses 46 for ClaimResolvedPayoutTopup. */\r\n WithdrawLpCollateral: 46,\r\n /** @deprecated v12.x tag 54. Removed in v17 — v17 uses 54 for SyncInsuranceLedger. */\r\n SetOffsetPair: 54,\r\n /** @deprecated v12.x tag 55. Removed in v17 — v17 uses 55 for UpdateTradeFeePolicy. */\r\n AttestCrossMargin: 55,\r\n /** @deprecated v12.x tag 56. Removed in v17 — v17 uses 56 for TopUpInsuranceDomain. */\r\n PauseMarket: 56,\r\n /** @deprecated v12.x tag 58. Removed in v17 — v17 uses 58 for UpdateFeeRedirectPolicy. */\r\n UnpauseMarket: 58,\r\n /** @deprecated v12.x tag 64. Removed in v17 — v17 uses 64 for ForceCloseAbandonedAsset. */\r\n MintPositionNft: 64,\r\n /** @deprecated v12.x tag 65. COLLIDES with v17 UpdateAssetAuthority(65). Do NOT use. */\r\n TransferPositionOwnership: 65,\r\n /** @deprecated v12.x tag 66. COLLIDES with v17 BatchTradeNoCpi(66). Do NOT use. */\r\n BurnPositionNft: 66,\r\n /** @deprecated v12.x tag 67. COLLIDES with v17 BatchTradeCpi(67). Do NOT use. */\r\n SetPendingSettlement: 67,\r\n /** @deprecated v12.x tag 68. COLLIDES with v17 SetMatcherConfig(68). Do NOT use. */\r\n ClearPendingSettlement: 68,\r\n /** @deprecated v12.x tag 69. COLLIDES with v17 RestartAssetOracle(69). Do NOT use. */\r\n TransferOwnershipCpi: 69,\r\n /** @deprecated v12.x tag 70. Not in v17. */\r\n SetWalletCap: 70,\r\n /** @deprecated v12.x tag 71. Not in v17. */\r\n SetOiImbalanceHardBlock: 71,\r\n /** @deprecated v12.x tag 72. COLLIDES with v17 TransferPortfolioOwnership(72). Do NOT use. */\r\n RescueOrphanVault: 72,\r\n /** @deprecated v12.x tag 73. COLLIDES with v17 SetNftProgramId(73). Do NOT use. */\r\n CloseOrphanSlab: 73,\r\n /** @deprecated v12.x tag 74. COLLIDES with v17 CreateLpVault(74). Do NOT use. */\r\n SetDexPool: 74,\r\n /** @deprecated v12.x tag 75. COLLIDES with v17 DepositToLpVault(75) AND v17 InitMatcherCtx(83). Do NOT use. */\r\n InitMatcherCtxV12: 75,\r\n /** @deprecated v12.x tag 78. COLLIDES with v17 LpVaultCrankFees(78). Do NOT use. */\r\n SetMaxPnlCap: 78,\r\n /** @deprecated v12.x tag 79. COLLIDES with v17 SetLpVaultPaused(79). Do NOT use. */\r\n SetOiCapMultiplier: 79,\r\n /** @deprecated v12.x tag 80. COLLIDES with v17 CloseLpVault(80). Do NOT use. */\r\n SetDisputeParams: 80,\r\n /** @deprecated v12.x tag 81. Not in v17. */\r\n SetLpCollateralParams: 81,\r\n /** @deprecated v12.x tag 82. Not in v17. */\r\n AcceptAdmin: 82,\r\n /**\r\n * InitMatcherCtx (tag 83) — bootstrap a matcher context by CPIing to the matcher program.\r\n *\r\n * v17 wire: tag(1) + kind(u8) + trading_fee_bps(u32) + base_spread_bps(u32) +\r\n * max_total_bps(u32) + impact_k_bps(u32) + liquidity_notional_e6(u128) +\r\n * max_fill_abs(u128) + max_inventory_abs(u128) + fee_to_insurance_bps(u16) +\r\n * skew_spread_mult_bps(u16) = 70 bytes total.\r\n *\r\n * The wrapper's handle_init_matcher_ctx signs the CPI as the matcher_delegate PDA\r\n * (via invoke_signed), satisfying the matcher program's lp_pda.is_signer check.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first to store\r\n * (matcherProg, matcherCtx, matcherDelegate) in the LP portfolio's matcher config tail.\r\n * InitMatcherCtx verifies the stored triple matches the accounts supplied here.\r\n *\r\n * CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n * ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n * wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx at tag 83 — this\r\n * is a real, live instruction, not a defunct/other-lineage one. The protocol-fee\r\n * change was renumbered (WithdrawProtocolFee→84, SetProtocolFeeAuthority→85) to\r\n * free tag 83 for this instruction rather than the reverse.\r\n */\r\n InitMatcherCtx: 83,\r\n /**\r\n * WithdrawProtocolFee (tag 84) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only).\r\n *\r\n * Renumbered 83→84 (2026-07-15) to free tag 83 for InitMatcherCtx, which the\r\n * deployed wrapper (percolator-prog@e26c97a4) has live at tag 83 — see the\r\n * note on IX_TAG.InitMatcherCtx above and ~/v17/DECISIONS-LEDGER.md.\r\n *\r\n * Wire: tag(1) + amount(u128) = 17 bytes. `amount == 0` withdraws all\r\n * currently-available capacity. Accounts: see ACCOUNTS_WITHDRAW_PROTOCOL_FEE\r\n * in abi/accounts.ts. Signer-gated on cfg.protocol_fee_authority.\r\n */\r\n WithdrawProtocolFee: 84,\r\n /**\r\n * SetProtocolFeeAuthority (tag 85) — v17 protocol-fee wrapper (VERSION 17,\r\n * percolator-prog@626fb617, feat/protocol-fee-taker-only). Rotates\r\n * cfg.protocol_fee_authority.\r\n *\r\n * Renumbered 84→85 (2026-07-15) as part of the same InitMatcherCtx(83) tag\r\n * reservation — see the note on IX_TAG.InitMatcherCtx above and\r\n * ~/v17/DECISIONS-LEDGER.md. Also frees this value from colliding with the\r\n * deprecated v12.x ReclaimEmptyAccount(85) below, which is not present in v17.\r\n *\r\n * Wire: tag(1) + new_authority(32) = 33 bytes. Accounts: see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. Gated on the\r\n * program's BPF upgrade authority — NOT marketauth, NOT any creator-facing gate.\r\n */\r\n SetProtocolFeeAuthority: 85,\r\n /**\r\n * UpdateFeeSplit (tag 86) — v17 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65). Sets the three stored fee shares.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes. Accounts: see ACCOUNTS_UPDATE_FEE_SPLIT\r\n * in abi/accounts.ts. Gated on `cfg.marketauth`.\r\n *\r\n * The three shares are bps *of T* (`trade_fee_base_bps`) and must sum to\r\n * exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS), else\r\n * Custom(52) FeeSplitSumInvalid. They must also satisfy the floors\r\n * (creator <= 3600, LP >= 3200, insurance >= 1200), else Custom(51)\r\n * FeeSplitFloorViolation.\r\n *\r\n * REACHABILITY: `StakeInitPool` irreversibly rotates `cfg.marketauth` to the\r\n * stake-pool PDA, after which this tag is reachable ONLY via the stake\r\n * program's CPI proxy (stake tag 25). Call it before StakeInitPool or use\r\n * `encodeStakeAdminUpdateFeeSplit`.\r\n */\r\n UpdateFeeSplit: 86,\r\n /**\r\n * WithdrawInsuranceReserveToStake (tag 87) — v17 fee-collection split.\r\n * Permissionless. Pushes the accrued insurance/staker leg out of the market\r\n * vault and into the bound stake pool's vault, where percolator-stake's\r\n * AccrueFees measures it as surplus and distributes it to stakers.\r\n *\r\n * Wire: tag(1) = 1 byte, no arguments. Accounts: see\r\n * ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE in abi/accounts.ts.\r\n *\r\n * The destination is NOT caller-chosen: it is `pool.vault`, read out of the\r\n * pool at `[\"stake_pool\", market]` under the wrapper's PINNED stake program\r\n * id. The only thing a caller decides is *when* the push happens.\r\n *\r\n * ⚠ Live-only (mode 0), and stricter than tag 84: rejects Recovery, Resolved\r\n * and matured-Live. ResolveMarket is one-way and tag 41 cannot reach this\r\n * unbudgeted leg, so any accrued-but-unpushed reserve is PERMANENTLY\r\n * FORFEITED once a market resolves. Keepers should crank tag 87 *before*\r\n * ResolveMarket, not after.\r\n */\r\n WithdrawInsuranceReserveToStake: 87,\r\n /**\r\n * UpdateMaintenanceFeePerSlot (tag 88) — v17 fee-collection split. Sets\r\n * `cfg.maintenance_fee_per_slot`, which was an InitMarket constructor\r\n * argument with no setter anywhere in the dispatch table and was therefore\r\n * frozen for the life of the market.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes. Accounts: see\r\n * ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT. Gated on `cfg.marketauth`.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes this with `read_u128`\r\n * (v16_program.rs tag-88 arm), matching both the storage type\r\n * (`WrapperConfigV16::maintenance_fee_per_slot: u128`) and InitMarket's own\r\n * wire encoding. A u64 payload leaves 8 bytes unconsumed and the wrapper\r\n * rejects the whole instruction with InvalidInstructionData.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86 — proxy is stake tag 26.\r\n */\r\n UpdateMaintenanceFeePerSlot: 88,\r\n /**\r\n * ExpireBackingBucket (tag 89) — PERMISSIONLESS backing-bucket liveness\r\n * repair. Advances a `Fresh`-but-LAPSED source-domain counterparty backing\r\n * bucket to `Expired`/`Impaired` so settlement against that domain can\r\n * proceed again.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) = 3 bytes. Accounts: see\r\n * ACCOUNTS_EXPIRE_BACKING_BUCKET — ONE account, the market, and NO signer.\r\n *\r\n * ⚠ ROUTINE KEEPER MAINTENANCE, NOT AN EDGE CASE. Every backed market\r\n * reaches the lapse eventually: the bucket's `expiry_slot` is fixed when the\r\n * bucket opens and is NEVER extended while it stays `Fresh`, so a longer\r\n * horizon defers the lapse, it does not avoid it. See\r\n * {@link encodeExpireBackingBucket} for the full keeper contract.\r\n */\r\n ExpireBackingBucket: 89,\r\n /**\r\n * WithdrawCreatorFee (tag 90) — v17 creator fee claim (percolator-prog\r\n * feat/protocol-fee-taker-only, 2026-07-23 creator-fee-claim design §3).\r\n * Pays the market creator's accrued trade-fee share out of the vault and\r\n * decrements `creator_fee_claimable_atoms` (WrapperConfigV17, byte 568) by\r\n * EXACTLY `amount`.\r\n *\r\n * Wire: tag(1) + amount(u128 LE) = 17 bytes. Accounts: see\r\n * ACCOUNTS_WITHDRAW_CREATOR_FEE in abi/accounts.ts (same 6-account shape as\r\n * tag 84).\r\n *\r\n * ⚠ `amount == 0` is REJECTED (InvalidInstruction), which is the OPPOSITE of\r\n * tag 84's \"0 means withdraw-all\" sentinel. This instruction is an exact\r\n * debit of the counter, so read `creatorFeeClaimableAtoms` off the parsed\r\n * config and pass that to drain it.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that — NOT\r\n * `cfg.marketauth`. On a staked market `StakeInitPool` has irreversibly\r\n * rotated `marketauth` to the stake-pool PDA but leaves `insurance_operator`\r\n * alone, so this deliberate divergence is what lets the creator still claim\r\n * after staking (and stops the pool PDA claiming creator revenue).\r\n *\r\n * ⚠ Over-claim (`amount > creatorFeeClaimableAtoms`) is rejected, never\r\n * saturated — there is no partial fill. Nothing is debited on failure.\r\n */\r\n WithdrawCreatorFee: 90,\r\n /**\r\n * RebalanceLpVaultBacking (v17 tag 91) — move IDLE (fresh, unliened) backing\r\n * between the two domains of the LP vault's asset, carrying ledger principal\r\n * in lockstep. No tokens move: `header.vault` is untouched.\r\n *\r\n * The vault is welded to ONE domain at CreateLpVault, but the house draws its\r\n * gains from the OPPOSITE domain, so without this the pot the house actually\r\n * needs can never be refilled (spec.md L410 requires refill be source-domain\r\n * local).\r\n */\r\n RebalanceLpVaultBacking: 91,\r\n /** @deprecated v12.x tag 85. COLLIDES with v17 SetProtocolFeeAuthority(85). Do NOT use. */\r\n ReclaimEmptyAccount: 85,\r\n /** @deprecated v12.x tag 86. Not in v17. */\r\n SettleAccount: 86,\r\n /** @deprecated v12.x tag 90. COLLIDES with v17 WithdrawCreatorFee(90). Do NOT use. */\r\n UpdateMarkPrice: 90,\r\n /** @deprecated v12.x tag 91. Not in v17. */\r\n AuditCrank: 91,\r\n /** @deprecated v12.x tag 92. Not in v17. */\r\n AdvanceOraclePhase: 92,\r\n /** @deprecated v12.x tag 93. Not in v17. */\r\n SlashCreationDeposit: 93,\r\n /** @deprecated v12.x tag 94. Not in v17. */\r\n InitSharedVault: 94,\r\n /** @deprecated v12.x tag 95. Not in v17. */\r\n AllocateMarket: 95,\r\n /** @deprecated v12.x tag 96. Not in v17. */\r\n QueueWithdrawalSV: 96,\r\n /** @deprecated v12.x tag 97. Not in v17. */\r\n ClaimEpochWithdrawal: 97,\r\n /** @deprecated v12.x tag 98. Not in v17. */\r\n AdvanceEpoch: 98,\r\n /** @deprecated v12.x tag 99. Not in v17. */\r\n ReclaimSlabRent: 99,\r\n /** @deprecated v12.x tag 100. Not in v17. */\r\n CloseStaleSlabs: 100,\r\n /** @deprecated v12.x tag 101. Not in v17. */\r\n ExecuteAdl: 101,\r\n /** @deprecated v12.x tag 102. Not in v17. */\r\n QueueWithdrawal: 102,\r\n /** @deprecated v12.x tag 103. Not in v17. */\r\n ClaimQueuedWithdrawal: 103,\r\n /** @deprecated v12.x tag 104. Not in v17. */\r\n CancelQueuedWithdrawal: 104,\r\n /** @deprecated v12.x tag 105. Not in v17. */\r\n TradeCpiV: 105,\r\n} as const;\r\nObject.freeze(IX_TAG);\r\n\r\n/**\r\n * v17 slab version discriminator. Stored as u16 LE at byte offset 8 of every\r\n * percolator-owned account (market-group, portfolio, insurance-ledger, etc.).\r\n *\r\n * The v17 MAGIC is 0x5045_5243_5631_3600n (\"PERCV16\\0\" as u64 LE). When\r\n * reading an account header, verify both MAGIC at [0..8] and VERSION at [8..10].\r\n */\r\nexport const EXPECTED_SLAB_VERSION = 16;\r\n\r\n/**\r\n * v17 account header magic — \"PERCV16\\0\" stored as little-endian u64.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_SLAB_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\nfunction removedInstruction(name: string, tag: number, replacement?: string): never {\r\n const suffix = replacement ? ` Use ${replacement} instead.` : \"\";\r\n throw new Error(\r\n `${name} (tag ${tag}) is not accepted by the deployed wrapper program.${suffix}`,\r\n );\r\n}\r\n\r\n/**\r\n * InitMarket instruction data — v17 wire format.\r\n *\r\n * v17 wire: tag(1) + market_params(218 bytes) = 219 bytes total.\r\n *\r\n * BREAKING vs v12.x: admin, collateralMint, feedId, staleness, conf, invert,\r\n * and unitScale are NO LONGER encoded in instruction data. In v17 these are\r\n * provided as account metas or configured separately via ConfigureHybridOracle /\r\n * ConfigureEwmaMark. The v17 decoder reads only the market risk parameters.\r\n *\r\n * The old v12.x encodeInitMarket with admin[32]+mint[32]+feedId[32]+... inline\r\n * is completely rejected by the v17 program — the first field read is now\r\n * max_portfolio_assets(u16), which would parse the first 2 bytes of admin as\r\n * a u16 portfolio count, producing invalid config or rejection at every call.\r\n *\r\n * Use `InitMarketArgs` (v12 legacy, now deprecated) or the new\r\n * `InitMarketV17Args` with encodeInitMarket(). The v12-era fields that are\r\n * absent from v17 (feedId, staleness, conf, invert, unitScale, maxMaintFee,\r\n * warmupPeriodSlots) are silently ignored when present in InitMarketV17Args.\r\n */\r\n/**\r\n * Optional 66-byte extended tail for InitMarket (S-4).\r\n *\r\n * When present and any field is non-zero the encoder appends a 66-byte block\r\n * in the exact order that the program reads it (percolator.rs:1516-1545):\r\n * insurance_withdraw_max_bps u16 (2 bytes)\r\n * insurance_withdraw_cooldown_slots u64 (8 bytes)\r\n * permissionless_resolve_stale_slots u64 (8 bytes)\r\n * funding_horizon_slots u64 (8 bytes)\r\n * funding_k_bps u64 (8 bytes)\r\n * funding_max_premium_bps i64 (8 bytes)\r\n * funding_max_bps_per_slot i64 (8 bytes)\r\n * mark_min_fee u64 (8 bytes)\r\n * force_close_delay_slots u64 (8 bytes)\r\n * total = 2 + 8*8 = 66 bytes\r\n *\r\n * When absent (or all fields are zero) the encoder omits the tail and the\r\n * program treats all extended fields as their default zero values. This\r\n * preserves full backward compatibility with existing 344-byte payloads.\r\n */\r\nexport interface InitMarketExtendedTail {\r\n /** Maximum percentage of insurance fund withdrawable per cooldown window (0–10 000 bps). */\r\n insuranceWithdrawMaxBps: number;\r\n /** Slots that must elapse between insurance withdrawals. Required when insuranceWithdrawMaxBps > 0. */\r\n insuranceWithdrawCooldownSlots: bigint | string;\r\n /** Slots after which an unresolved market may be permissionlessly resolved. */\r\n permissionlessResolveStaleSlots: bigint | string;\r\n /** Funding rate horizon in slots (custom_funding_k denominator). */\r\n fundingHorizonSlots: bigint | string;\r\n /** Funding rate K parameter in bps (0 = disabled). */\r\n fundingKBps: bigint | string;\r\n /** Maximum funding premium in bps (i64 — may be negative to flip direction). */\r\n fundingMaxPremiumBps: bigint | string;\r\n /** Maximum funding rate change per slot in bps (i64). */\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /** Minimum fee charged per mark-price update (u64, in collateral base units). */\r\n markMinFee: bigint | string;\r\n /** Slots to delay forced close after trigger condition is met (0 = immediate). */\r\n forceCloseDelaySlots: bigint | string;\r\n /**\r\n * Wave 9 (v2 tail): per-market `max_price_move_bps_per_slot` override.\r\n *\r\n * When omitted (or `undefined`), the encoder emits a 66-byte v1 tail and\r\n * the wrapper applies its deployment default\r\n * (`DEFAULT_MAX_PRICE_MOVE_BPS_PER_SLOT = 4`). When provided, the encoder\r\n * emits a 74-byte v2 tail with this value appended after\r\n * `forceCloseDelaySlots`. The wrapper rejects a zero v2 value with\r\n * `InvalidConfigParam`; the engine then re-validates the solvency\r\n * envelope at `init_in_place`.\r\n *\r\n * @since SDK 2.2.0 (Wave 9 InitMarket v2 wire-format)\r\n */\r\n maxPriceMoveBpsPerSlot?: bigint | string;\r\n}\r\n\r\nexport interface InitMarketArgs {\r\n admin: PublicKey | string;\r\n collateralMint: PublicKey | string;\r\n indexFeedId: string; // Pyth feed ID (hex string, 64 chars without 0x prefix). All zeros = Hyperp mode.\r\n maxStalenessSecs: bigint | string;\r\n confFilterBps: number;\r\n invert: number;\r\n unitScale: number;\r\n initialMarkPriceE6: bigint | string;\r\n // Fields between header and RiskParams (immutable after init, default 0 if omitted)\r\n maxMaintenanceFeePerSlot?: bigint | string; // u128 — max maintenance fee per slot\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n maxInsuranceFloor?: bigint | string;\r\n /** @deprecated v12.17-only field. v12.19 wrapper does not read it. Kept for source-compat, value ignored. */\r\n minOraclePriceCap?: bigint | string;\r\n // RiskParams block (16 fields, read by read_risk_params on-chain)\r\n /**\r\n * @deprecated Use hMin and hMax instead (v12.15+). Accepted as fallback for both hMin and hMax\r\n * when hMin/hMax are not provided.\r\n */\r\n warmupPeriodSlots?: bigint | string;\r\n /** Minimum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMin?: bigint | string;\r\n /** Maximum horizon slots (v12.15+). Falls back to warmupPeriodSlots if not provided. */\r\n hMax?: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n initialMarginBps: bigint | string;\r\n tradingFeeBps: bigint | string;\r\n maxAccounts: bigint | string;\r\n newAccountFee: bigint | string;\r\n insuranceFloor?: bigint | string; // u128 — wire slot: old riskReductionThreshold → insurance_floor\r\n maintenanceFeePerSlot: bigint | string;\r\n maxCrankStalenessSlots: bigint | string;\r\n liquidationFeeBps: bigint | string;\r\n liquidationFeeCap: bigint | string;\r\n liquidationBufferBps?: bigint | string; // u64 — wire compat: read and discarded by program\r\n minLiquidationAbs: bigint | string;\r\n /** @deprecated v12.17-only top-level field. v12.19 wrapper does not read a separate min_initial_deposit. Kept for source-compat, value ignored. */\r\n minInitialDeposit?: bigint | string;\r\n minNonzeroMmReq: bigint | string; // u128 — must be > 0, < minNonzeroImReq\r\n minNonzeroImReq: bigint | string; // u128 — must be > minNonzeroMmReq, <= minInitialDeposit\r\n /**\r\n * Optional 66-byte extended tail (S-4).\r\n * When present and any field is non-zero, appended after the 344-byte base payload.\r\n * When absent (or all zeros), the base 344-byte payload is sent and the program\r\n * uses default zero values for all extended fields.\r\n * @see InitMarketExtendedTail\r\n */\r\n extendedTail?: InitMarketExtendedTail;\r\n}\r\n\r\n/**\r\n * Encode a Pyth feed ID (hex string) to 32-byte Uint8Array.\r\n *\r\n * @deprecated feedId is no longer encoded in InitMarket instruction data in v17.\r\n * Oracle configuration is set separately via ConfigureHybridOracle (tag 34).\r\n * Retained as a utility for off-chain feed ID validation.\r\n */\r\nexport const HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function encodeFeedId(feedId: string): Uint8Array {\r\n const hex = feedId.startsWith(\"0x\") ? feedId.slice(2) : feedId;\r\n if (!HEX_RE.test(hex)) {\r\n throw new Error(\r\n `Invalid feed ID: expected 64 hex chars, got \"${hex.length === 64 ? \"non-hex characters\" : hex.length + \" chars\"}\"`,\r\n );\r\n }\r\n const bytes = new Uint8Array(32);\r\n for (let i = 0; i < 64; i += 2) {\r\n const byte = parseInt(hex.substring(i, i + 2), 16);\r\n if (Number.isNaN(byte)) {\r\n throw new Error(\r\n `Failed to parse hex byte at position ${i}: \"${hex.substring(i, i + 2)}\"`,\r\n );\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Default value for `publicBChunkAtoms` matching the engine's `MAX_VAULT_TVL`\r\n * (10_000_000_000_000_000 — effectively unlimited).\r\n *\r\n * WARNING: Using a small value (e.g. 1_000_000) stalls deep liquidations.\r\n * When a bankrupt position's liability exceeds `public_b_chunk_atoms`, the\r\n * engine returns `RecoveryRequired` and refuses further liquidation until\r\n * the insurance fund covers the residual. Production markets MUST use this\r\n * constant (or the engine's own `MAX_VAULT_TVL`) unless a deliberate chunk\r\n * limit is intended AND the insurance fund is sized accordingly.\r\n *\r\n * @example\r\n * ```ts\r\n * import { PUBLIC_B_CHUNK_ATOMS_UNLIMITED, encodeInitMarket } from \"@percolator/sdk\";\r\n * const data = encodeInitMarket({\r\n * ...otherParams,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED,\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport const PUBLIC_B_CHUNK_ATOMS_UNLIMITED = 10_000_000_000_000_000n;\r\n\r\n// v17 wire layout (v16_program.rs decode arm at tag 0):\r\n// tag(1) +\r\n// max_portfolio_assets(u16=2) +\r\n// h_min(u64=8) + h_max(u64=8) + initial_price(u64=8) +\r\n// min_nonzero_mm_req(u128=16) + min_nonzero_im_req(u128=16) +\r\n// maintenance_margin_bps(u64=8) + initial_margin_bps(u64=8) +\r\n// max_trading_fee_bps(u64=8) + trade_fee_base_bps(u64=8) +\r\n// liquidation_fee_bps(u64=8) +\r\n// liquidation_fee_cap(u128=16) + min_liquidation_abs(u128=16) +\r\n// max_price_move_bps_per_slot(u64=8) + max_accrual_dt_slots(u64=8) +\r\n// max_abs_funding_e9_per_slot(u64=8) + min_funding_lifetime_slots(u64=8) +\r\n// max_account_b_settlement_chunks(u64=8) + max_bankrupt_close_chunks(u64=8) +\r\n// max_bankrupt_close_lifetime_slots(u64=8) +\r\n// public_b_chunk_atoms(u128=16) + maintenance_fee_per_slot(u128=16)\r\n// Sizes: u16(2) + u64×15(120) + u128×6(96) = 218 bytes payload + 1 byte tag = 219 total\r\nconst INIT_MARKET_V17_LEN = 219;\r\n\r\n// Note: v12.x extended-tail constants and encodeExtendedTail helper have been\r\n// removed in v17. The v17 encodeInitMarket encodes a fixed 227-byte payload\r\n// with no optional tail — all parameters are required fields in the main body.\r\n\r\n/**\r\n * InitMarket v17 argument interface.\r\n *\r\n * admin and collateralMint are passed as account metas (accounts[0] and\r\n * accounts[2] respectively), NOT in instruction data.\r\n *\r\n * Oracle configuration (feedId, staleness, confFilter, invert, unitScale) is\r\n * set separately via ConfigureHybridOracle (tag 34) or ConfigureEwmaMark (tag 35)\r\n * after the market is created.\r\n *\r\n * Field order in wire format matches v16_program.rs InitMarket decoder exactly:\r\n * max_portfolio_assets, h_min, h_max, initial_price,\r\n * min_nonzero_mm_req, min_nonzero_im_req,\r\n * maintenance_margin_bps, initial_margin_bps,\r\n * max_trading_fee_bps, trade_fee_base_bps,\r\n * liquidation_fee_bps, liquidation_fee_cap, min_liquidation_abs,\r\n * max_price_move_bps_per_slot, max_accrual_dt_slots,\r\n * max_abs_funding_e9_per_slot, min_funding_lifetime_slots,\r\n * max_account_b_settlement_chunks, max_bankrupt_close_chunks,\r\n * max_bankrupt_close_lifetime_slots,\r\n * public_b_chunk_atoms, maintenance_fee_per_slot.\r\n */\r\nexport interface InitMarketV17Args {\r\n /** Max number of portfolios (u16). Must be > 0 and <= WRAPPER_MAX_PORTFOLIO_ASSETS. */\r\n maxPortfolioAssets: number;\r\n /** Minimum funding horizon in slots (u64). */\r\n hMin: bigint | string;\r\n /** Maximum funding horizon in slots (u64). */\r\n hMax: bigint | string;\r\n /** Initial mark price in e6 units (u64). Must be > 0 and <= MAX_ORACLE_PRICE. */\r\n initialPrice: bigint | string;\r\n /** Minimum non-zero maintenance margin requirement (u128). */\r\n minNonzeroMmReq: bigint | string;\r\n /** Minimum non-zero initial margin requirement (u128). */\r\n minNonzeroImReq: bigint | string;\r\n /** Maintenance margin ratio in bps (u64). */\r\n maintenanceMarginBps: bigint | string;\r\n /** Initial margin ratio in bps (u64). */\r\n initialMarginBps: bigint | string;\r\n /** Maximum trading fee in bps (u64). Must be >= trade_fee_base_bps. */\r\n maxTradingFeeBps: bigint | string;\r\n /** Base trade fee in bps (u64). Must be <= max_trading_fee_bps. */\r\n tradeFeeBaseBps: bigint | string;\r\n /** Liquidation fee in bps (u64). */\r\n liquidationFeeBps: bigint | string;\r\n /** Liquidation fee cap in absolute units (u128). */\r\n liquidationFeeCap: bigint | string;\r\n /** Minimum liquidation size in absolute units (u128). */\r\n minLiquidationAbs: bigint | string;\r\n /** Maximum price movement per slot in bps (u64). */\r\n maxPriceMoveBpsPerSlot: bigint | string;\r\n /** Maximum accrual delta-time in slots (u64). */\r\n maxAccrualDtSlots: bigint | string;\r\n /** Maximum absolute funding rate in e9 per slot (u64). */\r\n maxAbsFundingE9PerSlot: bigint | string;\r\n /** Minimum funding lifetime in slots (u64). */\r\n minFundingLifetimeSlots: bigint | string;\r\n /** Maximum account-B settlement chunks per crank (u64). */\r\n maxAccountBSettlementChunks: bigint | string;\r\n /** Maximum bankrupt-close chunks per crank (u64). */\r\n maxBankruptCloseChunks: bigint | string;\r\n /** Maximum bankrupt-close lifetime in slots (u64). */\r\n maxBankruptCloseLifetimeSlots: bigint | string;\r\n /**\r\n * Public-B chunk size in atoms (u128).\r\n *\r\n * WARNING: A small value (e.g. 1_000_000) can stall deep liquidations —\r\n * the engine returns `RecoveryRequired` when the bankrupt position's\r\n * liability exceeds this limit and insurance is insufficient to cover it.\r\n * Use `PUBLIC_B_CHUNK_ATOMS_UNLIMITED` (= engine's `MAX_VAULT_TVL` =\r\n * 10_000_000_000_000_000) unless you have a specific chunk-limit requirement\r\n * and a funded insurance pool.\r\n */\r\n publicBChunkAtoms: bigint | string;\r\n /** Maintenance fee per slot in absolute units (u128). Must be <= MAX_PROTOCOL_FEE_ABS. */\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\n/**\r\n * Encode InitMarket instruction data (v17 wire format).\r\n *\r\n * Produces a 219-byte payload: tag(1) + market parameter fields (218 bytes).\r\n * admin and collateralMint go into account metas (accounts[0] and accounts[2]).\r\n *\r\n * The old v12.x `InitMarketArgs` interface is accepted for source-compat via\r\n * overload but the v12 fields (admin, collateralMint, feedId, staleness, conf,\r\n * invert, unitScale, maxMaintenanceFeePerSlot, extendedTail, warmupPeriodSlots,\r\n * newAccountFee, insuranceFloor, maxCrankStalenessSlots, liquidationBufferBps,\r\n * minInitialDeposit) are silently ignored — provide `InitMarketV17Args` instead.\r\n *\r\n * @param args v17 market parameters (InitMarketV17Args)\r\n * @returns 227-byte Uint8Array\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMarket({\r\n * maxPortfolioAssets: 256,\r\n * hMin: 1000n,\r\n * hMax: 100000n,\r\n * initialPrice: 50_000_000_000n,\r\n * minNonzeroMmReq: 1_000_000n,\r\n * minNonzeroImReq: 2_000_000n,\r\n * maintenanceMarginBps: 500n,\r\n * initialMarginBps: 1000n,\r\n * maxTradingFeeBps: 100n,\r\n * tradeFeeBaseBps: 30n,\r\n * liquidationFeeBps: 100n,\r\n * liquidationFeeCap: 10_000_000n,\r\n * minLiquidationAbs: 1_000_000n,\r\n * maxPriceMoveBpsPerSlot: 4n,\r\n * maxAccrualDtSlots: 600n,\r\n * maxAbsFundingE9PerSlot: 1000n,\r\n * minFundingLifetimeSlots: 50n,\r\n * maxAccountBSettlementChunks: 10n,\r\n * maxBankruptCloseChunks: 10n,\r\n * maxBankruptCloseLifetimeSlots: 500n,\r\n * publicBChunkAtoms: PUBLIC_B_CHUNK_ATOMS_UNLIMITED, // use engine's MAX_VAULT_TVL; small values stall deep liquidations\r\n * maintenanceFeePerSlot: 0n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeInitMarket(args: InitMarketV17Args | InitMarketArgs): Uint8Array {\r\n // Detect v17 args by presence of maxPortfolioAssets (v17) vs admin (v12)\r\n const isV17Args = 'maxPortfolioAssets' in args;\r\n\r\n let maxPortfolioAssets: number;\r\n let hMin: bigint | string;\r\n let hMax: bigint | string;\r\n let initialPrice: bigint | string;\r\n let minNonzeroMmReq: bigint | string;\r\n let minNonzeroImReq: bigint | string;\r\n let maintenanceMarginBps: bigint | string;\r\n let initialMarginBps: bigint | string;\r\n let maxTradingFeeBps: bigint | string;\r\n let tradeFeeBaseBps: bigint | string;\r\n let liquidationFeeBps: bigint | string;\r\n let liquidationFeeCap: bigint | string;\r\n let minLiquidationAbs: bigint | string;\r\n let maxPriceMoveBpsPerSlot: bigint | string;\r\n let maxAccrualDtSlots: bigint | string;\r\n let maxAbsFundingE9PerSlot: bigint | string;\r\n let minFundingLifetimeSlots: bigint | string;\r\n let maxAccountBSettlementChunks: bigint | string;\r\n let maxBankruptCloseChunks: bigint | string;\r\n let maxBankruptCloseLifetimeSlots: bigint | string;\r\n let publicBChunkAtoms: bigint | string;\r\n let maintenanceFeePerSlot: bigint | string;\r\n\r\n if (isV17Args) {\r\n const v = args as InitMarketV17Args;\r\n maxPortfolioAssets = v.maxPortfolioAssets;\r\n hMin = v.hMin;\r\n hMax = v.hMax;\r\n initialPrice = v.initialPrice;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n maxTradingFeeBps = v.maxTradingFeeBps;\r\n tradeFeeBaseBps = v.tradeFeeBaseBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n maxPriceMoveBpsPerSlot = v.maxPriceMoveBpsPerSlot;\r\n maxAccrualDtSlots = v.maxAccrualDtSlots;\r\n maxAbsFundingE9PerSlot = v.maxAbsFundingE9PerSlot;\r\n minFundingLifetimeSlots = v.minFundingLifetimeSlots;\r\n maxAccountBSettlementChunks = v.maxAccountBSettlementChunks;\r\n maxBankruptCloseChunks = v.maxBankruptCloseChunks;\r\n maxBankruptCloseLifetimeSlots = v.maxBankruptCloseLifetimeSlots;\r\n publicBChunkAtoms = v.publicBChunkAtoms;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n } else {\r\n // v12.x InitMarketArgs compat shim — map old fields to v17 layout.\r\n // Fields removed in v17 (admin, collateralMint, feedId, staleness, conf,\r\n // invert, unitScale, extendedTail) are silently ignored.\r\n const v = args as InitMarketArgs;\r\n const resolvedHMin = v.hMin ?? v.warmupPeriodSlots ?? 0n;\r\n const resolvedHMax = v.hMax ?? v.warmupPeriodSlots ?? 0n;\r\n maxPortfolioAssets = typeof v.maxAccounts === 'string' ? parseInt(v.maxAccounts, 10) : Number(v.maxAccounts);\r\n hMin = resolvedHMin;\r\n hMax = resolvedHMax;\r\n initialPrice = v.initialMarkPriceE6;\r\n minNonzeroMmReq = v.minNonzeroMmReq;\r\n minNonzeroImReq = v.minNonzeroImReq;\r\n maintenanceMarginBps = v.maintenanceMarginBps;\r\n initialMarginBps = v.initialMarginBps;\r\n // v12 tradingFeeBps maps to max_trading_fee_bps and trade_fee_base_bps\r\n maxTradingFeeBps = v.tradingFeeBps;\r\n tradeFeeBaseBps = v.tradingFeeBps;\r\n liquidationFeeBps = v.liquidationFeeBps;\r\n liquidationFeeCap = v.liquidationFeeCap;\r\n minLiquidationAbs = v.minLiquidationAbs;\r\n // v12 ExtendedTail fields mapped to v17 equivalents (default safe values)\r\n maxPriceMoveBpsPerSlot = v.extendedTail?.maxPriceMoveBpsPerSlot ?? 4n;\r\n maxAccrualDtSlots = v.maxCrankStalenessSlots ?? 0n;\r\n maxAbsFundingE9PerSlot = v.extendedTail?.fundingMaxBpsPerSlot ?? 1000n;\r\n minFundingLifetimeSlots = 0n;\r\n // #310: the v12 InitMarketArgs interface has no equivalent for the four fields below,\r\n // which control the permissionless B-settlement path — the ONLY mechanism for closing\r\n // bankrupt accounts and releasing insurance. Defaulting them to 0 (the old behavior)\r\n // PERMANENTLY DISABLED bankruptcy recovery for any market created via the shim. Default\r\n // them to functional values instead so v12-initialized markets stay recoverable; callers\r\n // wanting explicit control should migrate to InitMarketV17Args.\r\n maxAccountBSettlementChunks = 10n;\r\n maxBankruptCloseChunks = 10n;\r\n maxBankruptCloseLifetimeSlots = 500n;\r\n publicBChunkAtoms = 1_000_000n;\r\n maintenanceFeePerSlot = v.maintenanceFeePerSlot;\r\n }\r\n\r\n const data = concatBytes(\r\n encU8(IX_TAG.InitMarket),\r\n encU16(maxPortfolioAssets),\r\n encU64(hMin),\r\n encU64(hMax),\r\n encU64(initialPrice),\r\n encU128(minNonzeroMmReq),\r\n encU128(minNonzeroImReq),\r\n encU64(maintenanceMarginBps),\r\n encU64(initialMarginBps),\r\n encU64(maxTradingFeeBps),\r\n encU64(tradeFeeBaseBps),\r\n encU64(liquidationFeeBps),\r\n encU128(liquidationFeeCap),\r\n encU128(minLiquidationAbs),\r\n encU64(maxPriceMoveBpsPerSlot),\r\n encU64(maxAccrualDtSlots),\r\n encU64(maxAbsFundingE9PerSlot),\r\n encU64(minFundingLifetimeSlots),\r\n encU64(maxAccountBSettlementChunks),\r\n encU64(maxBankruptCloseChunks),\r\n encU64(maxBankruptCloseLifetimeSlots),\r\n encU128(publicBChunkAtoms),\r\n encU128(maintenanceFeePerSlot),\r\n );\r\n\r\n if (data.length !== INIT_MARKET_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMarket: expected ${INIT_MARKET_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n return data;\r\n}\r\n\r\n/**\r\n * InitPortfolio / InitUser instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: the feePayment(u64) arg was removed. The program\r\n * decoder at `1 => Self::InitPortfolio` reads no bytes after the tag byte.\r\n * Sending extra bytes causes garbage reads in downstream decoder arms.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitUser();\r\n * ```\r\n */\r\nexport interface InitUserArgs {\r\n /** @deprecated feePayment is ignored in v17 — kept for source compatibility only. */\r\n feePayment?: bigint | string;\r\n}\r\n\r\nexport function encodeInitUser(_args?: InitUserArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.InitPortfolio]);\r\n}\r\n\r\n/**\r\n * InitLP (tag 2) — REMOVED in v17.\r\n *\r\n * Tag 2 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use the LP Vault flow (CreateLpVault tag 74) instead.\r\n */\r\nexport interface InitLPArgs {\r\n matcherProgram: PublicKey | string;\r\n matcherContext: PublicKey | string;\r\n feePayment: bigint | string;\r\n}\r\n\r\nexport function encodeInitLP(_args: InitLPArgs): Uint8Array {\r\n return removedInstruction(\"InitLP\", IX_TAG.InitLP, \"CreateLpVault (tag 74)\");\r\n}\r\n\r\n/**\r\n * DepositCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * Sending the old 11-byte payload (userIdx+u64) gives a 10-byte rest which\r\n * is 6 bytes short for read_u128 — InvalidInstructionData on every call.\r\n *\r\n * @param amount Collateral to deposit (u128; supports sub-cent precision).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositCollateral({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface DepositCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositCollateral(args: DepositCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawCollateral instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder reads `amount: read_u128(&mut rest)?` at bytes [1..17].\r\n * The old 11-byte payload gives a 10-byte rest — InvalidInstructionData.\r\n *\r\n * @param amount Collateral to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawCollateral({ amount: 500_000n });\r\n * ```\r\n */\r\nexport interface WithdrawCollateralArgs {\r\n /** @deprecated userIdx is no longer needed — portfolios are identified by account key in v17. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCollateral(args: WithdrawCollateralArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCollateral),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) action byte values.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank handler.\r\n * 0 = FeeSweep — accrue fees + dust sweep (no liquidation)\r\n * 1 = Liquidate — liquidate the portfolio identified by asset_index\r\n */\r\nexport const CrankAction = {\r\n FeeSweep: 0,\r\n Liquidate: 1,\r\n} as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5) instruction args.\r\n *\r\n * FIX W3 (upstream wrapper #206, pairs with engine E3 / upstream #92):\r\n * BREAKING wire change. `close_q`/`fee_bps` are NO LONGER caller-supplied —\r\n * liquidation size is engine-selected (`liquidation_engine_close_request_q`)\r\n * and the fee rate is always read from config inside\r\n * `liquidate_account_not_atomic`. This closes the \"min-fee chunking\" exploit\r\n * where a keeper could pick a tiny close_q to under-pay the liquidation fee\r\n * while still making forward progress. Any client still encoding the old\r\n * 53-byte layout (with close_q/fee_bps) will be rejected by the v17 program\r\n * as a decode error — this is a compile-time-shaped guarantee on the Rust\r\n * side, not a runtime check.\r\n *\r\n * v17 wire: tag(1) + action(u8) + asset_index(u16) + now_slot(u64) +\r\n * funding_rate_e9(i128 HARDCODED=0) + recovery_reason(u8) = 29 bytes.\r\n *\r\n * Source: v16_program.rs Instruction::PermissionlessCrank decode/encode\r\n * (tag 5), verified byte-for-byte against the Rust `read_u8`/`read_u16`/\r\n * `read_u64`/`read_i128`/`push_*` call sequence.\r\n *\r\n * CRITICAL: funding_rate_e9 is always hardcoded to 0n by this encoder.\r\n * The program hard-rejects any nonzero value with InvalidInstructionData.\r\n * Do NOT construct this payload manually and omit funding_rate_e9 — that\r\n * produces a truncated instruction (missing 16 bytes).\r\n *\r\n * @param action CrankAction.FeeSweep or CrankAction.Liquidate.\r\n * @param assetIndex Asset/domain index to operate on.\r\n * @param nowSlot Current slot (for crank freshness check).\r\n * @param recoveryReason Recovery reason byte (0 for normal operations).\r\n *\r\n * @example\r\n * ```ts\r\n * // Simple fee-sweep crank\r\n * const data = encodePermissionlessCrank({\r\n * action: CrankAction.FeeSweep,\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * recoveryReason: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface PermissionlessCrankArgs {\r\n action: number;\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n recoveryReason: number;\r\n}\r\n\r\nexport function encodePermissionlessCrank(args: PermissionlessCrankArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.PermissionlessCrank),\r\n encU8(args.action),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI128(0n), // funding_rate_e9 HARDCODED=0n (program rejects nonzero)\r\n encU8(args.recoveryReason),\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.17 KeeperCrank wire format is not accepted by v17.\r\n * Use encodePermissionlessCrank() instead.\r\n *\r\n * Retained for source-compat only. Will throw to prevent silent misuse.\r\n */\r\nexport interface KeeperCrankArgs {\r\n callerIdx: number;\r\n candidates?: unknown[];\r\n}\r\n\r\nexport function encodeKeeperCrank(_args: KeeperCrankArgs): Uint8Array {\r\n throw new Error(\r\n \"encodeKeeperCrank: v12.17 wire format is not accepted by the v17 wrapper. \" +\r\n \"Use encodePermissionlessCrank() instead.\"\r\n );\r\n}\r\n\r\n/**\r\n * TradeNoCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed completely. v12 had lpIdx+userIdx+size;\r\n * v17 has asset_index+size_q+exec_price+fee_bps.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed; positive=long, negative=short).\r\n * @param execPrice Execution price in e6 units.\r\n * @param feeBps Fee in basis points.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeNoCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * execPrice: 50_000_000_000n,\r\n * feeBps: 30n,\r\n * });\r\n * ```\r\n */\r\nexport interface TradeNoCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\nexport function encodeTradeNoCpi(args: TradeNoCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeNoCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.execPrice),\r\n encU64(args.feeBps),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeNoCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * LiquidateAtOracle (tag 7) — REMOVED in v17.\r\n *\r\n * Tag 7 has no decode arm in the v17 wrapper program. Sending this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Liquidations are handled via PermissionlessCrank (tag 5) in v17.\r\n */\r\nexport interface LiquidateAtOracleArgs {\r\n targetIdx: number;\r\n}\r\n\r\nexport function encodeLiquidateAtOracle(_args: LiquidateAtOracleArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LiquidateAtOracle\",\r\n IX_TAG.LiquidateAtOracle,\r\n \"PermissionlessCrank (tag 5)\",\r\n );\r\n}\r\n\r\n/**\r\n * ClosePortfolio / CloseAccount instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed. The v17 decoder at\r\n * `8 => Self::ClosePortfolio` reads no bytes after the tag. The extra 2\r\n * bytes from the old userIdx field cause InvalidInstructionData.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseAccount();\r\n * ```\r\n */\r\nexport interface CloseAccountArgs {\r\n /** @deprecated userIdx is not read in v17; portfolios are identified by account key. */\r\n userIdx?: number;\r\n}\r\n\r\nexport function encodeCloseAccount(_args?: CloseAccountArgs): Uint8Array {\r\n return new Uint8Array([IX_TAG.ClosePortfolio]);\r\n}\r\n\r\n/**\r\n * TopUpInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount promoted u64→u128. The v17 decoder at tag 9\r\n * reads `amount: read_u128(&mut rest)?` which requires 16 bytes after the\r\n * tag. The old 8-byte u64 payload is 8 bytes short — InvalidInstructionData.\r\n *\r\n * @param amount Amount to top up the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTopUpInsurance({ amount: 10_000_000n });\r\n * ```\r\n */\r\nexport interface TopUpInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpInsurance(args: TopUpInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.TopUpInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * TopUpBackingBucket instruction data (tag 24).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) + expiry_slot(u64 LE)\r\n * = 27 bytes.\r\n *\r\n * Deposits `amount` quote atoms of external collateral into a source domain's\r\n * counterparty backing bucket, requesting `expirySlot` as the bucket's fresh\r\n * expiry. Gated by the asset's `backing_bucket_authority` (v16_program.rs\r\n * handle_top_up_backing_bucket, ~line 8439/8516; engine\r\n * deposit_fresh_counterparty_backing_not_atomic, percolator/src/v16.rs:6118).\r\n *\r\n * Domain numbering: for asset index `i`, the LONG domain is `2*i` and the\r\n * SHORT domain is `2*i + 1`.\r\n *\r\n * ENGINE MECHANICS (percolator/src/v16.rs prepare_counterparty_backing_add_delta,\r\n * ~line 755): if the bucket is Empty/Expired, it adopts `expirySlot` and\r\n * transitions to Fresh. If it is already Fresh with the SAME expiry, this is a\r\n * no-op (safe to call again). If it is Fresh with a DIFFERENT expiry — in\r\n * particular a LAPSED one (`current_slot >= expiry_slot`) — this call reverts\r\n * with Custom(21) LockActive. Seeding a bucket once while it is still Empty,\r\n * with `expirySlot = MAX_BACKING_BUCKET_EXPIRY_SLOT` (9223372036854775807 =\r\n * u64::MAX / 2, effectively never-lapsing), makes that domain immune to the\r\n * \"backing-bucket-freshness deadlock\" for the market's practical lifetime —\r\n * every later automatic loss-reserve requests the SAME existing expiry and\r\n * hits the harmless no-op arm instead of the LockActive trap.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to deposit (u128; must be > 0). A small\r\n * nonzero \"dust\" amount is sufficient — there is no\r\n * minimum floor enforced by the engine.\r\n * @param expirySlot Requested fresh-expiry slot (u64). Use\r\n * MAX_BACKING_BUCKET_EXPIRY_SLOT to seed an immortal bucket.\r\n *\r\n * @example\r\n * ```ts\r\n * // Seed the long domain (asset 0) immortal, while the bucket is still Empty.\r\n * const data = encodeTopUpBackingBucket({\r\n * domain: 0,\r\n * amount: 10_000n, // 0.01 Sim-USDC dust\r\n * expirySlot: MAX_BACKING_BUCKET_EXPIRY_SLOT,\r\n * });\r\n * ```\r\n */\r\nexport const MAX_BACKING_BUCKET_EXPIRY_SLOT: bigint = 9_223_372_036_854_775_807n; // u64::MAX / 2\r\n\r\nexport interface TopUpBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n expirySlot: bigint | string;\r\n}\r\n\r\nexport function encodeTopUpBackingBucket(args: TopUpBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TopUpBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n encU64(args.expirySlot),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucket instruction data (tag 50).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws `amount` quote atoms of backing-bucket PRINCIPAL from a domain\r\n * back to the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket` → `verify_domain_withdrawal_preflight`\r\n * with DOMAIN_WITHDRAW_AUTH_BACKING. The destination token account must be\r\n * OWNED by the signing authority (verify_withdrawable_token_accounts).\r\n *\r\n * Together with TopUpBackingBucket (24, deposit) and\r\n * WithdrawBackingBucketEarnings (52, fee earnings) this completes the\r\n * LP-provider backing-bucket loop.\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short).\r\n * @param amount Quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucket(args: WithdrawBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucket),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateBackingFeePolicy instruction data (tag 51).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * THE switch that turns on LP-vault yield for a domain: sets the\r\n * backing-trade fee charged on that domain's fills, of which\r\n * `insurance_share_bps` is diverted to the insurance budget and the\r\n * remainder accrues to the domain's backing-bucket providers as\r\n * `utilization_fee_earnings` (withdrawable via tag 52). Every live market\r\n * currently has this at 0 — which is why LP APY is 0%.\r\n *\r\n * Gated by the asset's `insurance_authority` (v16_program.rs\r\n * `handle_update_backing_fee_policy`, gate at ~10492) — NOT marketauth, so\r\n * the market creator can call it even after the launch flow rotates\r\n * marketauth to the stake-pool PDA. Market must be Live.\r\n *\r\n * Handler-side validation (reverts InvalidInstruction otherwise):\r\n * fee_bps ≤ 10_000, insurance_share_bps ≤ 10_000, fee_bps == 0 implies\r\n * insurance_share_bps == 0, fee_bps ≤ the market's max_trading_fee_bps and\r\n * ≤ MAX_DYNAMIC_TRADE_FEE_BPS.\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param feeBps Backing-trade fee in bps (0 turns the fee off).\r\n * @param insuranceShareBps Share of that fee diverted to insurance, in bps\r\n * of the fee (the rest goes to backing providers).\r\n */\r\nexport interface UpdateBackingFeePolicyArgs {\r\n domain: number;\r\n feeBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateBackingFeePolicy(args: UpdateBackingFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateBackingFeePolicy),\r\n encU16(args.domain),\r\n encU16(args.feeBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings instruction data (tag 52).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) + amount(u128 LE) = 19 bytes.\r\n *\r\n * Withdraws accrued `utilization_fee_earnings` (the LP-provider share of the\r\n * backing-trade fee enabled via tag 51) from a domain's backing bucket to\r\n * the authority's token account. Gated by the asset's\r\n * `backing_bucket_authority` (or marketauth) — v16_program.rs\r\n * `handle_withdraw_backing_bucket_earnings` → same\r\n * DOMAIN_WITHDRAW_AUTH_BACKING preflight as tag 50. Unlike tag 50, the\r\n * per-domain ledger account is REQUIRED (account [2]).\r\n *\r\n * @param domain Domain index (2*assetIndex long, 2*assetIndex+1 short).\r\n * @param amount Earnings quote atoms to withdraw (u128; must be > 0).\r\n */\r\nexport interface WithdrawBackingBucketEarningsArgs {\r\n domain: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawBackingBucketEarnings(\r\n args: WithdrawBackingBucketEarningsArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawBackingBucketEarnings),\r\n encU16(args.domain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * TradeCpi instruction data (v17 wire format).\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)\r\n * = 28 bytes.\r\n *\r\n * BREAKING vs v12.x: payload fields changed. v12 had lpIdx+userIdx+size+limitPriceE6;\r\n * v17 has asset_index+size_q+fee_bps+limit_price.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param sizeQ Trade quantity (signed).\r\n * @param feeBps Fee in basis points.\r\n * @param limitPrice Limit price in e6 units. 0 = no limit (accept any price).\r\n * Buys: reject if exec_price > limit_price.\r\n * Sells: reject if exec_price < limit_price.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTradeCpi({\r\n * assetIndex: 0,\r\n * sizeQ: 1_000_000n,\r\n * feeBps: 30n,\r\n * limitPrice: 51_000_000_000n, // max price for a buy\r\n * });\r\n * ```\r\n */\r\nexport interface TradeCpiArgs {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n /** Limit price in e6 units. 0 = no limit. */\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport function encodeTradeCpi(args: TradeCpiArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(IX_TAG.TradeCpi),\r\n encU16(args.assetIndex),\r\n encI128(args.sizeQ),\r\n encU64(args.feeBps),\r\n encU64(args.limitPrice),\r\n );\r\n if (data.length !== 35) {\r\n throw new Error(\r\n `encodeTradeCpi: expected 35 bytes (tag+u16+i128+u64+u64), got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n/**\r\n * @deprecated Tag 35 removed in v12.17. Use TradeCpi (tag 10) with limitPriceE6 instead.\r\n * TradeCpi now handles PDA bump internally. Sending tag 35 will fail with InvalidInstructionData.\r\n */\r\nexport interface TradeCpiV2Args {\r\n lpIdx: number;\r\n userIdx: number;\r\n size: bigint | string;\r\n bump: number;\r\n}\r\n\r\n/** @deprecated Tag 35 removed in v12.17. Use encodeTradeCpi with limitPriceE6 instead. */\r\nexport function encodeTradeCpiV2(_args: TradeCpiV2Args): Uint8Array {\r\n return removedInstruction(\"TradeCpiV2\", IX_TAG.TradeCpiV, \"encodeTradeCpi()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 36 removed in v12.17. Will fail on-chain with InvalidInstructionData.\r\n */\r\nexport interface UnresolveMarketArgs {\r\n confirmation: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 36 removed in v12.17. Will fail on-chain. */\r\nexport function encodeUnresolveMarket(_args: UnresolveMarketArgs): Uint8Array {\r\n return removedInstruction(\"UnresolveMarket\", IX_TAG.UnresolveMarket, \"encodeResolveMarket()\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 11 removed in v12.17. Insurance floor is now set at InitMarket.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetRiskThresholdArgs {\r\n newThreshold: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 11 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetRiskThreshold(_args: SetRiskThresholdArgs): Uint8Array {\r\n return removedInstruction(\"SetRiskThreshold\", IX_TAG.SetRiskThreshold, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * UpdateAdmin (tag 12) — REMOVED in v17.\r\n *\r\n * Tag 12 has no decode arm in the v17 wrapper program. Calling this instruction\r\n * results in ProgramError::InvalidInstructionData on-chain.\r\n *\r\n * @deprecated Use UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65) in v17.\r\n */\r\nexport interface UpdateAdminArgs {\r\n newAdmin: PublicKey | string;\r\n}\r\n\r\n/** @deprecated Tag 12 removed in v17. Will fail on-chain. */\r\nexport function encodeUpdateAdmin(_args: UpdateAdminArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateAdmin\",\r\n IX_TAG.UpdateAdmin,\r\n \"UpdateAuthority (tag 32) or UpdateAssetAuthority (tag 65)\",\r\n );\r\n}\r\n\r\n/**\r\n * CloseSlab instruction data (1 byte)\r\n */\r\nexport function encodeCloseSlab(): Uint8Array {\r\n return encU8(IX_TAG.CloseSlab);\r\n}\r\n\r\n/**\r\n * UpdateConfig instruction data.\r\n *\r\n * 35 bytes: tag(1) + funding_horizon_slots(8) + funding_k_bps(8) +\r\n * funding_max_premium_bps(8) + funding_max_e9_per_slot(8) +\r\n * tvl_insurance_cap_mult(2). Wire layout matches v12.19 wrapper at\r\n * src/percolator.rs:2027-2041 (handle_update_config decode).\r\n */\r\nexport interface UpdateConfigArgs {\r\n fundingHorizonSlots: bigint | string;\r\n fundingKBps: bigint | string;\r\n fundingMaxPremiumBps: bigint | string;\r\n fundingMaxBpsPerSlot: bigint | string;\r\n /**\r\n * u16 deposit cap multiplier. 0 disables the protocol-enforced cap.\r\n * Wrapper field added at src/percolator.rs:2031.\r\n */\r\n tvlInsuranceCapMult?: number;\r\n}\r\n\r\n/** @deprecated v12.x UpdateConfig (old tag 14). Not in v17. */\r\nexport function encodeUpdateConfig(_args: UpdateConfigArgs): Uint8Array {\r\n return removedInstruction(\"UpdateConfig (v12 tag 14 — not in v17)\", IX_TAG.UpdateConfig, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated Tag 15 removed in v12.17. Maintenance fee is set at InitMarket only.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetMaintenanceFeeArgs {\r\n newFee: bigint | string;\r\n}\r\n\r\n/** @deprecated Tag 15 removed in v12.17. Will fail on-chain. */\r\nexport function encodeSetMaintenanceFee(_args: SetMaintenanceFeeArgs): Uint8Array {\r\n return removedInstruction(\"SetMaintenanceFee\", IX_TAG.SetMaintenanceFee, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * SetOraclePriceCap instruction data (9 bytes)\r\n * Set oracle price circuit breaker cap (admin only).\r\n *\r\n * max_change_e2bps: maximum oracle price movement per slot in 0.01 bps units.\r\n * 1_000_000 = 100% max move per slot.\r\n *\r\n * ⚠️ PERC-8191 (PR#150): cap=0 is NO LONGER accepted for admin-oracle markets.\r\n * - Hyperp markets: rejected if cap < DEFAULT_HYPERP_PRICE_CAP_E2BPS (1000).\r\n * - Admin-oracle markets: rejected if cap == 0 (circuit breaker bypass prevention).\r\n * - Pyth-pinned markets: immune (oracle_authority zeroed), any value accepted.\r\n *\r\n * Use a non-zero cap for all admin-oracle and Hyperp markets.\r\n */\r\nexport interface SetOraclePriceCapArgs {\r\n maxChangeE2bps: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetOraclePriceCap (old tag 16). Not in v17. */\r\nexport function encodeSetOraclePriceCap(_args: SetOraclePriceCapArgs): Uint8Array {\r\n return removedInstruction(\"SetOraclePriceCap (v12 tag 16 — not in v17)\", IX_TAG.SetOraclePriceCap, undefined);\r\n}\r\n\r\n/**\r\n * ResolveMode constants — retained for source compatibility with v12.x callers.\r\n *\r\n * @deprecated v17 ResolveMarket (tag 19) has no mode byte. These constants are\r\n * no longer encoded into the instruction data. They may be used in logging or\r\n * off-chain logic but must not be passed to encodeResolveMarket.\r\n */\r\nexport const RESOLVE_MODE_ORDINARY = 0 as const;\r\nexport const RESOLVE_MODE_DEGENERATE = 1 as const;\r\nexport type ResolveMode = typeof RESOLVE_MODE_ORDINARY | typeof RESOLVE_MODE_DEGENERATE;\r\n\r\n/**\r\n * ResolveMarket instruction data.\r\n *\r\n * v17 wire: tag(1) only — 1 byte total.\r\n *\r\n * BREAKING vs v12.x PORT-1 / Wave-12-J: the mode byte has been REMOVED.\r\n * The v17 decoder at `19 => Self::ResolveMarket` reads no bytes after the\r\n * tag. Sending a 2-byte payload causes the extra byte to be consumed by the\r\n * next read in a subsequent call, corrupting the instruction stream.\r\n *\r\n * The `mode` argument is accepted for source compatibility but is silently ignored.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeResolveMarket();\r\n * ```\r\n */\r\nexport function encodeResolveMarket(_args: { mode?: ResolveMode } = {}): Uint8Array {\r\n return new Uint8Array([IX_TAG.ResolveMarket]);\r\n}\r\n\r\n/**\r\n * WithdrawInsurance instruction data.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: amount(u128) is now REQUIRED. The v17 decoder at\r\n * tag 41 reads `amount: read_u128(&mut rest)?` — without 16 bytes of amount,\r\n * read_u128 returns Err(InvalidInstructionData). Every call with the old\r\n * 1-byte payload fails on devnet/mainnet.\r\n *\r\n * Withdraw insurance fund to admin (requires RESOLVED and all positions closed).\r\n *\r\n * @param amount Amount to withdraw from the insurance fund (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsurance({ amount: 5_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsurance(args: WithdrawInsuranceArgs): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.WithdrawInsurance), encU128(args.amount));\r\n}\r\n\r\n/**\r\n * AdminForceClose instruction data (3 bytes)\r\n * Force-close any position at oracle price (admin only, skips margin checks).\r\n */\r\nexport interface AdminForceCloseArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x AdminForceClose (old tag 17). Not in v17. */\r\nexport function encodeAdminForceClose(_args: AdminForceCloseArgs): Uint8Array {\r\n return removedInstruction(\"AdminForceClose (v12 tag 17 — not in v17)\", IX_TAG.AdminForceClose, \"encodeForceCloseAbandonedAsset() if applicable\");\r\n}\r\n\r\n/**\r\n * @deprecated Tag 22 is now SetInsuranceWithdrawPolicy in v12.17.\r\n * This encoder sends the WRONG wire format (u64+u64 instead of pubkey+u64+u16+u64).\r\n * Use encodeSetInsuranceWithdrawPolicy instead.\r\n */\r\nexport interface UpdateRiskParamsArgs {\r\n initialMarginBps: bigint | string;\r\n maintenanceMarginBps: bigint | string;\r\n tradingFeeBps?: bigint | string;\r\n}\r\n\r\n/** @deprecated Use encodeSetInsuranceWithdrawPolicy (tag 22). This sends wrong wire format. */\r\nexport function encodeUpdateRiskParams(_args: UpdateRiskParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"UpdateRiskParams\",\r\n IX_TAG.UpdateRiskParams,\r\n \"encodeSetInsuranceWithdrawPolicy()\",\r\n );\r\n}\r\n\r\n/**\r\n * On-chain confirmation code for RenounceAdmin (must match program constant).\r\n * ASCII \"RENOUNCE\" as u64 LE = 0x52454E4F554E4345.\r\n */\r\nexport const RENOUNCE_ADMIN_CONFIRMATION = 0x52454E4F554E4345n;\r\n\r\n/**\r\n * On-chain confirmation code for UnresolveMarket (must match program constant).\r\n */\r\nexport const UNRESOLVE_CONFIRMATION = 0xDEAD_BEEF_CAFE_1234n;\r\n\r\n/**\r\n * @deprecated Tag 23 is now WithdrawInsuranceLimited in v12.17.\r\n * This encoder sends the confirmation code as a withdrawal amount — DANGEROUS.\r\n * Use encodeWithdrawInsuranceLimited instead.\r\n */\r\nexport function encodeRenounceAdmin(): Uint8Array {\r\n return removedInstruction(\r\n \"RenounceAdmin\",\r\n IX_TAG.RenounceAdmin,\r\n \"encodeWithdrawInsuranceLimited()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw (Tag 39, PERC-627 / GH#1926 / PERC-8287) — burn LP vault tokens and\r\n * withdraw proportional collateral.\r\n *\r\n * **BREAKING (PR#170):** accounts[9] = creatorLockPda is now REQUIRED.\r\n * Always include `deriveCreatorLockPda(programId, slab)` at position 9.\r\n * Non-creator withdrawers pass the derived PDA; if no lock exists on-chain\r\n * the check is a no-op. Omitting this account causes `ExpectLenFailed` on-chain.\r\n *\r\n * Instruction data: tag(1) + lp_amount(8) = 9 bytes\r\n *\r\n * Accounts (use ACCOUNTS_LP_VAULT_WITHDRAW):\r\n * [0] withdrawer signer\r\n * [1] slab writable\r\n * [2] withdrawerAta writable\r\n * [3] vault writable\r\n * [4] tokenProgram\r\n * [5] lpVaultMint writable\r\n * [6] withdrawerLpAta writable\r\n * [7] vaultAuthority\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable ← derive with deriveCreatorLockPda(programId, slab)\r\n *\r\n * @param lpAmount - Amount of LP vault tokens to burn.\r\n *\r\n * @example\r\n * ```ts\r\n * import { encodeLpVaultWithdraw, ACCOUNTS_LP_VAULT_WITHDRAW, buildAccountMetas } from \"@percolator/sdk\";\r\n * import { deriveCreatorLockPda, deriveVaultAuthority } from \"@percolator/sdk\";\r\n *\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * const [vaultAuthority] = deriveVaultAuthority(PROGRAM_ID, slabKey);\r\n *\r\n * const data = encodeLpVaultWithdraw({ lpAmount: 1_000_000_000n });\r\n * const keys = buildAccountMetas(ACCOUNTS_LP_VAULT_WITHDRAW, {\r\n * withdrawer, slab: slabKey, withdrawerAta, vault, tokenProgram: TOKEN_PROGRAM_ID,\r\n * lpVaultMint, withdrawerLpAta, vaultAuthority, lpVaultState, creatorLockPda,\r\n * });\r\n * ```\r\n */\r\nexport interface LpVaultWithdrawArgs {\r\n /** Amount of LP vault tokens to burn. */\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultWithdraw (tag 39 in v12, now alias 76=RequestRedeemLpShares in v17).\r\n * v17 uses a 2-step request/execute redemption flow — see encodeRequestRedeemLpShares.\r\n */\r\nexport function encodeLpVaultWithdraw(_args: LpVaultWithdrawArgs): Uint8Array {\r\n return removedInstruction(\r\n \"LpVaultWithdraw (v12 wire, tag 39→76 alias — wire format changed)\",\r\n IX_TAG.LpVaultWithdraw,\r\n \"encodeRequestRedeemLpShares() + encodeExecuteRedemption()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x PauseMarket (old tag 56). v17 reuses tag 56 for TopUpInsuranceDomain.\r\n */\r\nexport function encodePauseMarket(): Uint8Array {\r\n return removedInstruction(\"PauseMarket (v12 tag 56 — now TopUpInsuranceDomain in v17)\", IX_TAG.PauseMarket, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x UnpauseMarket (old tag 58). v17 reuses tag 58 for UpdateFeeRedirectPolicy.\r\n */\r\nexport function encodeUnpauseMarket(): Uint8Array {\r\n return removedInstruction(\"UnpauseMarket (v12 tag 58 — now UpdateFeeRedirectPolicy in v17)\", IX_TAG.UnpauseMarket, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-117: Pyth Oracle CPI Instructions\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated Tag 32 removed in v12.17. Pyth oracle is configured at InitMarket via indexFeedId.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport interface SetPythOracleArgs {\r\n feedId: Uint8Array;\r\n maxStalenessSecs: bigint;\r\n confFilterBps: number;\r\n}\r\n\r\n/** @deprecated Tag 32 removed in v12.17. Pyth is configured at InitMarket. */\r\nexport function encodeSetPythOracle(args: SetPythOracleArgs): Uint8Array {\r\n void args;\r\n return removedInstruction(\"SetPythOracle\", IX_TAG.SetPythOracle, \"encodeInitMarket()\");\r\n}\r\n\r\n/**\r\n * Derive the expected Pyth PriceUpdateV2 account address for a given feed ID.\r\n * Uses PDA seeds: [shard_id(2), feed_id(32)] under the Pyth Receiver program.\r\n *\r\n * @param feedId 32-byte Pyth feed ID\r\n * @param shardId Shard index (default 0 for mainnet/devnet)\r\n */\r\nexport const PYTH_RECEIVER_PROGRAM_ID = 'rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ';\r\n\r\nexport async function derivePythPriceUpdateAccount(\r\n feedId: Uint8Array,\r\n shardId = 0,\r\n): Promise {\r\n if (!(feedId instanceof Uint8Array) || feedId.length !== 32) {\r\n throw new Error(`derivePythPriceUpdateAccount: feedId must be 32 bytes, got ${feedId?.length ?? \"invalid\"}`);\r\n }\r\n if (!Number.isInteger(shardId) || shardId < 0 || shardId > 0xffff) {\r\n throw new Error(`derivePythPriceUpdateAccount: shardId must be a u16, got ${shardId}`);\r\n }\r\n const { PublicKey } = await import('@solana/web3.js');\r\n const shardBuf = new Uint8Array(2);\r\n new DataView(shardBuf.buffer).setUint16(0, shardId, true);\r\n const [pda] = PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n new PublicKey(PYTH_RECEIVER_PROGRAM_ID),\r\n );\r\n return pda.toBase58();\r\n}\r\n\r\n// SetPythOracle tag (32) is already defined in IX_TAG above.\r\n\r\n// PERC-118: Mark Price EMA Instructions\r\n// ============================================================================\r\n\r\n// Tag 33 — permissionless mark price EMA crank (defined in IX_TAG above).\r\n\r\n/**\r\n * @deprecated Tag 33 removed in v12.17. Use UpdateHyperpMark (tag 34) for DEX-oracle markets.\r\n * Sending this instruction will fail with InvalidInstructionData.\r\n */\r\nexport function encodeUpdateMarkPrice(): Uint8Array {\r\n return removedInstruction(\"UpdateMarkPrice\", IX_TAG.UpdateMarkPrice, \"encodeUpdateHyperpMark()\");\r\n}\r\n\r\n/**\r\n * Mark price EMA parameters (must match program/src/percolator.rs constants).\r\n */\r\nexport const MARK_PRICE_EMA_WINDOW_SLOTS = 72_000n;\r\nexport const MARK_PRICE_EMA_ALPHA_E6 = 2_000_000n / (MARK_PRICE_EMA_WINDOW_SLOTS + 1n);\r\n\r\n/**\r\n * Compute the next EMA mark price step (TypeScript mirror of the on-chain function).\r\n */\r\nexport function computeEmaMarkPrice(\r\n markPrevE6: bigint,\r\n oracleE6: bigint,\r\n dtSlots: bigint,\r\n alphaE6 = MARK_PRICE_EMA_ALPHA_E6,\r\n capE2bps = 0n,\r\n): bigint {\r\n if (oracleE6 === 0n) return markPrevE6;\r\n if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;\r\n\r\n let oracleClamped = oracleE6;\r\n if (capE2bps > 0n) {\r\n // Avoid overflow: divide early to reduce intermediate product\r\n const maxDelta = (markPrevE6 * capE2bps / 1_000_000n) * dtSlots;\r\n const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;\r\n const hi = markPrevE6 + maxDelta;\r\n if (oracleClamped < lo) oracleClamped = lo;\r\n if (oracleClamped > hi) oracleClamped = hi;\r\n }\r\n\r\n const effectiveAlpha = alphaE6 * dtSlots > 1_000_000n ? 1_000_000n : alphaE6 * dtSlots;\r\n const oneMinusAlpha = 1_000_000n - effectiveAlpha;\r\n\r\n return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1_000_000n;\r\n}\r\n\r\n// PERC-119: Hyperp EMA Oracle for Permissionless Tokens\r\n// ============================================================================\r\n\r\n// Tag 34 — permissionless Hyperp mark price oracle (defined in IX_TAG above).\r\n\r\n/**\r\n * UpdateHyperpMark (Tag 34) — permissionless Hyperp EMA oracle crank.\r\n *\r\n * Reads the spot price from a PumpSwap, Raydium CLMM, or Meteora DLMM pool,\r\n * applies 8-hour EMA smoothing with circuit breaker, and writes the new mark\r\n * to authority_price_e6 on the slab.\r\n *\r\n * This is the core mechanism for permissionless token markets — no Pyth or\r\n * Chainlink feed is needed. The DEX AMM IS the oracle.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n * 1. [] DEX pool account (PumpSwap / Raydium CLMM / Meteora DLMM)\r\n * 2. [] Clock sysvar (SysvarC1ock11111111111111111111111111111111)\r\n * 3..N [] Remaining accounts (e.g. PumpSwap vault0 + vault1)\r\n */\r\nexport function encodeUpdateHyperpMark(): Uint8Array {\r\n // v17: tag 34 is ConfigureHybridOracle (a large payload), NOT a 1-byte DEX-pool mark crank.\r\n // Emitting [34] would be decoded as ConfigureHybridOracle with an empty body → InvalidInstructionData.\r\n // The v12 hyperp DEX-pool mark mode was removed; fail loud instead of building a rejected tx.\r\n return removedInstruction(\r\n \"UpdateHyperpMark (v12 DEX-pool mark crank — tag 34 is ConfigureHybridOracle in v17)\",\r\n 34,\r\n \"ConfigureHybridOracle (tag 34) / ConfigureEwmaMark (tag 35), or PermissionlessCrank (tag 5) for mark refresh\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-306: Per-Market Insurance Isolation\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x FundMarketInsurance (old tag 25). Not in v17.\r\n */\r\nexport function encodeFundMarketInsurance(_args: { amount: bigint }): Uint8Array {\r\n return removedInstruction(\"FundMarketInsurance (v12 tag 25 — not in v17)\", IX_TAG.FundMarketInsurance, undefined);\r\n}\r\n\r\n/**\r\n * Set insurance isolation BPS for a market.\r\n * Accounts: [admin(signer), slab(writable)]\r\n */\r\nexport function encodeSetInsuranceIsolation(args: { bps: number }): Uint8Array {\r\n void args;\r\n return removedInstruction(\r\n \"SetInsuranceIsolation\",\r\n IX_TAG.SetInsuranceIsolation,\r\n \"encodeFundMarketInsurance()\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// NOTE: encodeExecuteAdl() was historically removed when it was discovered\r\n// that PERC-305 was NOT implemented on-chain and tag 43 was ChallengeSettlement.\r\n// PERC-305 (ExecuteAdl) is now live at tag 50. Encoder added below.\r\n// ============================================================================\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal (Tag 47, PERC-309) — queue a large LP withdrawal.\r\n *\r\n * Creates a withdraw_queue PDA. The LP tokens are claimed in epoch tranches\r\n * via ClaimQueuedWithdrawal. Call CancelQueuedWithdrawal to abort.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), lpVaultState, withdrawQueue(writable), systemProgram]\r\n *\r\n * @param lpAmount - Amount of LP tokens to queue for withdrawal.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeQueueWithdrawal({ lpAmount: 1_000_000_000n });\r\n * ```\r\n */\r\n/** @deprecated v12.x QueueWithdrawal (old tag 102). Not in v17. */\r\nexport function encodeQueueWithdrawal(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawal (v12 tag 102 — not in v17)\", IX_TAG.QueueWithdrawal, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n/**\r\n * ClaimQueuedWithdrawal (Tag 48, PERC-309) — claim one epoch tranche from a queued withdrawal.\r\n *\r\n * Burns LP tokens and releases one tranche of SOL to the user.\r\n * Call once per epoch until epochs_remaining == 0.\r\n *\r\n * Accounts: [user(signer,writable), slab(writable), withdrawQueue(writable),\r\n * lpVaultMint(writable), userLpAta(writable), vault(writable),\r\n * userAta(writable), vaultAuthority, tokenProgram, lpVaultState(writable)]\r\n */\r\n/** @deprecated v12.x ClaimQueuedWithdrawal (old tag 103). Not in v17. */\r\nexport function encodeClaimQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimQueuedWithdrawal (v12 tag 103 — not in v17)\", IX_TAG.ClaimQueuedWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * CancelQueuedWithdrawal (Tag 49, PERC-309) — cancel a queued withdrawal, refund remaining LP.\r\n *\r\n * Closes the withdraw_queue PDA and returns its rent lamports to the user.\r\n * The queued LP amount that was not yet claimed is NOT refunded — it is burned.\r\n * Use only to abandon a partial withdrawal.\r\n *\r\n * Accounts: [user(signer,writable), slab, withdrawQueue(writable)]\r\n */\r\n/** @deprecated v12.x CancelQueuedWithdrawal (old tag 104). Not in v17. */\r\nexport function encodeCancelQueuedWithdrawal(): Uint8Array {\r\n return removedInstruction(\"CancelQueuedWithdrawal (v12 tag 104 — not in v17)\", IX_TAG.CancelQueuedWithdrawal, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (Tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl (Tag 50, PERC-305) — auto-deleverage the most profitable position.\r\n *\r\n * Permissionless. Surgically closes or reduces `targetIdx` position when\r\n * `pnl_pos_tot > max_pnl_cap` on the market. The caller receives no reward —\r\n * the incentive is unblocking the market for normal trading.\r\n *\r\n * Requires `UpdateRiskParams.max_pnl_cap > 0` on the market.\r\n *\r\n * Accounts: [caller(signer), slab(writable), clock, oracle, ...backupOracles?]\r\n *\r\n * @param targetIdx - Account index of the position to deleverage.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteAdl({ targetIdx: 5 });\r\n * ```\r\n */\r\nexport interface ExecuteAdlArgs {\r\n targetIdx: number;\r\n}\r\n\r\n/** @deprecated v12.x ExecuteAdl (old tag 101). Not in v17. */\r\nexport function encodeExecuteAdl(_args: ExecuteAdlArgs): Uint8Array {\r\n return removedInstruction(\"ExecuteAdl (v12 tag 101 — not in v17)\", IX_TAG.ExecuteAdl, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (Tag 51) / ReclaimSlabRent (Tag 52) — Slab recovery\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs (Tag 51) — close a slab of an invalid/old layout and recover rent SOL.\r\n *\r\n * Admin only. Skips slab_guard; validates header magic + admin authority instead.\r\n * Use for slabs created by old program layouts (e.g. pre-PERC-120 devnet deploys)\r\n * whose size does not match any current valid tier.\r\n *\r\n * Accounts: [dest(signer,writable), slab(writable)]\r\n */\r\n/** @deprecated v12.x CloseStaleSlabs (old tag 100). Not in v17. */\r\nexport function encodeCloseStaleSlabs(): Uint8Array {\r\n return removedInstruction(\"CloseStaleSlabs (v12 tag 100 — not in v17)\", IX_TAG.CloseStaleSlabs, undefined);\r\n}\r\n\r\n/**\r\n * ReclaimSlabRent (Tag 52) — reclaim rent from an uninitialised slab.\r\n *\r\n * For use when market creation failed mid-flow (slab funded but InitMarket not called).\r\n * The slab account must sign (proves the caller holds the slab keypair).\r\n * Cannot close an initialised slab (magic == PERCOLAT) — use CloseSlab (tag 13).\r\n *\r\n * Accounts: [dest(signer,writable), slab(signer,writable)]\r\n */\r\n/** @deprecated v12.x ReclaimSlabRent (old tag 99). Not in v17. */\r\nexport function encodeReclaimSlabRent(): Uint8Array {\r\n return removedInstruction(\"ReclaimSlabRent (v12 tag 99 — not in v17)\", IX_TAG.ReclaimSlabRent, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// AuditCrank (Tag 53) — Permissionless on-chain invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank (Tag 53) — verify conservation invariants on-chain (permissionless).\r\n *\r\n * Walks all accounts and verifies: capital sum, pnl_pos_tot, total_oi, LP consistency,\r\n * and solvency. Sets FLAG_PAUSED on violation (with a 150-slot cooldown guard to\r\n * prevent DoS from transient failures).\r\n *\r\n * Accounts: [slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeAuditCrank();\r\n * ```\r\n */\r\n/** @deprecated v12.x AuditCrank (old tag 91). Not in v17. */\r\nexport function encodeAuditCrank(): Uint8Array {\r\n return removedInstruction(\"AuditCrank (v12 tag 91 — not in v17)\", IX_TAG.AuditCrank, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// SMART PRICE ROUTER — quote computation for LP selection\r\n// ============================================================================\r\n\r\n/**\r\n * Parsed vAMM matcher parameters (from on-chain matcher context account)\r\n */\r\nexport interface VammMatcherParams {\r\n mode: number; // 0 = Passive, 1 = vAMM\r\n tradingFeeBps: number;\r\n baseSpreadBps: number;\r\n maxTotalBps: number;\r\n impactKBps: number;\r\n liquidityNotionalE6: bigint;\r\n}\r\n\r\n/** Magic bytes identifying a vAMM matcher context: \"PERCMATC\" as u64 LE = 0x504552434d415443 */\r\nexport const VAMM_MAGIC = 0x504552434d415443n;\r\n/** Alias matching the Rust constant name for parity tests */\r\nexport const MATCHER_MAGIC = VAMM_MAGIC;\r\n\r\n/** Offset where matcher return is written in the context account (always 0 per ABI) */\r\nexport const CTX_RETURN_OFFSET = 0;\r\n/** Byte length of the MatcherReturn section of the context account */\r\nexport const MATCHER_RETURN_LEN = 64;\r\n/** Offset into matcher context where vAMM params start (= MATCHER_RETURN_LEN) */\r\nexport const CTX_VAMM_OFFSET = 64;\r\n/** Byte length of the MatcherCtx (vAMM state) section of the context account */\r\nexport const CTX_VAMM_LEN = 256;\r\n/** Total matcher context account size: MATCHER_RETURN_LEN + CTX_VAMM_LEN */\r\nexport const MATCHER_CONTEXT_LEN = 320;\r\n/** Byte length of a MatcherCall instruction (tag 0 CPI payload) */\r\nexport const MATCHER_CALL_LEN = 67;\r\n/**\r\n * Byte length of an InitMatcherCtx instruction payload sent to the matcher program.\r\n * Layout: tag(1) + kind(1) + trading_fee_bps(4) + base_spread_bps(4) +\r\n * max_total_bps(4) + impact_k_bps(4) + liquidity_notional_e6(16) +\r\n * max_fill_abs(16) + max_inventory_abs(16) + fee_to_insurance_bps(2) +\r\n * skew_spread_mult_bps(2) + lp_account_id(8) = 78\r\n */\r\nexport const INIT_CTX_LEN = 78;\r\n\r\nconst BPS_DENOM = 10_000n;\r\n\r\n/**\r\n * Compute execution price for a given LP quote.\r\n * For buys (isLong=true): price above oracle.\r\n * For sells (isLong=false): price below oracle.\r\n */\r\nexport function computeVammQuote(\r\n params: VammMatcherParams,\r\n oraclePriceE6: bigint,\r\n tradeSize: bigint,\r\n isLong: boolean,\r\n): bigint {\r\n const absSize = tradeSize < 0n ? -tradeSize : tradeSize;\r\n const absNotionalE6 = (absSize * oraclePriceE6) / 1_000_000n;\r\n\r\n // Impact for vAMM mode\r\n let impactBps = 0n;\r\n if (params.mode === 1 && params.liquidityNotionalE6 > 0n) {\r\n impactBps = (absNotionalE6 * BigInt(params.impactKBps)) / params.liquidityNotionalE6;\r\n }\r\n\r\n // Total = base_spread + trading_fee + impact, capped at max_total\r\n const maxTotal = BigInt(params.maxTotalBps);\r\n const baseFee = BigInt(params.baseSpreadBps) + BigInt(params.tradingFeeBps);\r\n const maxImpact = maxTotal > baseFee ? maxTotal - baseFee : 0n;\r\n const clampedImpact = impactBps < maxImpact ? impactBps : maxImpact;\r\n let totalBps = baseFee + clampedImpact;\r\n if (totalBps > maxTotal) totalBps = maxTotal;\r\n\r\n if (isLong) {\r\n return (oraclePriceE6 * (BPS_DENOM + totalBps)) / BPS_DENOM;\r\n } else {\r\n // Prevent underflow: if totalBps >= BPS_DENOM, price would go negative\r\n if (totalBps >= BPS_DENOM) return 1n; // minimum 1 micro-dollar\r\n return (oraclePriceE6 * (BPS_DENOM - totalBps)) / BPS_DENOM;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless crank)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase (Tag 56) — permissionless oracle phase advancement.\r\n *\r\n * Checks if a market should transition from Phase 0→1→2 based on\r\n * time elapsed and cumulative volume. Anyone can call this.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [writable] Slab\r\n */\r\n/** @deprecated v12.x AdvanceOraclePhase (old tag 92). Not in v17. */\r\nexport function encodeAdvanceOraclePhase(): Uint8Array {\r\n return removedInstruction(\"AdvanceOraclePhase (v12 tag 92 — not in v17)\", IX_TAG.AdvanceOraclePhase, undefined);\r\n}\r\n\r\n/** Oracle phase constants matching on-chain values */\r\nexport const ORACLE_PHASE_NASCENT = 0;\r\nexport const ORACLE_PHASE_GROWING = 1;\r\nexport const ORACLE_PHASE_MATURE = 2;\r\n\r\n/** Phase transition thresholds (must match program constants) */\r\nexport const PHASE1_MIN_SLOTS = 648_000n; // ~72h at 400ms\r\nexport const PHASE1_VOLUME_MIN_SLOTS = 36_000n; // ~4h at 400ms\r\nexport const PHASE2_VOLUME_THRESHOLD = 100_000_000_000n; // $100K in e6\r\nexport const PHASE2_MATURITY_SLOTS = 3_024_000n; // ~14 days at 400ms\r\n\r\n/**\r\n * Check if an oracle phase transition is due (TypeScript mirror of on-chain logic).\r\n *\r\n * @returns [newPhase, shouldTransition]\r\n */\r\nexport function checkPhaseTransition(\r\n currentSlot: bigint,\r\n marketCreatedSlot: bigint,\r\n oraclePhase: number,\r\n cumulativeVolumeE6: bigint,\r\n phase2DeltaSlots: number,\r\n hasMatureOracle: boolean,\r\n): [number, boolean] {\r\n switch (oraclePhase) {\r\n case 0: {\r\n const elapsed = currentSlot - (marketCreatedSlot > 0n ? marketCreatedSlot : currentSlot);\r\n const timeReady = elapsed >= PHASE1_MIN_SLOTS;\r\n const volumeReady = elapsed >= PHASE1_VOLUME_MIN_SLOTS\r\n && cumulativeVolumeE6 >= PHASE2_VOLUME_THRESHOLD;\r\n if (timeReady || volumeReady) {\r\n return [ORACLE_PHASE_GROWING, true];\r\n }\r\n return [ORACLE_PHASE_NASCENT, false];\r\n }\r\n case 1: {\r\n if (hasMatureOracle) return [ORACLE_PHASE_MATURE, true];\r\n const phase2Start = marketCreatedSlot + BigInt(phase2DeltaSlots);\r\n const elapsedSincePhase2 = currentSlot - phase2Start;\r\n if (elapsedSincePhase2 >= PHASE2_MATURITY_SLOTS) {\r\n return [ORACLE_PHASE_MATURE, true];\r\n }\r\n return [ORACLE_PHASE_GROWING, false];\r\n }\r\n default:\r\n return [ORACLE_PHASE_MATURE, false];\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// PERC-629: Dynamic Creation Deposit\r\n// ============================================================================\r\n\r\n/**\r\n * SlashCreationDeposit (Tag 58) — permissionless: slash a market creator's deposit\r\n * after the spam grace period has elapsed (PERC-629).\r\n *\r\n * **WARNING**: Tag 58 is reserved in tags.rs but has NO instruction decoder or\r\n * handler in the on-chain program. Sending this instruction will fail with\r\n * `InvalidInstructionData`. Do not use until the on-chain handler is deployed.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [] Slab\r\n * 2. [writable] Creator history PDA\r\n * 3. [writable] Insurance vault\r\n * 4. [writable] Treasury\r\n * 5. [] System program\r\n *\r\n * @deprecated Not yet implemented on-chain — will fail with InvalidInstructionData.\r\n */\r\nexport function encodeSlashCreationDeposit(): Uint8Array {\r\n return removedInstruction(\"SlashCreationDeposit\", IX_TAG.SlashCreationDeposit);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-628: Elastic Shared Vault + Epoch Withdrawals\r\n// ============================================================================\r\n\r\n/**\r\n * InitSharedVault (Tag 59) — admin: create the global shared vault PDA (PERC-628).\r\n *\r\n * Instruction data: tag(1) + epochDurationSlots(8) + maxMarketExposureBps(2) = 11 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [writable] Shared vault PDA\r\n * 2. [] System program\r\n */\r\nexport interface InitSharedVaultArgs {\r\n epochDurationSlots: bigint | string;\r\n maxMarketExposureBps: number;\r\n}\r\n\r\n/** @deprecated v12.x InitSharedVault (old tag 94). Not in v17. */\r\nexport function encodeInitSharedVault(_args: InitSharedVaultArgs): Uint8Array {\r\n return removedInstruction(\"InitSharedVault (v12 tag 94 — not in v17)\", IX_TAG.InitSharedVault, undefined);\r\n}\r\n\r\n/**\r\n * AllocateMarket (Tag 60) — admin: allocate virtual liquidity from the shared vault\r\n * to a market (PERC-628).\r\n *\r\n * Instruction data: tag(1) + amount(16) = 17 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] Admin\r\n * 1. [] Slab\r\n * 2. [writable] Shared vault PDA\r\n * 3. [writable] Market alloc PDA\r\n * 4. [] System program\r\n */\r\nexport interface AllocateMarketArgs {\r\n amount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x AllocateMarket (old tag 95). Not in v17. */\r\nexport function encodeAllocateMarket(_args: AllocateMarketArgs): Uint8Array {\r\n return removedInstruction(\"AllocateMarket (v12 tag 95 — not in v17)\", IX_TAG.AllocateMarket, undefined);\r\n}\r\n\r\n/**\r\n * QueueWithdrawalSV (Tag 61) — user: queue a withdrawal request for the current\r\n * epoch (PERC-628). Tokens are locked until the epoch elapses.\r\n *\r\n * Instruction data: tag(1) + lpAmount(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] System program\r\n */\r\nexport interface QueueWithdrawalSVArgs {\r\n lpAmount: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x QueueWithdrawalSV (old tag 96). Not in v17. */\r\nexport function encodeQueueWithdrawalSV(_args: QueueWithdrawalSVArgs): Uint8Array {\r\n return removedInstruction(\"QueueWithdrawalSV (v12 tag 96 — not in v17)\", IX_TAG.QueueWithdrawalSV, undefined);\r\n}\r\n\r\n/**\r\n * ClaimEpochWithdrawal (Tag 62) — user: claim a queued withdrawal after the epoch\r\n * has elapsed (PERC-628). Receives pro-rata collateral from the vault.\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] User\r\n * 1. [writable] Shared vault PDA\r\n * 2. [writable] Withdraw request PDA\r\n * 3. [] Slab\r\n * 4. [writable] Vault\r\n * 5. [writable] User ATA\r\n * 6. [] Vault authority\r\n * 7. [] Token program\r\n */\r\n/** @deprecated v12.x ClaimEpochWithdrawal (old tag 97). Not in v17. */\r\nexport function encodeClaimEpochWithdrawal(): Uint8Array {\r\n return removedInstruction(\"ClaimEpochWithdrawal (v12 tag 97 — not in v17)\", IX_TAG.ClaimEpochWithdrawal, undefined);\r\n}\r\n\r\n/**\r\n * AdvanceEpoch (Tag 63) — permissionless crank: move the shared vault to the next\r\n * epoch once `epoch_duration_slots` have elapsed (PERC-628).\r\n *\r\n * Instruction data: 1 byte (tag only)\r\n *\r\n * Accounts:\r\n * 0. [signer] Caller (anyone)\r\n * 1. [writable] Shared vault PDA\r\n */\r\n/** @deprecated v12.x AdvanceEpoch (old tag 98). Not in v17. */\r\nexport function encodeAdvanceEpoch(): Uint8Array {\r\n return removedInstruction(\"AdvanceEpoch (v12 tag 98 — not in v17)\", IX_TAG.AdvanceEpoch, undefined);\r\n}\r\n\r\n// PERC-628: Tag 63 ─────────────────────────────────────────────────────────\r\n\r\n// PERC-8110 ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SetOiImbalanceHardBlock (Tag 71, PERC-8110) — set OI imbalance hard-block threshold (admin only).\r\n *\r\n * When `|long_oi − short_oi| / total_oi * 10_000 >= threshold_bps`, any new trade that would\r\n * *increase* the imbalance is rejected with `OiImbalanceHardBlock` (error code 59).\r\n *\r\n * - `threshold_bps = 0`: hard block disabled.\r\n * - `threshold_bps = 8_000`: block trades that push skew above 80%.\r\n * - `threshold_bps = 10_000`: never allow >100% skew (always blocks one side when oi > 0).\r\n *\r\n * Instruction data layout: tag(1) + threshold_bps(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK, { admin, slab }),\r\n * data: Buffer.from(encodeSetOiImbalanceHardBlock({ thresholdBps: 8_000 })),\r\n * });\r\n * ```\r\n */\r\n/** @deprecated v12.x SetOiImbalanceHardBlock (old tag 71). Not in v17. */\r\nexport function encodeSetOiImbalanceHardBlock(_args: { thresholdBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOiImbalanceHardBlock (v12 tag 71 — not in v17)\", IX_TAG.SetOiImbalanceHardBlock, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// PERC-608 — Position NFT instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft (Tag 64, PERC-608) — mint a Token-2022 NFT representing a position.\r\n *\r\n * Creates a PositionNft PDA + Token-2022 mint with metadata, then mints 1 NFT to the\r\n * position owner's ATA. The NFT represents ownership of `user_idx` in the slab.\r\n *\r\n * The program creates the ATA internally via CPI when the 11th account (Associated Token\r\n * Program) is provided. This is required because the NFT mint PDA doesn't exist until the\r\n * program creates it, so the ATA can't be created in a preceding instruction.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts (11):\r\n * 0. [signer, writable] payer\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (created — seeds: [\"position_nft\", slab, user_idx_u16_le])\r\n * 3. [writable] nft_mint PDA (created — seeds: [\"position_nft_mint\", slab, user_idx_u16_le])\r\n * 4. [writable] owner_ata (Token-2022 ATA for nft_mint — created by program if absent)\r\n * 5. [signer] owner (must match engine account owner)\r\n * 6. [] vault_authority PDA (seeds: [\"vault\", slab])\r\n * 7. [] token_2022_program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)\r\n * 8. [] system_program\r\n * 9. [] rent sysvar\r\n * 10. [] associated_token_program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)\r\n */\r\nexport interface MintPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x MintPositionNft (old tag 64). v17 reuses tag 64 for ForceCloseAbandonedAsset.\r\n * NFT operations in v17 use the standalone percolator-nft program; use SetNftProgramId(73)\r\n * to register it and TransferPortfolioOwnership(72) for B-3 transfers.\r\n */\r\nexport function encodeMintPositionNft(_args: MintPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"MintPositionNft (v12 tag 64 — COLLIDES with v17 ForceCloseAbandonedAsset)\",\r\n IX_TAG.MintPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferPositionOwnership (Tag 65, PERC-608) — transfer an open position to a new owner.\r\n *\r\n * Transfers the Token-2022 NFT from current owner to new owner and updates the on-chain\r\n * engine account's owner field. Requires `pending_settlement == 0`.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] current_owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA\r\n * 3. [writable] nft_mint PDA\r\n * 4. [writable] current_owner_ata (source Token-2022 ATA)\r\n * 5. [writable] new_owner_ata (destination Token-2022 ATA)\r\n * 6. [] new_owner\r\n * 7. [] token_2022_program\r\n */\r\nexport interface TransferPositionOwnershipArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferPositionOwnership (old tag 65). v17 reuses tag 65 for UpdateAssetAuthority.\r\n * Use encodeTransferPortfolioOwnership() (tag 72) for B-3 ownership transfer in v17.\r\n */\r\nexport function encodeTransferPositionOwnership(_args: TransferPositionOwnershipArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferPositionOwnership (v12 tag 65 — COLLIDES with v17 UpdateAssetAuthority)\",\r\n IX_TAG.TransferPositionOwnership,\r\n \"encodeTransferPortfolioOwnership() (tag 72)\",\r\n );\r\n}\r\n\r\n/**\r\n * BurnPositionNft (Tag 66, PERC-608) — burn the Position NFT when a position is closed.\r\n *\r\n * Burns the NFT, closes the PositionNft PDA and the mint PDA, returning rent to the owner.\r\n * Can only be called after the position is fully closed (size == 0).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer, writable] owner\r\n * 1. [writable] slab\r\n * 2. [writable] position_nft PDA (closed — rent to owner)\r\n * 3. [writable] nft_mint PDA (closed via Token-2022 close_account)\r\n * 4. [writable] owner_ata (Token-2022 ATA, balance burned)\r\n * 5. [] vault_authority PDA\r\n * 6. [] token_2022_program\r\n */\r\nexport interface BurnPositionNftArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x BurnPositionNft (old tag 66). v17 reuses tag 66 for BatchTradeNoCpi.\r\n * NFT burn is handled by the standalone percolator-nft program in v17.\r\n */\r\nexport function encodeBurnPositionNft(_args: BurnPositionNftArgs): Uint8Array {\r\n return removedInstruction(\r\n \"BurnPositionNft (v12 tag 66 — COLLIDES with v17 BatchTradeNoCpi)\",\r\n IX_TAG.BurnPositionNft,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * SetPendingSettlement (Tag 67, PERC-608) — keeper sets the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin before performing a funding settlement transfer.\r\n * Blocks NFT transfers until ClearPendingSettlement is called.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface SetPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetPendingSettlement (old tag 67). v17 reuses tag 67 for BatchTradeCpi.\r\n */\r\nexport function encodeSetPendingSettlement(_args: SetPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetPendingSettlement (v12 tag 67 — COLLIDES with v17 BatchTradeCpi)\",\r\n IX_TAG.SetPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * ClearPendingSettlement (Tag 68, PERC-608) — keeper clears the pending_settlement flag.\r\n *\r\n * Called by the keeper/admin after KeeperCrank has run and funding is settled.\r\n * Admin-only (protected by GH#1475 keeper allowlist guard).\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) = 3 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] keeper / admin\r\n * 1. [] slab (read — for PDA verification + admin check)\r\n * 2. [writable] position_nft PDA\r\n */\r\nexport interface ClearPendingSettlementArgs {\r\n userIdx: number;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ClearPendingSettlement (old tag 68). v17 reuses tag 68 for SetMatcherConfig.\r\n */\r\nexport function encodeClearPendingSettlement(_args: ClearPendingSettlementArgs): Uint8Array {\r\n return removedInstruction(\r\n \"ClearPendingSettlement (v12 tag 68 — COLLIDES with v17 SetMatcherConfig)\",\r\n IX_TAG.ClearPendingSettlement,\r\n \"percolator-nft program\",\r\n );\r\n}\r\n\r\n/**\r\n * TransferOwnershipCpi (Tag 69, PERC-608) — internal CPI target for percolator-nft TransferHook.\r\n *\r\n * Called by the Token-2022 TransferHook on the percolator-nft program during an NFT transfer.\r\n * Updates the engine account's owner field to the new_owner public key.\r\n * NOT intended for direct external use — always called via Token-2022 CPI.\r\n *\r\n * Instruction data layout: tag(1) + user_idx(2) + new_owner(32) = 35 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] nft TransferHook program (CPI caller)\r\n * 1. [writable] slab\r\n * (remaining accounts per Token-2022 ExtraAccountMeta spec)\r\n */\r\nexport interface TransferOwnershipCpiArgs {\r\n userIdx: number;\r\n newOwner: PublicKey | string;\r\n}\r\n\r\n/**\r\n * @deprecated v12.x TransferOwnershipCpi (old tag 69). v17 reuses tag 69 for RestartAssetOracle.\r\n */\r\nexport function encodeTransferOwnershipCpi(_args: TransferOwnershipCpiArgs): Uint8Array {\r\n return removedInstruction(\r\n \"TransferOwnershipCpi (v12 tag 69 — COLLIDES with v17 RestartAssetOracle)\",\r\n IX_TAG.TransferOwnershipCpi,\r\n \"percolator-nft transfer hook\",\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// PERC-8111 — SetWalletCap (tag 70)\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap (Tag 70, PERC-8111) — set the per-wallet position cap (admin only).\r\n *\r\n * Limits the maximum absolute position size any single wallet may hold on this market.\r\n * Enforced on every trade (TradeNoCpi + TradeCpi) after execute_trade.\r\n *\r\n * - `capE6 = 0`: disable per-wallet cap (no limit, default).\r\n * - `capE6 > 0`: max |position_size| in e6 units ($1 = 1_000_000).\r\n * Phase 1 launch value: 1_000_000_000n ($1,000).\r\n *\r\n * When a trade would breach the cap, the on-chain error `WalletPositionCapExceeded`\r\n * (error code 58) is returned.\r\n *\r\n * Instruction data layout: tag(1) + cap_e6(8) = 9 bytes\r\n *\r\n * Accounts:\r\n * 0. [signer] admin\r\n * 1. [writable] slab\r\n *\r\n * @example\r\n * ```ts\r\n * // Set $1K per-wallet cap\r\n * const ix = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 1_000_000_000n })),\r\n * });\r\n *\r\n * // Disable cap\r\n * const disableIx = new TransactionInstruction({\r\n * programId: PROGRAM_ID,\r\n * keys: buildAccountMetas(ACCOUNTS_SET_WALLET_CAP, [admin, slab]),\r\n * data: Buffer.from(encodeSetWalletCap({ capE6: 0n })),\r\n * });\r\n * ```\r\n */\r\nexport interface SetWalletCapArgs {\r\n /** Max position size in e6 units. 0 = disabled. $1 = 1_000_000n, $1K = 1_000_000_000n. */\r\n capE6: bigint | string;\r\n}\r\n\r\n/** @deprecated v12.x SetWalletCap (old tag 70). Not in v17. */\r\nexport function encodeSetWalletCap(_args: SetWalletCapArgs): Uint8Array {\r\n return removedInstruction(\"SetWalletCap (v12 tag 70 — not in v17)\", IX_TAG.SetWalletCap, undefined);\r\n}\r\n\r\n// ============================================================================\r\n// InitMatcherCtx — bootstrap matcher context via wrapper CPI to matcher program (tag 83)\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83) — LP owner bootstraps the matcher context account by invoking\r\n * the wrapper, which CPIs to the matcher program signing as the matcher_delegate PDA.\r\n *\r\n * v17 wire: tag(1=83) + kind(u8) + trading_fee_bps(u32 LE) + base_spread_bps(u32 LE) +\r\n * max_total_bps(u32 LE) + impact_k_bps(u32 LE) + liquidity_notional_e6(u128 LE) +\r\n * max_fill_abs(u128 LE) + max_inventory_abs(u128 LE) + fee_to_insurance_bps(u16 LE) +\r\n * skew_spread_mult_bps(u16 LE) = 70 bytes total.\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called FIRST. The wrapper's\r\n * handler reads the LP portfolio's stored matcher config and verifies that:\r\n * cfg.matcher_program == matcherProg\r\n * cfg.matcher_context == matcherCtx\r\n * cfg.matcher_delegate == matcherDelegate (derived via deriveMatcherDelegate())\r\n *\r\n * The wrapper calls derive_matcher_delegate and invoke_signed so the delegate PDA acts\r\n * as a signer in the matcher CPI — this is what satisfies the matcher's lp_pda.is_signer\r\n * check on the deployed binary. No client-side signer of the delegate is needed.\r\n *\r\n * Accounts (per handle_init_matcher_ctx in deployed wrapper, tag 83):\r\n * [0] lp_owner signer (LP portfolio owner)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lp_portfolio read-only (LP's portfolio; must have provenance matching market + owner)\r\n * [3] matcher_ctx writable (320-byte account owned by matcher program)\r\n * [4] matcher_prog read-only, executable (the matcher program)\r\n * [5] matcher_delegate read-only (PDA derived by deriveMatcherDelegate; wrapper signs for it)\r\n *\r\n * @param args.kind 0=Passive, 1=vAMM\r\n * @param args.tradingFeeBps Base trading fee in bps (u32, e.g. 30)\r\n * @param args.baseSpreadBps Base spread in bps (u32)\r\n * @param args.maxTotalBps Max total spread in bps (u32)\r\n * @param args.impactKBps vAMM price impact constant in bps (u32; 0 for Passive)\r\n * @param args.liquidityNotionalE6 Liquidity notional in e6 units (u128; 0 for Passive)\r\n * @param args.maxFillAbs Max single fill in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.maxInventoryAbs Max inventory in absolute units (u128; use i128::MAX for unlimited)\r\n * @param args.feeToInsuranceBps Fraction of fees to insurance in bps (u16)\r\n * @param args.skewSpreadMultBps Skew spread multiplier in bps (u16; 0=disabled)\r\n *\r\n * Confirmed live on the deployed wrapper (percolator-prog@e26c97a4) at tag 83 by\r\n * forensic rebuild + live simulateTransaction (see ~/v17/DECISIONS-LEDGER.md,\r\n * \"Pinned deployed revisions\", 2026-07-15). The v17 protocol-fee instructions\r\n * were renumbered (WithdrawProtocolFee=84, SetProtocolFeeAuthority=85) to keep\r\n * this tag free.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeInitMatcherCtx({\r\n * kind: 0, // Passive\r\n * tradingFeeBps: 30,\r\n * baseSpreadBps: 50,\r\n * maxTotalBps: 200,\r\n * impactKBps: 0,\r\n * liquidityNotionalE6: 0n,\r\n * maxFillAbs: 170141183460469231731687303715884105727n, // i128::MAX\r\n * maxInventoryAbs: 170141183460469231731687303715884105727n,\r\n * feeToInsuranceBps: 0,\r\n * skewSpreadMultBps: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface InitMatcherCtxArgs {\r\n /**\r\n * @deprecated lpIdx is not present in the v17 wire format. The wrapper derives the LP\r\n * info from the lp_portfolio account (accounts[2]). This field is ignored if provided.\r\n */\r\n lpIdx?: number;\r\n /** Matcher kind: 0=Passive, 1=vAMM. */\r\n kind: number;\r\n /** Base trading fee in bps (u32, e.g. 30 = 0.30%). */\r\n tradingFeeBps: number;\r\n /** Base spread in bps (u32). */\r\n baseSpreadBps: number;\r\n /** Max total spread in bps (u32). */\r\n maxTotalBps: number;\r\n /** vAMM price impact constant in bps (u32). Use 0 for Passive kind. */\r\n impactKBps: number;\r\n /** Liquidity notional in e6 units (u128). Use 0n for Passive kind. */\r\n liquidityNotionalE6: bigint | string;\r\n /** Max single fill size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit (i128::MAX). */\r\n maxFillAbs: bigint | string;\r\n /** Max inventory size in absolute units (u128). Use 170141183460469231731687303715884105727n for no limit. */\r\n maxInventoryAbs: bigint | string;\r\n /** Fraction of fees routed to insurance fund in bps (u16). */\r\n feeToInsuranceBps: number;\r\n /** Skew spread multiplier in bps (u16). 0 = disabled. */\r\n skewSpreadMultBps: number;\r\n}\r\n\r\n/** Wire length of InitMatcherCtx instruction payload (tag + 10 fields). */\r\nexport const INIT_MATCHER_CTX_V17_LEN = 70;\r\n\r\n/**\r\n * Encode InitMatcherCtx instruction data (v17 wire format, tag 83).\r\n *\r\n * Sends to the WRAPPER program (not the matcher directly). The wrapper CPIs the matcher\r\n * via invoke_signed, making the delegate PDA a signer in the matcher's process_init call.\r\n *\r\n * @param args InitMatcherCtxArgs (lpIdx field ignored in v17)\r\n * @returns 70-byte Uint8Array\r\n */\r\nexport function encodeInitMatcherCtx(args: InitMatcherCtxArgs): Uint8Array {\r\n const data = concatBytes(\r\n encU8(83), // IX_TAG.InitMatcherCtx = 83\r\n encU8(args.kind),\r\n new Uint8Array(new Uint32Array([args.tradingFeeBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.baseSpreadBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.maxTotalBps]).buffer), // u32 LE\r\n new Uint8Array(new Uint32Array([args.impactKBps]).buffer), // u32 LE\r\n encU128(args.liquidityNotionalE6), // u128 LE\r\n encU128(args.maxFillAbs), // u128 LE\r\n encU128(args.maxInventoryAbs), // u128 LE\r\n encU16(args.feeToInsuranceBps), // u16 LE\r\n encU16(args.skewSpreadMultBps), // u16 LE\r\n );\r\n if (data.length !== INIT_MATCHER_CTX_V17_LEN) {\r\n throw new Error(\r\n `encodeInitMatcherCtx: expected ${INIT_MATCHER_CTX_V17_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n return data;\r\n}\r\n\r\n// ============================================================================\r\n// Missing encoders — corrected tag mappings (tags 22-74)\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetInsuranceWithdrawPolicy (old tag 22). Not in v17.\r\n */\r\nexport interface SetInsuranceWithdrawPolicyArgs {\r\n authority: PublicKey | string;\r\n minWithdrawBase: bigint | string;\r\n maxWithdrawBps: number;\r\n cooldownSlots: bigint | string;\r\n}\r\nexport function encodeSetInsuranceWithdrawPolicy(_args: SetInsuranceWithdrawPolicyArgs): Uint8Array {\r\n return removedInstruction(\"SetInsuranceWithdrawPolicy (v12 tag 22 — not in v17)\", IX_TAG.SetInsuranceWithdrawPolicy, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x WithdrawInsuranceLimited (old tag 23). v17 uses tag 23 for WithdrawInsuranceLimited (same tag, different meaning — verify wire before using).\r\n */\r\nexport function encodeWithdrawInsuranceLimited(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLimited (v12 tag 23 — verify v17 wire before use)\", IX_TAG.WithdrawInsuranceLimited, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ResolvePermissionless (old tag 29). v17 uses tag 39 for ResolveStalePermissionless.\r\n */\r\nexport function encodeResolvePermissionless(): Uint8Array {\r\n return removedInstruction(\r\n \"ResolvePermissionless (v12 tag 29 — use ResolveStalePermissionless(39) in v17)\",\r\n IX_TAG.ResolvePermissionless,\r\n \"encodeResolveStalePermissionless()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ForceCloseResolved (old tag 30) is NOT CloseResolved in v17.\r\n * v17 reuses tag 30 for CloseResolved with a completely different wire format.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport function encodeForceCloseResolved(_args: { userIdx: number }): Uint8Array {\r\n return removedInstruction(\r\n \"ForceCloseResolved\",\r\n IX_TAG.ForceCloseResolved,\r\n \"encodeCloseResolved() for v17\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x CreateLpVault wire format. Use encodeCreateLpVaultV17() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeCreateLpVault(args: { feeShareBps: bigint | string; utilCurveEnabled?: boolean }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeCreateLpVault (v12 format)\",\r\n IX_TAG.CreateLpVault,\r\n \"encodeCreateLpVaultV17()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x LpVaultDeposit wire format. Use encodeDepositToLpVault() for v17.\r\n * This is kept for source-compat only — the v12 wire format will be rejected by v17.\r\n */\r\nexport function encodeLpVaultDeposit(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"encodeLpVaultDeposit (v12 format)\",\r\n IX_TAG.LpVaultDeposit,\r\n \"encodeDepositToLpVault()\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x ChallengeSettlement. v17 reuses tag 43 for ForfeitRecoveryLeg.\r\n */\r\nexport function encodeChallengeSettlement(_args: { proposedPriceE6: bigint | string }): Uint8Array {\r\n return removedInstruction(\r\n \"ChallengeSettlement\",\r\n IX_TAG.ChallengeSettlement,\r\n undefined,\r\n );\r\n}\r\n\r\n/** @deprecated v12.x ResolveDispute. v17 reuses tag 44 for RebalanceReduce. */\r\nexport function encodeResolveDispute(_args: { accept: number }): Uint8Array {\r\n return removedInstruction(\"ResolveDispute\", IX_TAG.ResolveDispute, undefined);\r\n}\r\n\r\n/** @deprecated v12.x DepositLpCollateral. v17 reuses tag 45 for FinalizeResetSide. */\r\nexport function encodeDepositLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositLpCollateral\", IX_TAG.DepositLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x WithdrawLpCollateral. v17 reuses tag 46 for ClaimResolvedPayoutTopup. */\r\nexport function encodeWithdrawLpCollateral(_args: { userIdx: number; lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawLpCollateral\", IX_TAG.WithdrawLpCollateral, undefined);\r\n}\r\n\r\n/** @deprecated v12.x SetOffsetPair. v17 reuses tag 54 for SyncInsuranceLedger. */\r\nexport function encodeSetOffsetPair(_args: { offsetBps: number }): Uint8Array {\r\n return removedInstruction(\"SetOffsetPair\", IX_TAG.SetOffsetPair, undefined);\r\n}\r\n\r\n/** @deprecated v12.x AttestCrossMargin. v17 reuses tag 55 for UpdateTradeFeePolicy. */\r\nexport function encodeAttestCrossMargin(_args: { userIdxA: number; userIdxB: number }): Uint8Array {\r\n return removedInstruction(\"AttestCrossMargin\", IX_TAG.AttestCrossMargin, undefined);\r\n}\r\n\r\n/** @deprecated v12.x RescueOrphanVault. v17 reuses tag 72 for TransferPortfolioOwnership. */\r\nexport function encodeRescueOrphanVault(): Uint8Array {\r\n return removedInstruction(\"RescueOrphanVault\", IX_TAG.RescueOrphanVault, \"encodeTransferPortfolioOwnership()\");\r\n}\r\n\r\n/** @deprecated v12.x CloseOrphanSlab. v17 reuses tag 73 for SetNftProgramId. */\r\nexport function encodeCloseOrphanSlab(): Uint8Array {\r\n return removedInstruction(\"CloseOrphanSlab\", IX_TAG.CloseOrphanSlab, \"encodeSetNftProgramId()\");\r\n}\r\n\r\n/** @deprecated v12.x SetDexPool. v17 reuses tag 74 for CreateLpVault. */\r\nexport function encodeSetDexPool(_args: { pool: PublicKey | string }): Uint8Array {\r\n return removedInstruction(\"SetDexPool\", IX_TAG.SetDexPool, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeCreateInsuranceMint(): Uint8Array {\r\n return removedInstruction(\"CreateInsuranceMint (v12 alias)\", IX_TAG.CreateLpVault, \"encodeCreateLpVaultV17()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeDepositInsuranceLP(_args: { amount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"DepositInsuranceLP (v12 alias)\", IX_TAG.DepositToLpVault, \"encodeDepositToLpVault()\");\r\n}\r\n\r\n/** @deprecated v12.x Insurance LP alias — removed in v17. */\r\nexport function encodeWithdrawInsuranceLP(_args: { lpAmount: bigint | string }): Uint8Array {\r\n return removedInstruction(\"WithdrawInsuranceLP (v12 alias)\", IX_TAG.RequestRedeemLpShares, \"encodeRequestRedeemLpShares()\");\r\n}\r\n\r\n// ============================================================================\r\n// Phase B admin setters (tags 78-81) — added 2026-04-17\r\n// Wire up MarketConfig fields added in prog Phase A. Admin-only, validated.\r\n// Accounts for all 4: [admin(signer), slab(writable)] (2 accounts).\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x SetMaxPnlCap (old tag 78). v17 reuses tag 78 for LpVaultCrankFees.\r\n * This function throws at runtime to prevent silent on-chain mismatch.\r\n */\r\nexport interface SetMaxPnlCapArgs {\r\n cap: bigint | string;\r\n}\r\n\r\nexport function encodeSetMaxPnlCap(_args: SetMaxPnlCapArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetMaxPnlCap (v12 tag 78 — now LpVaultCrankFees in v17)\",\r\n IX_TAG.SetMaxPnlCap,\r\n \"encodeLpVaultCrankFees() [if you meant v17] or no equivalent\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetOiCapMultiplier (old tag 79). v17 reuses tag 79 for SetLpVaultPaused.\r\n */\r\nexport interface SetOiCapMultiplierArgs {\r\n packed: bigint | string;\r\n}\r\n\r\nexport function encodeSetOiCapMultiplier(_args: SetOiCapMultiplierArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetOiCapMultiplier (v12 tag 79 — now SetLpVaultPaused in v17)\",\r\n IX_TAG.SetOiCapMultiplier,\r\n \"encodeSetLpVaultPaused() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/** @deprecated v12.x helper — kept for legacy callers that use packOiCap(). */\r\nexport function packOiCap(multiplierBps: number, softCapBps: number): bigint {\r\n if (multiplierBps < 0 || multiplierBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: multiplier_bps out of u32 range: ${multiplierBps}`);\r\n }\r\n if (softCapBps < 0 || softCapBps > 0xFFFF_FFFF) {\r\n throw new Error(`packOiCap: soft_cap_bps out of u32 range: ${softCapBps}`);\r\n }\r\n return BigInt(multiplierBps) | (BigInt(softCapBps) << 32n);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetDisputeParams (old tag 80). v17 reuses tag 80 for CloseLpVault.\r\n */\r\nexport interface SetDisputeParamsArgs {\r\n windowSlots: bigint | string;\r\n bondAmount: bigint | string;\r\n}\r\n\r\nexport function encodeSetDisputeParams(_args: SetDisputeParamsArgs): Uint8Array {\r\n return removedInstruction(\r\n \"SetDisputeParams (v12 tag 80 — now CloseLpVault in v17)\",\r\n IX_TAG.SetDisputeParams,\r\n \"encodeCloseLpVault() [if you meant v17]\",\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SetLpCollateralParams (old tag 81). Not in v17.\r\n */\r\nexport interface SetLpCollateralParamsArgs {\r\n enabled: number;\r\n ltvBps: number;\r\n}\r\n\r\nexport function encodeSetLpCollateralParams(_args: SetLpCollateralParamsArgs): Uint8Array {\r\n return removedInstruction(\"SetLpCollateralParams (v12 tag 81 — not in v17)\", IX_TAG.SetLpCollateralParams, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x AcceptAdmin (old tag 82). v17 uses UpdateAuthority(32) for admin rotation.\r\n */\r\nexport function encodeAcceptAdmin(): Uint8Array {\r\n return removedInstruction(\"AcceptAdmin (v12 tag 82 — not in v17)\", IX_TAG.AcceptAdmin, \"encodeUpdateAuthority()\");\r\n}\r\n\r\n// ============================================================================\r\n// G-3 fixes (audit-2026-04-27): missing per-account encoders for tags 25-28.\r\n// Wrapper handlers exist at src/percolator.rs:2088, 2092, 2097, 2103.\r\n// ============================================================================\r\n\r\n/**\r\n * @deprecated v12.x ReclaimEmptyAccount (old tag 85). Not in v17.\r\n */\r\nexport interface ReclaimEmptyAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeReclaimEmptyAccount(_args: ReclaimEmptyAccountArgs): Uint8Array {\r\n return removedInstruction(\"ReclaimEmptyAccount (v12 tag 85 — not in v17)\", IX_TAG.ReclaimEmptyAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x SettleAccount (old tag 86). Not in v17.\r\n */\r\nexport interface SettleAccountArgs {\r\n userIdx: number;\r\n}\r\n\r\nexport function encodeSettleAccount(_args: SettleAccountArgs): Uint8Array {\r\n return removedInstruction(\"SettleAccount (v12 tag 86 — not in v17)\", IX_TAG.SettleAccount, undefined);\r\n}\r\n\r\n/**\r\n * @deprecated v12.x DepositFeeCredits (old tag 27). Not in v17.\r\n */\r\nexport interface DepositFeeCreditsArgs {\r\n userIdx: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeDepositFeeCredits(_args: DepositFeeCreditsArgs): Uint8Array {\r\n return removedInstruction(\"DepositFeeCredits (v12 tag 27 — not in v17)\", IX_TAG.DepositFeeCredits, undefined);\r\n}\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28) — voluntary PnL conversion with open position.\r\n * Owner only.\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: userIdx(u16) removed; amount promoted u64→u128.\r\n * The v17 decoder at tag 28 reads `amount: read_u128(&mut rest)?` — the\r\n * old 2-byte userIdx is consumed as the first 2 bytes of the u128, then\r\n * only 8 bytes remain for the u128 tail (14 bytes short). Every call fails\r\n * with InvalidInstructionData. Also, `userIdx` is stale — v17 portfolios\r\n * are identified by account key alone.\r\n *\r\n * Accounts: see ACCOUNTS_CONVERT_RELEASED_PNL.\r\n *\r\n * @param amount Amount of released PnL to convert (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConvertReleasedPnl({ amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface ConvertReleasedPnlArgs {\r\n /** @deprecated userIdx is not needed in v17 — portfolios are identified by account key. */\r\n userIdx?: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeConvertReleasedPnl(args: ConvertReleasedPnlArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ConvertReleasedPnl),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// G-2 fix (audit-2026-04-27): UpdateAuthority (tag 83). v12.18.x 4-way split.\r\n// Wrapper: src/percolator.rs:6876 (handler), 2140-2146 (decode).\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateAuthority (tag 32) — rotate the single market-level authority (marketauth).\r\n *\r\n * v17 wire: tag(1) + new_pubkey[32] = 33 bytes.\r\n *\r\n * BREAKING vs v12.18.x: the kind byte is REMOVED. Tag 32 now ONLY rotates\r\n * marketauth. Per-asset authority rotation uses tag 65 (UpdateAssetAuthority).\r\n * Burning marketauth to zero is rejected on-chain.\r\n *\r\n * Accounts: [currentAuth(signer), newAuth(signer), slab(writable)]\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateAuthority({ newPubkey: newAdminKey });\r\n * ```\r\n */\r\nexport interface UpdateAuthorityArgs {\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAuthority(args: UpdateAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAuthority),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — UpdateAssetAuthority (tag 65)\r\n// ============================================================================\r\n\r\n/**\r\n * Per-asset authority kind for UpdateAssetAuthority (tag 65).\r\n *\r\n * Exact mapping from v16_program.rs lines 5246-5250:\r\n * ASSET_AUTH_ADMIN = 0 → AssetAdmin\r\n * ASSET_AUTH_INSURANCE = 1 → Insurance\r\n * ASSET_AUTH_INSURANCE_OPERATOR = 2 → InsuranceOperator\r\n * ASSET_AUTH_BACKING_BUCKET = 3 → BackingBucket\r\n * ASSET_AUTH_ORACLE = 4 → Oracle\r\n *\r\n * CRITICAL: the kind byte is sent on-chain and routes to a specific authority\r\n * slot. Wrong values silently corrupt authority state:\r\n * - Calling with kind=Insurance(1) rotates `insurance_authority` (correct).\r\n * - Calling with the OLD wrong value 0 for Insurance hits `asset_admin` slot,\r\n * corrupting the market-level admin key instead.\r\n *\r\n * Stake program uses kind=AssetAdmin(0) targeting asset_index=0 to bind\r\n * the stake vault PDA into the asset_admin authority slot.\r\n */\r\nexport const ASSET_AUTH_KIND = {\r\n /** ASSET_AUTH_ADMIN = 0 in v16_program.rs:5246 — routes to asset_admin field */\r\n AssetAdmin: 0,\r\n /** ASSET_AUTH_INSURANCE = 1 in v16_program.rs:5247 — routes to insurance_authority field */\r\n Insurance: 1,\r\n /** ASSET_AUTH_INSURANCE_OPERATOR = 2 in v16_program.rs:5248 — routes to insurance_operator field */\r\n InsuranceOperator: 2,\r\n /** ASSET_AUTH_BACKING_BUCKET = 3 in v16_program.rs:5249 — routes to backing_bucket_authority field */\r\n BackingBucket: 3,\r\n /** ASSET_AUTH_ORACLE = 4 in v16_program.rs:5250 — routes to oracle_authority field */\r\n Oracle: 4,\r\n} as const;\r\nObject.freeze(ASSET_AUTH_KIND);\r\n\r\nexport type AssetAuthKind = (typeof ASSET_AUTH_KIND)[keyof typeof ASSET_AUTH_KIND];\r\n\r\n/**\r\n * UpdateAssetAuthority (tag 65) — rotate a per-asset authority.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + kind(u8) + new_pubkey[32] = 36 bytes.\r\n *\r\n * Gated by the asset's own asset_admin (can rotate any) or by the current\r\n * holder of that authority (self-rotation). Isolated to the given asset_index.\r\n *\r\n * @param assetIndex Asset index (0 = primary, 1+ = additional assets).\r\n * @param kind ASSET_AUTH_KIND.* constant.\r\n * @param newPubkey New authority pubkey. Zero = burn (only AssetAdmin on asset!=0).\r\n *\r\n * @example\r\n * ```ts\r\n * // Rotate insurance authority for asset 0\r\n * // ASSET_AUTH_KIND.Insurance = 1 (routes to insurance_authority slot on-chain)\r\n * const data = encodeUpdateAssetAuthority({\r\n * assetIndex: 0,\r\n * kind: ASSET_AUTH_KIND.Insurance,\r\n * newPubkey: newInsuranceKey,\r\n * });\r\n * ```\r\n */\r\nexport interface UpdateAssetAuthorityArgs {\r\n assetIndex: number;\r\n kind: AssetAuthKind;\r\n newPubkey: PublicKey | string;\r\n}\r\n\r\nexport function encodeUpdateAssetAuthority(args: UpdateAssetAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateAssetAuthority),\r\n encU16(args.assetIndex),\r\n encU8(args.kind),\r\n encPubkey(args.newPubkey),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — BatchTradeNoCpi (tag 66) + BatchTradeCpi (tag 67)\r\n// ============================================================================\r\n\r\n/**\r\n * One leg of a BatchTradeNoCpi instruction.\r\n */\r\nexport interface BatchTradeNoCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n execPrice: bigint | string;\r\n feeBps: bigint | string;\r\n}\r\n\r\n/**\r\n * BatchTradeNoCpi (tag 66) — multi-leg NoCpi batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + exec_price(u64) + fee_bps(u64)]×n\r\n *\r\n * @param legs Array of up to 255 trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeNoCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, execPrice: 50_000_000_000n, feeBps: 30n },\r\n * { assetIndex: 1, sizeQ: -500_000n, execPrice: 40_000_000_000n, feeBps: 30n },\r\n * ]});\r\n * ```\r\n */\r\nexport interface BatchTradeNoCpiArgs {\r\n legs: BatchTradeNoCpiLeg[];\r\n}\r\n\r\nfunction validateBatchTradeFeeBps(value: bigint | string, caller: string): void {\r\n const feeBps = typeof value === \"string\" ? BigInt(value) : value;\r\n if (feeBps > 10_000n) {\r\n throw new Error(`${caller}: feeBps must be <= 10000, got ${feeBps}`);\r\n }\r\n}\r\n\r\nexport function encodeBatchTradeNoCpi(args: BatchTradeNoCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeNoCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeNoCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeNoCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeNoCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.execPrice));\r\n parts.push(encU64(leg.feeBps));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n/**\r\n * BatchTradeCpi (tag 67) — multi-leg CPI batch trade.\r\n *\r\n * Wire: tag(1) + n_legs(u8) + [asset_index(u16) + size_q(i128) + fee_bps(u64) + limit_price(u64)]×n\r\n *\r\n * @param legs Array of up to 255 CPI trade legs.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeBatchTradeCpi({ legs: [\r\n * { assetIndex: 0, sizeQ: 1_000_000n, feeBps: 30n, limitPrice: 51_000_000_000n },\r\n * ]});\r\n * ```\r\n */\r\n\r\nexport interface BatchTradeCpiLeg {\r\n assetIndex: number;\r\n sizeQ: bigint | string;\r\n feeBps: bigint | string;\r\n limitPrice: bigint | string;\r\n}\r\n\r\nexport interface BatchTradeCpiArgs {\r\n legs: BatchTradeCpiLeg[];\r\n}\r\n\r\nexport function encodeBatchTradeCpi(args: BatchTradeCpiArgs): Uint8Array {\r\n if (args.legs.length === 0) {\r\n throw new Error(\"encodeBatchTradeCpi: at least one leg is required\");\r\n }\r\n if (args.legs.length > 255) {\r\n throw new Error(`encodeBatchTradeCpi: too many legs (${args.legs.length} > 255)`);\r\n }\r\n\r\n const parts: Uint8Array[] = [\r\n encU8(IX_TAG.BatchTradeCpi),\r\n encU8(args.legs.length),\r\n ];\r\n\r\n for (const leg of args.legs) {\r\n validateBatchTradeFeeBps(leg.feeBps, \"encodeBatchTradeCpi\");\r\n parts.push(encU16(leg.assetIndex));\r\n parts.push(encI128(leg.sizeQ));\r\n parts.push(encU64(leg.feeBps));\r\n parts.push(encU64(leg.limitPrice));\r\n }\r\n\r\n return concatBytes(...parts);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — SetMatcherConfig (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68) — enable or disable the matcher for this portfolio.\r\n *\r\n * Wire: tag(1) + enabled(u8) = 2 bytes.\r\n *\r\n * @param enabled 1 = enabled, 0 = disabled.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetMatcherConfig({ enabled: 1 });\r\n * ```\r\n */\r\nexport interface SetMatcherConfigArgs {\r\n enabled: number;\r\n}\r\n\r\nexport function encodeSetMatcherConfig(args: SetMatcherConfigArgs): Uint8Array {\r\n if (args.enabled !== 0 && args.enabled !== 1) {\r\n throw new Error(`encodeSetMatcherConfig: enabled must be 0 or 1, got ${args.enabled}`);\r\n }\r\n return concatBytes(encU8(IX_TAG.SetMatcherConfig), encU8(args.enabled));\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — RestartAssetOracle (tag 69)\r\n// ============================================================================\r\n\r\n/**\r\n * RestartAssetOracle (tag 69) — permissionless oracle restart.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_price(u64) = 20 bytes.\r\n *\r\n * Used to un-stick a stale or hung oracle. Anyone can call this.\r\n *\r\n * @param assetIndex Asset/domain index.\r\n * @param nowSlot Current slot.\r\n * @param initialPrice Initial mark price in e6 units.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRestartAssetOracle({\r\n * assetIndex: 0,\r\n * nowSlot: currentSlot,\r\n * initialPrice: 50_000_000_000n,\r\n * });\r\n * ```\r\n */\r\nexport interface RestartAssetOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialPrice: bigint | string;\r\n}\r\n\r\nexport function encodeRestartAssetOracle(args: RestartAssetOracleArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RestartAssetOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialPrice),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — WithdrawInsuranceAsset (tag 57)\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawInsuranceAsset (tag 57) — withdraw from a specific asset's insurance fund.\r\n *\r\n * Wire: tag(1) + asset_index(u16) + amount(u128) = 19 bytes.\r\n *\r\n * Replaces the v12.x gap at tag 57. Requires insurance_authority signature.\r\n * asset_index is u16 (domain u8→u16 migration in v17).\r\n *\r\n * @param assetIndex Asset/domain index (u16, not u8).\r\n * @param amount Amount to withdraw (u128).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceAsset({ assetIndex: 0, amount: 1_000_000n });\r\n * ```\r\n */\r\nexport interface WithdrawInsuranceAssetArgs {\r\n assetIndex: number;\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawInsuranceAsset(args: WithdrawInsuranceAssetArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawInsuranceAsset),\r\n encU16(args.assetIndex),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 NEW — LP-vault renumbered tags (74-80)\r\n// ============================================================================\r\n\r\n/**\r\n * CreateLpVault (tag 74) — create the LP vault for a market/asset domain.\r\n *\r\n * Wire: tag(1) + fee_share_bps(u16) + redemption_cooldown_slots(u64) +\r\n * oi_reservation_threshold_bps(u16) + domain(u16) = 14 bytes.\r\n *\r\n * @param feeShareBps LP vault fee share in bps (0-10000).\r\n * @param redemptionCooldownSlots Slots between redemption requests.\r\n * @param oiReservationThresholdBps OI reservation threshold in bps.\r\n * @param domain Asset/domain index (u16 in v17).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCreateLpVault({\r\n * feeShareBps: 5000,\r\n * redemptionCooldownSlots: 21600n,\r\n * oiReservationThresholdBps: 8000,\r\n * domain: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface CreateLpVaultArgs {\r\n feeShareBps: number;\r\n redemptionCooldownSlots: bigint | string;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n}\r\n\r\nexport function encodeCreateLpVaultV17(args: CreateLpVaultArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.CreateLpVault),\r\n encU16(args.feeShareBps),\r\n encU64(args.redemptionCooldownSlots),\r\n encU16(args.oiReservationThresholdBps),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * DepositToLpVault (tag 75) — deposit collateral into the LP vault.\r\n *\r\n * Wire: tag(1) + amount(u128) + domain(u16) = 19 bytes.\r\n *\r\n * `domain` selects which pot of the vault's asset receives the backing and MUST\r\n * satisfy `domain >> 1 === registry.domain >> 1`. Shares are priced off COMBINED\r\n * NAV across both pots, so the depositor is indifferent to the choice; routing\r\n * exists so new money can reach whichever pot the house is drawing on.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 10 is the SIBLING-domain backing ledger\r\n * (`deriveLpBackingLedger(programId, market, domain ^ 1)`). It is required even\r\n * when uninitialised — NAV spans both pots, and omitting it would understate NAV\r\n * and mint the depositor free shares at existing holders' expense.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeDepositToLpVault({ amount: 1_000_000n, domain: 2 });\r\n * ```\r\n */\r\nexport function encodeDepositToLpVault(args: {\r\n amount: bigint | string;\r\n domain: number;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.DepositToLpVault),\r\n encU128(args.amount),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n/**\r\n * RequestRedeemLpShares (tag 76) — request redemption of LP vault shares.\r\n *\r\n * Wire: tag(1) + shares(u128) = 17 bytes.\r\n *\r\n * BREAKING vs v12.x: was LpVaultWithdraw (tag 39) with lpAmount u64.\r\n * v17 uses shares u128 and a two-step request/execute redemption flow.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRequestRedeemLpShares({ shares: 1_000_000n });\r\n * ```\r\n */\r\nexport function encodeRequestRedeemLpShares(args: { shares: bigint | string }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.RequestRedeemLpShares), encU128(args.shares));\r\n}\r\n\r\n/**\r\n * ExecuteRedemption (tag 77) — execute a pending LP redemption.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot the payout is physically DRAWN from. NAV and\r\n * available-principal stay COMBINED across both pots, so this does not change\r\n * what the redeemer is owed — only where the atoms come from. A redemption draws\r\n * from ONE pot and fails closed (EngineCounterUnderflow) if that pot cannot\r\n * cover it; rebalance (tag 91) first.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 11 is the SIBLING-domain backing ledger.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeExecuteRedemption({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeExecuteRedemption(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.ExecuteRedemption), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78) — crank fee accrual for the LP vault.\r\n *\r\n * Wire: tag(1) + domain(u16) = 3 bytes.\r\n *\r\n * `domain` selects which pot receives the cranked fees. Mints no shares, so the\r\n * choice cannot dilute; routing exists so fees can become backing in the pot\r\n * that needs it. The target ledger is created on first use.\r\n *\r\n * ACCOUNTS (v17 dual-domain): index 4 is the SIBLING-domain backing ledger and\r\n * index 5 is the system program (needed to create a missing target ledger).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeLpVaultCrankFees({ domain: 2 });\r\n * ```\r\n */\r\nexport function encodeLpVaultCrankFees(args: { domain: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.LpVaultCrankFees), encU16(args.domain));\r\n}\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91) — move IDLE backing between the two pots of\r\n * the LP vault's asset.\r\n *\r\n * Wire: tag(1) + fromDomain(u16) + toDomain(u16) + amount(u128) = 21 bytes.\r\n *\r\n * Permissionless: both pots belong to the same vault, so the move cannot extract\r\n * value, and the source-side gate refuses anything that would leave the source\r\n * pot under-backed. Only `fresh_unliened` backing moves — backing pledged against\r\n * open interest, already consumed, or impaired stays put.\r\n *\r\n * ACCOUNTS: [cranker(signer,w), market(w), registry, fromLedger(w), toLedger(w),\r\n * systemProgram]. The destination ledger is created on first arrival.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeRebalanceLpVaultBacking({\r\n * fromDomain: 2, toDomain: 3, amount: 500_000n,\r\n * });\r\n * ```\r\n */\r\nexport function encodeRebalanceLpVaultBacking(args: {\r\n fromDomain: number;\r\n toDomain: number;\r\n amount: bigint | string;\r\n}): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.RebalanceLpVaultBacking),\r\n encU16(args.fromDomain),\r\n encU16(args.toDomain),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetLpVaultPaused (tag 79) — pause or unpause the LP vault.\r\n *\r\n * Wire: tag(1) + paused(u8) = 2 bytes.\r\n *\r\n * @param paused 1 = paused, 0 = active.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetLpVaultPaused({ paused: 1 });\r\n * ```\r\n */\r\nexport function encodeSetLpVaultPaused(args: { paused: number }): Uint8Array {\r\n return concatBytes(encU8(IX_TAG.SetLpVaultPaused), encU8(args.paused));\r\n}\r\n\r\n/**\r\n * CloseLpVault (tag 80) — close an empty LP vault.\r\n *\r\n * Wire: tag(1) = 1 byte.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeCloseLpVault();\r\n * ```\r\n */\r\nexport function encodeCloseLpVault(): Uint8Array {\r\n return encU8(IX_TAG.CloseLpVault);\r\n}\r\n\r\n// ============================================================================\r\n// v17 NFT / B-3 (tags 72/73) — kept from v16\r\n// ============================================================================\r\n\r\n/**\r\n * TransferPortfolioOwnership (tag 72) — B-3 position ownership transfer.\r\n *\r\n * Wire: tag(1) + new_owner[32] + asset_index(u16) = 35 bytes.\r\n *\r\n * @param newOwner New owner pubkey.\r\n * @param assetIndex Asset/domain index.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeTransferPortfolioOwnership({\r\n * newOwner: newOwnerKey,\r\n * assetIndex: 0,\r\n * });\r\n * ```\r\n */\r\nexport interface TransferPortfolioOwnershipArgs {\r\n newOwner: PublicKey | string;\r\n assetIndex: number;\r\n}\r\n\r\nexport function encodeTransferPortfolioOwnership(args: TransferPortfolioOwnershipArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.TransferPortfolioOwnership),\r\n encPubkey(args.newOwner),\r\n encU16(args.assetIndex),\r\n );\r\n}\r\n\r\n/**\r\n * SetNftProgramId (tag 73) — register the percolator-nft program in the NftRegistry.\r\n *\r\n * Wire: tag(1) + nft_program_id[32] = 33 bytes.\r\n *\r\n * @param nftProgramId Pubkey of the percolator-nft program.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetNftProgramId({ nftProgramId: NFT_PROGRAM_ID });\r\n * ```\r\n */\r\nexport interface SetNftProgramIdArgs {\r\n nftProgramId: PublicKey | string;\r\n}\r\n\r\nexport function encodeSetNftProgramId(args: SetNftProgramIdArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetNftProgramId),\r\n encPubkey(args.nftProgramId),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK A — v17 oracle-config encoders (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34) — set Pyth/hybrid oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + now_unix_ts(i64) +\r\n * oracle_leg_count(u8) + oracle_leg_flags(u8) + max_staleness_secs(u64) +\r\n * hybrid_soft_stale_slots(u64) + mark_ewma_halflife_slots(u64) +\r\n * mark_min_fee(u64) + invert(u8) + unit_scale(u32) + conf_filter_bps(u16) +\r\n * oracle_leg_feeds[0..3]([32] each) = 156 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable),\r\n * [2..2+oracle_leg_count] oracle feed accounts (read-only).\r\n *\r\n * Constraints (from v16_program.rs:10419-10435):\r\n * - oracle_leg_count ∈ [1, ORACLE_LEG_CAP=3]\r\n * - max_staleness_secs ∈ [1, MAX_ORACLE_STALENESS_SECS=86400]\r\n * - hybrid_soft_stale_slots > 0\r\n * - invert ∈ {0, 1}\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param nowUnixTs Current Unix timestamp in seconds (i64).\r\n * @param oracleLegCount Number of active oracle legs (1–3).\r\n * @param oracleLegFlags Bit-flags for oracle leg configuration.\r\n * @param maxStalenessSecs Maximum oracle staleness in seconds (1–86400).\r\n * @param hybridSoftStaleSlots Slots after which the hybrid oracle is considered soft-stale.\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots).\r\n * @param markMinFee Minimum fee charged per mark-price update.\r\n * @param invert 0 = normal, 1 = invert price (e.g., for inverted pairs).\r\n * @param unitScale Unit scaling factor (u32).\r\n * @param confFilterBps Confidence filter in basis points (u16).\r\n * @param oracleLegFeeds Array of exactly 3 oracle leg feed pubkeys (unused slots = SystemProgram).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureHybridOracle({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * nowUnixTs: 1700000000n,\r\n * oracleLegCount: 1,\r\n * oracleLegFlags: 0,\r\n * maxStalenessSecs: 60n,\r\n * hybridSoftStaleSlots: 100n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * invert: 0,\r\n * unitScale: 1000000,\r\n * confFilterBps: 200,\r\n * oracleLegFeeds: [PYTH_FEED_KEY, PublicKey.default, PublicKey.default],\r\n * });\r\n * assert(data.length === 156);\r\n * ```\r\n */\r\nexport interface ConfigureHybridOracleArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n nowUnixTs: bigint | string;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n maxStalenessSecs: bigint | string;\r\n hybridSoftStaleSlots: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n /** Exactly 3 entries — unused legs MUST be PublicKey.default (all zeros). */\r\n oracleLegFeeds: [PublicKey | string, PublicKey | string, PublicKey | string];\r\n}\r\n\r\nconst ORACLE_LEG_CAP = 3;\r\n\r\nexport function encodeConfigureHybridOracle(args: ConfigureHybridOracleArgs): Uint8Array {\r\n if (!Number.isInteger(args.oracleLegCount) || args.oracleLegCount < 1 || args.oracleLegCount > ORACLE_LEG_CAP) {\r\n throw new Error(`encodeConfigureHybridOracle: oracleLegCount must be an integer in 1..${ORACLE_LEG_CAP}`);\r\n }\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureHybridOracle),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encI64(args.nowUnixTs),\r\n encU8(args.oracleLegCount),\r\n encU8(args.oracleLegFlags),\r\n encU64(args.maxStalenessSecs),\r\n encU64(args.hybridSoftStaleSlots),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n encU8(args.invert),\r\n encU32(args.unitScale),\r\n encU16(args.confFilterBps),\r\n encPubkey(args.oracleLegFeeds[0]),\r\n encPubkey(args.oracleLegFeeds[1]),\r\n encPubkey(args.oracleLegFeeds[2]),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35) — set EWMA mark oracle config for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) +\r\n * mark_ewma_halflife_slots(u64) + mark_min_fee(u64) = 35 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10558-10563):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - mark_ewma_halflife_slots > 0\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n * @param markEwmaHalflifeSlots EWMA half-life for mark price smoothing (slots, must be > 0).\r\n * @param markMinFee Minimum fee charged per mark-price update (u64).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureEwmaMark({\r\n * assetIndex: 1,\r\n * nowSlot: 300000000n,\r\n * initialMarkE6: 50000000000n,\r\n * markEwmaHalflifeSlots: 500n,\r\n * markMinFee: 0n,\r\n * });\r\n * assert(data.length === 35);\r\n * ```\r\n */\r\nexport interface ConfigureEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n markEwmaHalflifeSlots: bigint | string;\r\n markMinFee: bigint | string;\r\n}\r\n\r\nfunction requirePositiveU64(value: bigint | string, field: string): void {\r\n const n = typeof value === \"string\" ? BigInt(value) : value;\r\n if (n <= 0n) {\r\n throw new Error(`${field} must be > 0`);\r\n }\r\n}\r\nexport function encodeConfigureEwmaMark(args: ConfigureEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n requirePositiveU64(args.markEwmaHalflifeSlots, \"markEwmaHalflifeSlots\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n encU64(args.markEwmaHalflifeSlots),\r\n encU64(args.markMinFee),\r\n );\r\n}\r\n\r\n/**\r\n * PushEwmaMark (tag 36) — push a new EWMA mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10771):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_EWMA_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushEwmaMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushEwmaMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushEwmaMark(args: PushEwmaMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushEwmaMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62) — set auth-push mark oracle for a market asset.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + initial_mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10665):\r\n * - initial_mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Caller must be the asset's oracle_authority\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param initialMarkE6 Initial mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeConfigureAuthMark({ assetIndex: 1, nowSlot: 300000000n, initialMarkE6: 50000000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface ConfigureAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n initialMarkE6: bigint | string;\r\n}\r\n\r\nexport function encodeConfigureAuthMark(args: ConfigureAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.initialMarkE6, \"initialMarkE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.ConfigureAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.initialMarkE6),\r\n );\r\n}\r\n\r\n/**\r\n * PushAuthMark (tag 63) — push a new auth-mark price observation.\r\n *\r\n * v17 wire: tag(1) + asset_index(u16) + now_slot(u64) + mark_e6(u64) = 19 bytes total.\r\n *\r\n * Accounts: [0] oracle_authority (signer), [1] market (writable).\r\n *\r\n * Constraints (from v16_program.rs:10847):\r\n * - mark_e6 ∈ [1, MAX_ORACLE_PRICE]\r\n * - Asset oracle mode must be ORACLE_MODE_AUTH_MARK\r\n * - Caller must be the asset's oracle_authority\r\n * - now_slot ≥ last EWMA slot and current market slot\r\n *\r\n * @param assetIndex Asset slot index (u16).\r\n * @param nowSlot Current on-chain slot (u64).\r\n * @param markE6 New mark price × 1e6 (u64, must be > 0).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodePushAuthMark({ assetIndex: 1, nowSlot: 300000001n, markE6: 50100000000n });\r\n * assert(data.length === 19);\r\n * ```\r\n */\r\nexport interface PushAuthMarkArgs {\r\n assetIndex: number;\r\n nowSlot: bigint | string;\r\n markE6: bigint | string;\r\n}\r\n\r\nexport function encodePushAuthMark(args: PushAuthMarkArgs): Uint8Array {\r\n requirePositiveU64(args.markE6, \"markE6\");\r\n\r\n return concatBytes(\r\n encU8(IX_TAG.PushAuthMark),\r\n encU16(args.assetIndex),\r\n encU64(args.nowSlot),\r\n encU64(args.markE6),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// TASK B — Matcher passive-init payload (matcher program, not wrapper)\r\n// ============================================================================\r\n\r\n/**\r\n * MatcherInitPassive — 66-byte payload sent to the MATCHER PROGRAM (not wrapper)\r\n * to initialize a passive LP matcher context.\r\n *\r\n * This is NOT a wrapper instruction. Program = matcher program address.\r\n * Accounts: [0] matcherDelegate (read-only PDA), [1] matcherCtx (writable).\r\n *\r\n * Wire layout (66 bytes, from percolator-prog/tests/v16_five_program_crosscut.rs:640-648):\r\n * [0] = 2 (opcode: passive-LP init)\r\n * [1] = 0 (reserved)\r\n * [2..10] = 0 (8 bytes reserved)\r\n * [10..14] = 100u32 LE (default max_inventory_abs slot)\r\n * [14..34] = 0 (20 bytes reserved)\r\n * [34..50] = max_fill_abs (u128 LE)\r\n * [50..66] = 0 (16 bytes reserved)\r\n * Total = 66 bytes\r\n *\r\n * The matcher delegate PDA is derived via `deriveMatcherDelegate()` in pda.ts using\r\n * seeds [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx].\r\n *\r\n * @param maxFillAbs Maximum absolute fill size (u128). Pass BigInt.MaxUint128 (2^128-1) for no limit.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeMatcherInitPassive({ maxFillAbs: 2n ** 128n - 1n });\r\n * assert(data.length === 66);\r\n * // send to matcherProgram, accounts: [delegate(ro), ctx(w)]\r\n * ```\r\n */\r\nexport interface MatcherInitPassiveArgs {\r\n maxFillAbs: bigint | string;\r\n}\r\n\r\nexport function encodeMatcherInitPassive(args: MatcherInitPassiveArgs): Uint8Array {\r\n const buf = new Uint8Array(66);\r\n buf[0] = 2;\r\n buf[1] = 0;\r\n // [10..14] = 100u32 LE (default max_inventory_abs / slot factor)\r\n const u32Bytes = encU32(100);\r\n buf.set(u32Bytes, 10);\r\n // [34..50] = max_fill_abs u128 LE\r\n const u128Bytes = encU128(args.maxFillAbs);\r\n buf.set(u128Bytes, 34);\r\n return buf;\r\n}\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B.\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// Instruction::decode arms 84/85 and handle_withdraw_protocol_fee /\r\n// handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx, which forensic rebuild + live simulateTransaction confirmed\r\n// is live on the deployed wrapper (percolator-prog@e26c97a4) — see\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\".\r\n//\r\n// ⚠️ Only valid against VERSION=17 markets (protocol-fee wrapper). The\r\n// pre-protocol-fee (VERSION=16) wrapper has no decode arm at tag 84/85 at\r\n// all — sending this encoded data to it would be rejected or misinterpreted.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee instruction data (tag 84).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes.\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (`protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms` on\r\n * WrapperConfigV17) to an external token account. Signer-gated on\r\n * `cfg.protocolFeeAuthority` (see `parseWrapperConfigV17`). The transfer is\r\n * clamped to what's actually available on-chain (engine surplus, vault\r\n * balance) and only the actually-transferred amount is marked withdrawn —\r\n * this never errors solely because the ledger raced ahead of availability.\r\n *\r\n * @param amount Atoms to withdraw (u128). Pass `0n` to withdraw all\r\n * currently-available capacity.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawProtocolFee({ amount: 0n }); // withdraw-all\r\n * // accounts: ACCOUNTS_WITHDRAW_PROTOCOL_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawProtocolFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawProtocolFee(args: WithdrawProtocolFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawProtocolFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n\r\n/**\r\n * SetProtocolFeeAuthority instruction data (tag 85).\r\n *\r\n * v17 wire: tag(1) + new_authority(32) = 33 bytes.\r\n *\r\n * Rotates `cfg.protocolFeeAuthority` on a single market. Gated on the\r\n * program's BPF upgrade authority (a `ProgramData` PDA read, NOT\r\n * marketauth/insurance_authority/any creator-facing gate) — see\r\n * ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY in abi/accounts.ts. No global fan-out;\r\n * a keeper script iterates markets for a mass rotation.\r\n *\r\n * @param newAuthority New protocol-fee-authority pubkey.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeSetProtocolFeeAuthority({ newAuthority: newTreasury });\r\n * ```\r\n */\r\nexport interface SetProtocolFeeAuthorityArgs {\r\n newAuthority: PublicKey;\r\n}\r\n\r\nexport function encodeSetProtocolFeeAuthority(args: SetProtocolFeeAuthorityArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.SetProtocolFeeAuthority),\r\n encPubkey(args.newAuthority),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * On-chain fee-split constants, mirrored from `v16_program.rs::constants`.\r\n *\r\n * `T = trade_fee_base_bps` is the whole trade fee. It splits four ways at\r\n * every trade-fee credit site: a constant 2000 bps protocol skim, then the\r\n * three stored shares below, which are bps *of T* and must sum to exactly\r\n * `FEE_SHARE_TOTAL_BPS`.\r\n *\r\n * The floors are percentages of the post-protocol remainder (creator <= 45%,\r\n * LP >= 40%, insurance >= 15%) converted to bps-of-T by `pct * 8000`. They sum\r\n * to exactly 8000, i.e. they are precisely complementary — pushing creator\r\n * above its ceiling necessarily drags another leg under its floor.\r\n *\r\n * Defaults are written unconditionally at InitMarket and are never instruction\r\n * arguments, so a market that never calls UpdateFeeSplit still pays all four\r\n * legs correctly from its first trade.\r\n */\r\nexport const FEE_SPLIT = {\r\n /** Constant protocol skim, bps of T. Compile-time in the program; not stored, not settable. */\r\n PROTOCOL_FEE_BPS: 2000,\r\n /** The three stored shares must sum to exactly this (= 10_000 - PROTOCOL_FEE_BPS). */\r\n FEE_SHARE_TOTAL_BPS: 8000,\r\n DEFAULT_CREATOR_SHARE_BPS: 1600,\r\n DEFAULT_LP_SHARE_BPS: 4800,\r\n DEFAULT_INSURANCE_SHARE_BPS: 1600,\r\n /** Creator ceiling, bps of T (45% of the post-protocol remainder). */\r\n MAX_CREATOR_SHARE_BPS: 3600,\r\n /** LP floor, bps of T (40% of the post-protocol remainder). */\r\n MIN_LP_SHARE_BPS: 3200,\r\n /** Insurance/staker floor, bps of T (15% of the post-protocol remainder). */\r\n MIN_INSURANCE_SHARE_BPS: 1200,\r\n} as const;\r\nObject.freeze(FEE_SPLIT);\r\n\r\n/**\r\n * Client-side mirror of `policy_v16::validate_fee_split`. Returns `null` when\r\n * the split would be accepted on-chain, otherwise a human-readable reason.\r\n *\r\n * Provided so a wizard/UI can reject a bad split before paying for a\r\n * transaction; the wrapper enforces the same rules regardless (Custom(52)\r\n * FeeSplitSumInvalid for the sum, Custom(51) FeeSplitFloorViolation for the\r\n * floors), so this is a convenience, never the security boundary.\r\n *\r\n * @param args The three candidate shares, in bps of T.\r\n * @returns `null` if valid, else a string describing the first violation.\r\n *\r\n * @example\r\n * ```ts\r\n * validateFeeSplit({ creatorShareBps: 1600, lpShareBps: 4800, insuranceShareBps: 1600 });\r\n * // => null (these are the on-chain defaults)\r\n * validateFeeSplit({ creatorShareBps: 4000, lpShareBps: 3200, insuranceShareBps: 800 });\r\n * // => \"creatorShareBps 4000 exceeds MAX_CREATOR_SHARE_BPS 3600\"\r\n * ```\r\n */\r\nexport function validateFeeSplit(args: UpdateFeeSplitArgs): string | null {\r\n const { creatorShareBps, lpShareBps, insuranceShareBps } = args;\r\n const sum = creatorShareBps + lpShareBps + insuranceShareBps;\r\n if (sum !== FEE_SPLIT.FEE_SHARE_TOTAL_BPS) {\r\n return `shares sum to ${sum}, must sum to exactly FEE_SHARE_TOTAL_BPS ${FEE_SPLIT.FEE_SHARE_TOTAL_BPS}`;\r\n }\r\n if (creatorShareBps > FEE_SPLIT.MAX_CREATOR_SHARE_BPS) {\r\n return `creatorShareBps ${creatorShareBps} exceeds MAX_CREATOR_SHARE_BPS ${FEE_SPLIT.MAX_CREATOR_SHARE_BPS}`;\r\n }\r\n if (lpShareBps < FEE_SPLIT.MIN_LP_SHARE_BPS) {\r\n return `lpShareBps ${lpShareBps} is below MIN_LP_SHARE_BPS ${FEE_SPLIT.MIN_LP_SHARE_BPS}`;\r\n }\r\n if (insuranceShareBps < FEE_SPLIT.MIN_INSURANCE_SHARE_BPS) {\r\n return `insuranceShareBps ${insuranceShareBps} is below MIN_INSURANCE_SHARE_BPS ${FEE_SPLIT.MIN_INSURANCE_SHARE_BPS}`;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * UpdateFeeSplit instruction data (tag 86).\r\n *\r\n * v17 wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes.\r\n *\r\n * Sets the three stored fee shares. Gated on `cfg.marketauth` — see\r\n * ACCOUNTS_UPDATE_FEE_SPLIT in abi/accounts.ts. Shares are bps of T and must\r\n * sum to FEE_SHARE_TOTAL_BPS (8000) while satisfying the floors; use\r\n * {@link validateFeeSplit} to check before sending.\r\n *\r\n * ⚠ ORDERING: call this BEFORE `StakeInitPool`, which irreversibly rotates\r\n * `cfg.marketauth` to the stake-pool PDA. Afterwards a PDA cannot sign a\r\n * top-level transaction and this tag is reachable only via the stake program's\r\n * CPI proxy — see {@link encodeStakeAdminUpdateFeeSplit} (stake tag 25).\r\n *\r\n * @param creatorShareBps Creator's share of T in bps. Must be <= 3600.\r\n * @param lpShareBps LP vault's share of T in bps. Must be >= 3200.\r\n * @param insuranceShareBps Insurance/staker share of T in bps. Must be >= 1200.\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Restore the on-chain defaults explicitly.\r\n * const data = encodeUpdateFeeSplit({\r\n * creatorShareBps: 1600,\r\n * lpShareBps: 4800,\r\n * insuranceShareBps: 1600,\r\n * });\r\n * // accounts: ACCOUNTS_UPDATE_FEE_SPLIT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateFeeSplitArgs {\r\n creatorShareBps: number;\r\n lpShareBps: number;\r\n insuranceShareBps: number;\r\n}\r\n\r\nexport function encodeUpdateFeeSplit(args: UpdateFeeSplitArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateFeeSplit),\r\n encU16(args.creatorShareBps),\r\n encU16(args.lpShareBps),\r\n encU16(args.insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake instruction data (tag 87).\r\n *\r\n * v17 wire: tag(1) = 1 byte. No arguments — the amount is\r\n * `insurance_reserve_accrued_atoms - insurance_reserve_withdrawn_atoms`,\r\n * clamped on-chain to engine-available surplus, and the destination is derived\r\n * rather than passed.\r\n *\r\n * Permissionless: any signer may crank it. The destination is `pool.vault`,\r\n * read out of the stake pool at `[\"stake_pool\", market]` under the wrapper's\r\n * PINNED stake program id, so there is nothing for a caller to redirect.\r\n *\r\n * ⚠ Live-only. Rejects Recovery and Resolved (Custom 21 EngineLockActive) and\r\n * matured-Live. `ResolveMarket` is one-way and `WithdrawInsuranceAsset` (tag\r\n * 41/57) cannot reach this unbudgeted leg, so anything accrued but not pushed\r\n * before a market resolves is PERMANENTLY FORFEITED by stakers. Crank before\r\n * resolution.\r\n *\r\n * ⚠ A default (non-devnet) wrapper build has no pinned stake program id and\r\n * fails closed with Custom(60) StakeProgramNotPinned. There is no v17 mainnet\r\n * stake deployment.\r\n *\r\n * @returns 1-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeWithdrawInsuranceReserveToStake();\r\n * // accounts: ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE from abi/accounts.ts\r\n * ```\r\n */\r\nexport function encodeWithdrawInsuranceReserveToStake(): Uint8Array {\r\n return encU8(IX_TAG.WithdrawInsuranceReserveToStake);\r\n}\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot instruction data (tag 88).\r\n *\r\n * v17 wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The wrapper decodes it with `read_u128`,\r\n * matching the storage type (`WrapperConfigV16::maintenance_fee_per_slot`) and\r\n * InitMarket's own encoding. A u64 payload leaves 8 bytes unconsumed and the\r\n * wrapper rejects the instruction outright.\r\n *\r\n * Gated on `cfg.marketauth`. The wrapper range-checks against\r\n * `MAX_PROTOCOL_FEE_ABS` (1e36) and returns Custom(14) EngineInvalidConfig if\r\n * exceeded — the same bound InitMarket applies.\r\n *\r\n * Same StakeInitPool ordering caveat as tag 86; the proxy is\r\n * {@link encodeStakeAdminUpdateMaintenanceFeePerSlot} (stake tag 26).\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default is 0\r\n * (maintenance fee disabled).\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateMaintenanceFeePerSlot({ maintenanceFeePerSlot: 0n });\r\n * // accounts: ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface UpdateMaintenanceFeePerSlotArgs {\r\n maintenanceFeePerSlot: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateMaintenanceFeePerSlot(\r\n args: UpdateMaintenanceFeePerSlotArgs,\r\n): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateMaintenanceFeePerSlot),\r\n encU128(args.maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * UpdateTradeFeePolicy instruction data (tag 55).\r\n *\r\n * v17 wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides. Gated on\r\n * ASSET 0's `insurance_authority`, NOT on `marketauth` — so unlike tags 86/88\r\n * this survives `StakeInitPool` but is stranded by `BindInsuranceAuthority`,\r\n * after which the proxy is {@link encodeStakeAdminUpdateTradeFeePolicy}\r\n * (stake tag 28).\r\n *\r\n * ⚠ Note the type asymmetry with tag 88: this decodes with `read_u64`, tag 88\r\n * with `read_u128`.\r\n *\r\n * Added 2026-07-20: IX_TAG.UpdateTradeFeePolicy existed but had no encoder,\r\n * which left stake tag 28's CPI target unrepresentable from the SDK.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64).\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeUpdateTradeFeePolicy({ tradeFeeBaseBps: 30n });\r\n * ```\r\n */\r\nexport interface UpdateTradeFeePolicyArgs {\r\n tradeFeeBaseBps: bigint | string;\r\n}\r\n\r\nexport function encodeUpdateTradeFeePolicy(args: UpdateTradeFeePolicyArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.UpdateTradeFeePolicy),\r\n encU64(args.tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * ExpireBackingBucket instruction data (tag 89).\r\n *\r\n * v17 wire: tag(1) + domain(u16 LE) = 3 bytes. Verified against\r\n * v16_program.rs's tag-89 decode arm (`89 => Self::ExpireBackingBucket {\r\n * domain: read_u16(&mut rest)? }`) followed by the shared\r\n * `if !rest.is_empty()` guard — any trailing byte is rejected.\r\n *\r\n * PERMISSIONLESS. One account, the market, writable, and NO signer at all\r\n * (see ACCOUNTS_EXPIRE_BACKING_BUCKET). Any keeper can call it; there is no\r\n * authority to hold.\r\n *\r\n * ## Why this exists\r\n *\r\n * A realized loss reserves capital as counterparty backing, which opens the\r\n * source domain's bucket as `Fresh` with a fixed `expiry_slot`. Once that\r\n * expiry passes while the bucket is still `Fresh`, the domain becomes a DEAD\r\n * END in all three directions, permanently:\r\n *\r\n * - settling a GAIN against it -> Custom(19) EngineStale\r\n * - reserving a further LOSS -> Custom(21) EngineLockActive\r\n * - `TopUpBackingBucket` to re-fund it -> Custom(21) EngineLockActive\r\n *\r\n * The bucket cannot even be paid to come back. Before tag 89 the wrapper had\r\n * no call site that reached the engine's own escape hatch\r\n * (`expire_source_backing_bucket_not_atomic`) on a LIVE market — the engine\r\n * used it only on the RESOLVED close path — so a lapse bricked the domain for\r\n * good. Tag 89 IS that missing call site.\r\n *\r\n * ## ⚠ This is routine maintenance, not an edge case — wire a keeper\r\n *\r\n * EVERY BACKED MARKET LAPSES EVENTUALLY. `fresh_counterparty_backing_expiry_slot`\r\n * returns the stored expiry unchanged on a live bucket, so the expiry is set\r\n * once when the bucket opens and is never extended. Seeding a long horizon\r\n * (e.g. MAX_BACKING_BUCKET_EXPIRY_SLOT) DEFERS the lapse; it does not prevent\r\n * it. Treat tag 89 as a standing keeper duty alongside the crank, not as an\r\n * incident-response tool: a keeper should scan live markets for domains whose\r\n * bucket is `Fresh` with `current_slot >= expiry_slot` and expire them. If\r\n * nobody cranks it, the first lapse silently bricks the domain and the failure\r\n * surfaces to users as an unexplained Custom(19)/Custom(21) on ordinary\r\n * settlement.\r\n *\r\n * ## Safety\r\n *\r\n * Permissionless is not an authority hole. The engine refuses the transition\r\n * unless the bucket is `Fresh` AND `now_slot >= expiry_slot`, and `now_slot`\r\n * is read from the runtime `Clock` (via\r\n * `authenticated_market_slot_or_fallback_view`), NEVER from a caller argument\r\n * — so no caller can force an early forfeiture. Moves no tokens.\r\n *\r\n * Expiry forfeits the lapsed principal to the junior pool. That is the\r\n * engine's documented expiry semantics, not a haircut invented by this\r\n * instruction; the alternative is the account never settling at all.\r\n *\r\n * ## Failure modes\r\n *\r\n * - Custom(21) EngineLockActive — the market is not Live (`mode != 0`). The\r\n * resolved/wound-down path reaches the transition through the engine's own\r\n * resolved-close sweep, so re-entering it from outside is refused.\r\n * - Custom(9) InvalidInstruction — `domain >= 2 * max_market_slots`.\r\n * - Custom(19) EngineStale — the engine declined: the bucket is not `Fresh`,\r\n * or it is `Fresh` but has NOT yet lapsed. Fails closed, so calling this\r\n * speculatively on a healthy domain is safe (it just reverts).\r\n *\r\n * @param domain Backing-bucket domain index (2*assetIndex for long,\r\n * 2*assetIndex+1 for short), u16. Must be\r\n * `< 2 * max_market_slots`.\r\n * @returns 3-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * // Keeper: unbrick the long domain of asset 0 after its bucket lapsed.\r\n * const data = encodeExpireBackingBucket({ domain: 0 });\r\n * // accounts: ACCOUNTS_EXPIRE_BACKING_BUCKET — [market] writable, no signer\r\n * // beyond the fee payer.\r\n * ```\r\n */\r\nexport interface ExpireBackingBucketArgs {\r\n domain: number;\r\n}\r\n\r\nexport function encodeExpireBackingBucket(args: ExpireBackingBucketArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.ExpireBackingBucket),\r\n encU16(args.domain),\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n//\r\n// Companion read side: `creatorFeeClaimableAtoms` on WrapperConfigV17\r\n// (u64 LE at V17_CREATOR_FEE_CLAIMABLE_OFF = 568, inside the UNCHANGED\r\n// 576-byte config — see solana/slab.ts).\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee instruction data (tag 90).\r\n *\r\n * v17 wire: tag(1) + amount(u128 LE) = 17 bytes. Verified against\r\n * percolator-prog `src/v16_program.rs`:\r\n *\r\n * decode arm: 90 => Self::WithdrawCreatorFee { amount: read_u128(&mut rest)? }\r\n * read_u128: u128::from_le_bytes(..) -> LITTLE-endian, 16 bytes\r\n * tail guard: if !rest.is_empty() { return Err(InvalidInstructionData) }\r\n * -> total length is EXACTLY 17; any trailing byte is rejected\r\n * encode arm: out.push(90); push_u128(&mut out, amount)\r\n *\r\n * Pays the market creator's accrued trade-fee share out of the market vault to\r\n * an external token account, debiting `creatorFeeClaimableAtoms` by exactly\r\n * `amount`. That counter is disjoint from the insurance domain budget (the loss\r\n * backstop): before this change the creator leg was credited INTO the backstop,\r\n * so a \"claim fees\" button was really a backstop withdrawal. Tag 90 cannot\r\n * touch the backstop, and tag 57 (WithdrawInsuranceAsset) cannot touch this\r\n * counter.\r\n *\r\n * ⚠ `amount: 0n` is REJECTED by the program (InvalidInstruction), NOT treated\r\n * as the \"withdraw all\" sentinel that {@link encodeWithdrawProtocolFee} (tag\r\n * 84) uses. To drain, read `creatorFeeClaimableAtoms` from\r\n * `parseWrapperConfigV17` and pass that exact value.\r\n *\r\n * ⚠ Over-claim is rejected, not clamped — there is no partial fill, and nothing\r\n * is debited on failure. If the vault's unbudgeted surplus is momentarily thin\r\n * the whole instruction fails closed (EngineLockActive); retry with less.\r\n *\r\n * ⚠ Authority is asset 0's `insurance_operator` and ONLY that (never\r\n * `cfg.marketauth`), so claiming still works on a staked market where\r\n * StakeInitPool has rotated `marketauth` to the stake-pool PDA.\r\n *\r\n * @param amount Atoms to claim (u128 on the wire; the on-chain counter is a\r\n * u64, so anything above u64::MAX is an over-claim).\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketAccount.data);\r\n * // Drain the full claimable balance:\r\n * const data = encodeWithdrawCreatorFee({ amount: cfg.creatorFeeClaimableAtoms });\r\n * // accounts: ACCOUNTS_WITHDRAW_CREATOR_FEE from abi/accounts.ts\r\n * ```\r\n */\r\nexport interface WithdrawCreatorFeeArgs {\r\n amount: bigint | string;\r\n}\r\n\r\nexport function encodeWithdrawCreatorFee(args: WithdrawCreatorFeeArgs): Uint8Array {\r\n return concatBytes(\r\n encU8(IX_TAG.WithdrawCreatorFee),\r\n encU128(args.amount),\r\n );\r\n}\r\n","import {\r\n PublicKey,\r\n AccountMeta,\r\n SYSVAR_CLOCK_PUBKEY,\r\n SYSVAR_RENT_PUBKEY,\r\n SystemProgram,\r\n} from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Account spec for building instruction account metas.\r\n * Each instruction has a fixed ordering that matches the Rust processor.\r\n */\r\nexport interface AccountSpec {\r\n name: string;\r\n signer: boolean;\r\n writable: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// ACCOUNT ORDERINGS - Single source of truth\r\n// ============================================================================\r\n\r\n/**\r\n * InitMarket: 9 accounts (Pyth Pull - feed_id is in instruction data, not as accounts)\r\n */\r\nexport const ACCOUNTS_INIT_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"mint\", signer: false, writable: false },\r\n { name: \"vault\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"dummyAta\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * InitPortfolio (tag 2): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_portfolio):\r\n * [0] owner signer, writable (portfolio owner; pays for alloc)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n *\r\n * v12 clock sysvar, userAta, vault, tokenProgram are gone — v17\r\n * InitPortfolio does not transfer collateral and does not read the clock.\r\n */\r\nexport const ACCOUNTS_INIT_USER: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * InitLP: 6 accounts\r\n * Program at percolator.rs:6607 calls expect_len(accounts, 6).\r\n * The 6th account (accounts[5]) is the clock sysvar — used via Clock::from_account_info.\r\n * [0] user signer, writable (LP owner; pays fee)\r\n * [1] slab writable\r\n * [2] userAta writable (collateral source for fee)\r\n * [3] vault writable (collateral destination)\r\n * [4] tokenProgram read-only\r\n * [5] clock read-only (SYSVAR_CLOCK_PUBKEY)\r\n */\r\nexport const ACCOUNTS_INIT_LP: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Deposit (tag 3): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] sourceToken writable (owner's collateral ATA)\r\n * [4] vaultToken writable (program vault token account)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar. Portfolio account added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeDepositCollateral).\r\n */\r\nexport const ACCOUNTS_DEPOSIT_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Withdraw (tag 4): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw):\r\n * [0] owner signer (portfolio owner)\r\n * [1] market writable (market-group slab; must be program-owned)\r\n * [2] portfolio writable (portfolio PDA; must be program-owned)\r\n * [3] destToken writable (owner's collateral ATA — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs token CPI)\r\n * [6] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: clock sysvar, oracleIdx. Portfolio added at [2].\r\n * v17 amount is u128 (see instructions.ts encodeWithdrawCollateral).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * E2 (native NFT-holder auth): the OPTIONAL trailing accounts that let the CURRENT\r\n * HOLDER of a position's bound NFT operate an NFT-escrowed position — deposit\r\n * (margin-defend), withdraw, trade_cpi/batch_trade_cpi, close_resolved,\r\n * claim_resolved_payout, convert/forfeit/rebalance. Append these to the base\r\n * account list when the signer is the NFT holder (not `portfolio.owner`); omit\r\n * them for the normal `owner == signer` path. The wrapper reads them as trailing\r\n * optional accounts and routes funds to the SIGNER (the holder), never the escrow PDA.\r\n * [+0] nftRegistry — `[\"nft_registry\", marketGroup]` PDA (under the wrapper program)\r\n * [+1] positionNft — `[\"position_nft\", portfolio, marketId_le]` PDA (the NFT program)\r\n * [+2] signerNftAta — the signer's token account holding the bound NFT (amount == 1)\r\n */\r\nexport const ACCOUNTS_NFT_HOLDER_AUTH: readonly AccountSpec[] = [\r\n { name: \"nftRegistry\", signer: false, writable: false },\r\n { name: \"positionNft\", signer: false, writable: false },\r\n { name: \"signerNftAta\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * Append the E2 NFT-holder-auth trio to any owner-gated account list, so the bound\r\n * NFT's holder can operate an escrowed position. No-op semantics for the wrapper\r\n * when the signer is the portfolio owner (it takes the fast path and ignores them).\r\n */\r\nexport function withNftHolderAuth(base: readonly AccountSpec[]): AccountSpec[] {\r\n return [...base, ...ACCOUNTS_NFT_HOLDER_AUTH];\r\n}\r\n\r\n/**\r\n * KeeperCrank: 4 accounts\r\n * @deprecated v12.x only. Use ACCOUNTS_PERMISSIONLESS_CRANK in v17.\r\n */\r\nexport const ACCOUNTS_KEEPER_CRANK: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PermissionlessCrank (tag 5): 3 fixed accounts + variable oracle tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_permissionless_crank):\r\n * [0] owner signer, writable (keeper key; receives liquidation reward)\r\n * [1] market writable (the market-group slab)\r\n * [2] portfolio writable (the PORTFOLIO being cranked / liquidated)\r\n * [3..] oracleTail read-only oracle accounts (Pyth PriceUpdateV2 PDAs, one per asset)\r\n *\r\n * For liquidation with reward (action=1 and cfg.liquidation_cranker_fee_share_bps!=0),\r\n * the LAST oracle tail account must be the keeper's OWN portfolio (writable), so the\r\n * program can credit the liquidation fee there. The keeper portfolio must be owned by\r\n * the same program and have a different key from accounts[2].\r\n *\r\n * Use buildPermissionlessCrankKeys() (in keeper) to assemble the full account list\r\n * including oracle tail and optional keeper portfolio.\r\n */\r\nexport const ACCOUNTS_PERMISSIONLESS_CRANK_BASE: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * RestartAssetOracle (tag 69): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs:9660 handle_restart_asset_oracle):\r\n * [0] authority signer (asset_admin for the target asset_index)\r\n * [1] market writable (the market-group slab)\r\n *\r\n * Gated by the asset's asset_admin key (per-asset in AssetOracleProfileV16).\r\n * Only callable when the asset lifecycle == ASSET_LIFECYCLE_RECOVERY.\r\n * Permissionless in the sense that any holder of asset_admin can call it.\r\n */\r\nexport const ACCOUNTS_RESTART_ASSET_ORACLE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n\r\n/**\r\n * TradeNoCpi (tag 9): 5 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_nocpi):\r\n * [0] signerA signer, writable (party A — portfolio owner)\r\n * [1] signerB signer, writable (party B — portfolio owner)\r\n * [2] market writable (market-group slab; program-owned)\r\n * [3] accountA writable (portfolio A; program-owned)\r\n * [4] accountB writable (portfolio B; program-owned)\r\n *\r\n * v12 stale accounts removed: lp, clock, oracle. market replaces slab.\r\n * signerB replaces lp (both portfolios must have live owner signers).\r\n */\r\nexport const ACCOUNTS_TRADE_NOCPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: true },\r\n { name: \"signerB\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LiquidateAtOracle: 4 accounts\r\n * Note: account[0] is unused but must be present\r\n */\r\nexport const ACCOUNTS_LIQUIDATE_AT_ORACLE: readonly AccountSpec[] = [\r\n { name: \"unused\", signer: false, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClosePortfolio (tag 8): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_close_portfolio):\r\n * [0] owner signer, writable (portfolio owner or marketauth on terminal cleanup)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] portfolio writable (portfolio PDA being closed; program-owned)\r\n *\r\n * v12 stale accounts removed: vault, userAta, vaultPda, tokenProgram, clock, oracle.\r\n * v17 ClosePortfolio does not transfer collateral — it simply deregisters the\r\n * portfolio and closes the account back to the market slab.\r\n */\r\nexport const ACCOUNTS_CLOSE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * TopUpInsurance (tag 9): 5 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_insurance):\r\n * [0] signer signer, writable (insurance authority for asset 0)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-asset InsuranceLedger PDA)\r\n *\r\n * v12 stale accounts removed: clock sysvar (was at [5]).\r\n * v17 amount is u128 (see instructions.ts encodeTopUpInsurance).\r\n * Pass ledger PDA derived via deriveInsuranceLedger() when tracking\r\n * per-authority deposit principals; omit for simple vault top-ups.\r\n */\r\nexport const ACCOUNTS_TOPUP_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TopUpBackingBucket (tag 24): 5 accounts (+1 optional).\r\n *\r\n * v17 wire account layout (v16_program.rs handle_top_up_backing_bucket):\r\n * [0] signer signer, writable — must == the asset's backing_bucket_authority\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] sourceToken writable (signer's collateral ATA — source of the deposit)\r\n * [3] vaultToken writable (program vault token account — destination)\r\n * [4] tokenProgram read-only\r\n * [5] ledger writable, optional (per-domain BackingDomainLedger PDA;\r\n * omit for a simple top-up with no ledger tracking)\r\n *\r\n * v17 amount/expiry are u128/u64 (see instructions.ts encodeTopUpBackingBucket).\r\n */\r\nexport const ACCOUNTS_TOP_UP_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"signer\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucket (tag 50): 6 fixed accounts + optional ledger.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority-OWNED token account — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-domain BackingDomainLedger PDA)\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateBackingFeePolicy (tag 51): 2 accounts — the LP-yield on/off switch.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_backing_fee_policy):\r\n * [0] authority signer — the asset's insurance_authority (NOT marketauth,\r\n * so it stays callable by the creator wallet after the\r\n * launch flow rotates marketauth to the stake-pool PDA)\r\n * [1] market writable (market-group slab; program-owned)\r\n */\r\nexport const ACCOUNTS_UPDATE_BACKING_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawBackingBucketEarnings (tag 52): 7 accounts — ledger REQUIRED.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_backing_bucket_earnings):\r\n * [0] authority signer — the asset's backing_bucket_authority (or marketauth)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] ledger writable, REQUIRED (per-domain BackingDomainLedger PDA;\r\n * unlike tag 50 where it is an optional tail)\r\n * [3] destToken writable (authority-OWNED token account — destination)\r\n * [4] vaultToken writable (program vault token account — source)\r\n * [5] vaultAuthority read-only (PDA that signs the token CPI)\r\n * [6] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_WITHDRAW_BACKING_BUCKET_EARNINGS: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TradeCpi (tag 10): 7 fixed accounts + optional tail.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_trade_cpi):\r\n * [0] signerA signer (party A — portfolio owner)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] accountA writable (portfolio A; program-owned)\r\n * [3] accountB writable (portfolio B; program-owned)\r\n * [4] matcherProg read-only, executable (matcher program)\r\n * [5] matcherCtx writable (matcher context account; owned by matcherProg)\r\n * [6] matcherDelegate read-only (PDA derived by deriveMatcherDelegate())\r\n * [7+] tail additional accounts forwarded to matcher CPI\r\n *\r\n * v12 stale accounts removed: lpOwner, clock, oracle, lpPda.\r\n * matcherDelegate replaces lpPda — derive via deriveMatcherDelegate().\r\n * market replaces slab name.\r\n */\r\nexport const ACCOUNTS_TRADE_CPI: readonly AccountSpec[] = [\r\n { name: \"signerA\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"accountA\", signer: false, writable: true },\r\n { name: \"accountB\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetRiskThreshold: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_RISK_THRESHOLD: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAdmin: 2 accounts\r\n */\r\nexport const ACCOUNTS_UPDATE_ADMIN: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * AcceptAdmin: 2 accounts (tag 82)\r\n * Second half of two-step admin transfer. The proposed new admin must sign to\r\n * complete the transfer. Program at percolator.rs:7994 calls expect_len(accounts, 2).\r\n * [0] pendingAdmin signer, writable (must match config.pending_admin)\r\n * [1] slab writable\r\n */\r\nexport const ACCOUNTS_ACCEPT_ADMIN: readonly AccountSpec[] = [\r\n { name: \"pendingAdmin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CloseSlab: 6 accounts\r\n * Drains vault and recovers rent after market is fully resolved and all accounts closed.\r\n * Program at percolator.rs:8033 calls expect_len(accounts, 6).\r\n * [0] dest signer, writable (receives rent + drained vault tokens)\r\n * [1] slab writable\r\n * [2] vault writable (token account — drained)\r\n * [3] vaultAuthority read-only (PDA that signs the drain transfer)\r\n * [4] destAta writable (dest's token ATA receiving drained tokens)\r\n * [5] tokenProgram read-only\r\n */\r\nexport const ACCOUNTS_CLOSE_SLAB: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"destAta\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateConfig: 3 accounts (canonical) or 4 (with oracle).\r\n * v12.19 wrapper at src/percolator.rs:9544 accepts either.\r\n * 3-account form: [admin(s+w), slab(w), clock].\r\n * 4-account form: [admin(s+w), slab(w), clock, oracle] (used when the wrapper\r\n * needs to re-read price during config commit). Default to the 3-account form;\r\n * callers that need oracle re-reads should append the oracle account themselves.\r\n */\r\nexport const ACCOUNTS_UPDATE_CONFIG: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetMaintenanceFee: 2 accounts\r\n */\r\nexport const ACCOUNTS_SET_MAINTENANCE_FEE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetOraclePriceCap: 3 accounts.\r\n * v12.19 wrapper at src/percolator.rs:9654 calls accounts::expect_len(3).\r\n * Layout: [admin(s+w), slab(w), clock].\r\n */\r\nexport const ACCOUNTS_SET_ORACLE_PRICE_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ResolveMarket (tag 19): 2 accounts.\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj),\r\n * `handle_resolve_market` at src/v16_program.rs:12269:\r\n * [0] admin signer — `account(accounts, 0)` + `expect_signer(admin)`\r\n * [1] market writable — `account(accounts, 1)` + `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([admin(s+w), slab(w), clock, oracle], src/percolator.rs:9748) is stale on both\r\n * counts: the handler takes the slot from the `Clock::get()` syscall rather than a\r\n * clock account, and never touches an oracle account at all.\r\n *\r\n * `admin` is NOT writable: the handler calls `expect_signer(admin)` but never\r\n * `expect_writable(admin)`, and nothing debits it (ResolveMarket moves no\r\n * lamports). This matches ACCOUNTS_RESTART_ASSET_ORACLE, the closest analog —\r\n * also admin-gated, market-level, no token movement — which is\r\n * [authority(signer, !writable), market(writable)]. Marking a signer writable\r\n * when the program does not require it only widens the account's write lock.\r\n */\r\nexport const ACCOUNTS_RESOLVE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsurance (tag 41): 6 fixed accounts + 1 optional.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_insurance):\r\n * [0] authority signer, writable (insurance authority)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] destToken writable (authority's collateral ATA — destination)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA that signs token CPI)\r\n * [5] tokenProgram read-only\r\n * [6] ledger writable, optional (per-authority InsuranceLedger PDA)\r\n *\r\n * v12 stale ordering fixed: vaultPda was at [5] after tokenProgram.\r\n * v17 layout: dest_token → vault_token → vault_authority → token_program.\r\n * Only callable on terminal markets (mode==1, materialized_portfolio_count==0).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLimited (tag 23): 7 or 8 accounts.\r\n * On live markets the 8th oracle account is REQUIRED (upstream 8ce8d54):\r\n * the handler does a same-instruction accrue_market_to against the fresh\r\n * oracle price to prevent withdrawals against overstated insurance.\r\n * On resolved markets the oracle is frozen — 7 accounts suffice.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"authorityAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_LIVE: readonly AccountSpec[] = [\r\n ...ACCOUNTS_WITHDRAW_INSURANCE_LIMITED_RESOLVED,\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * PauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_PAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UnpauseMarket: 2 accounts\r\n */\r\nexport const ACCOUNTS_UNPAUSE_MARKET: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// G-3 / G-4 / G-2 fixes (audit-2026-04-27): missing ACCOUNTS_ specs.\r\n// Wrapper handlers at src/percolator.rs:10470 (reclaim), 10503 (settle),\r\n// 10557 (deposit_fee_credits), 10636 (convert_released_pnl), 9990\r\n// (set_insurance_withdraw_policy), 6876 (update_authority).\r\n// ============================================================================\r\n\r\n/**\r\n * ReclaimEmptyAccount (tag 25): 2 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10470.\r\n */\r\nexport const ACCOUNTS_RECLAIM_EMPTY_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SettleAccount (tag 26): 3 accounts. Permissionless.\r\n * Wrapper: src/percolator.rs:10503.\r\n */\r\nexport const ACCOUNTS_SETTLE_ACCOUNT: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositFeeCredits (tag 27): 6 accounts. Owner only.\r\n * Wrapper: src/percolator.rs:10557. SPL transfer requires userAta + vault writable.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_FEE_CREDITS: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ConvertReleasedPnl (tag 28): 3 base accounts + an optional NFT-holder trio.\r\n * Owner only. No token movement (internal PnL-bucket conversion within the\r\n * same portfolio).\r\n *\r\n * v17 wire account layout, VERIFIED against the deployed wrapper\r\n * percolator-prog@19d5d932 (program DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj):\r\n * `handle_convert_released_pnl` at src/v16_program.rs:11947 delegates its whole\r\n * account decode to `with_one_portfolio_view(program_id, accounts, true, ..)`\r\n * at src/v16_program.rs:17469, which reads:\r\n * [0] owner signer — `expect_signer(owner)` (owner_must_sign = true)\r\n * [1] market writable — `expect_writable` + `expect_owner`\r\n * [2] portfolio writable — `expect_writable` + `expect_owner`\r\n *\r\n * The v12.19 4-account layout this constant previously documented\r\n * ([user(s+w), slab(w), clock, oracle], src/percolator.rs:10636) is stale: there\r\n * is no clock account (the handler needs no slot) and no oracle account.\r\n *\r\n * `owner` is NOT writable: `with_one_portfolio_view` calls `expect_signer(owner)`\r\n * but never `expect_writable(owner)`, and unlike ACCOUNTS_INIT_USER /\r\n * ACCOUNTS_CLOSE_ACCOUNT — whose owners ARE writable because they pay or receive\r\n * portfolio rent — this instruction moves no lamports at all.\r\n *\r\n * OPTIONAL NFT-HOLDER TRIO at base index 3: when the signer is not the owner but\r\n * holds the portfolio's bound (escrowed) position NFT, `with_one_portfolio_view`\r\n * reads `optional_nft_holder_accounts(accounts, 3)` and authorises via\r\n * `authorize_owner_or_nft_holder`. Compose it with `withNftHolderAuth()`:\r\n * withNftHolderAuth(ACCOUNTS_CONVERT_RELEASED_PNL)\r\n */\r\nexport const ACCOUNTS_CONVERT_RELEASED_PNL: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"portfolio\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceWithdrawPolicy (tag 22): 2 accounts. Admin only.\r\n * Wrapper: src/percolator.rs:9990.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_WITHDRAW_POLICY: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateAuthority (tag 83, v12.18.x 4-way split): 3 accounts.\r\n * Wrapper: src/percolator.rs:6876.\r\n *\r\n * Both the current authority and the new authority must sign. For burn\r\n * (`new_pubkey == default()`) the new account is still passed but does\r\n * not need to sign per wrapper L7036 region.\r\n */\r\nexport const ACCOUNTS_UPDATE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"currentAuthority\", signer: true, writable: false },\r\n { name: \"newAuthority\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// ACCOUNT META BUILDERS\r\n// ============================================================================\r\n\r\n/**\r\n * Build AccountMeta array from spec and provided pubkeys.\r\n *\r\n * Accepts either:\r\n * - `PublicKey[]` — ordered array, one entry per spec account (legacy form)\r\n * - `Record` — named map keyed by account `name` (preferred form)\r\n *\r\n * Named-map form resolves accounts by spec name so callers don't have to\r\n * remember the positional order, and errors clearly on missing names.\r\n */\r\nexport function buildAccountMetas(\r\n spec: readonly AccountSpec[],\r\n keys: PublicKey[] | Record\r\n): AccountMeta[] {\r\n let keysArray: PublicKey[];\r\n\r\n if (Array.isArray(keys)) {\r\n keysArray = keys;\r\n } else {\r\n // Named map: resolve by spec name\r\n keysArray = spec.map((s) => {\r\n const key = (keys as Record)[s.name];\r\n if (!key) {\r\n throw new Error(\r\n `buildAccountMetas: missing key for account \"${s.name}\". ` +\r\n `Provided keys: [${Object.keys(keys).join(\", \")}]`\r\n );\r\n }\r\n return key;\r\n });\r\n }\r\n\r\n if (keysArray.length !== spec.length) {\r\n throw new Error(\r\n `Account count mismatch: expected ${spec.length}, got ${keysArray.length}`\r\n );\r\n }\r\n return spec.map((s, i) => ({\r\n pubkey: keysArray[i],\r\n isSigner: s.signer,\r\n isWritable: s.writable,\r\n }));\r\n}\r\n\r\n/**\r\n * CreateInsuranceMint: 9 accounts\r\n * Creates SPL mint PDA for insurance LP tokens. Admin only, once per market.\r\n */\r\nexport const ACCOUNTS_CREATE_INSURANCE_MINT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"collateralMint\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n { name: \"payer\", signer: true, writable: true },\r\n] as const;\r\n\r\n/**\r\n * DepositInsuranceLP: 8 accounts\r\n * Deposit collateral into insurance fund, receive LP tokens.\r\n */\r\nexport const ACCOUNTS_DEPOSIT_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"depositorAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceLP: 8 accounts\r\n * Burn LP tokens and withdraw proportional share of insurance fund.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_LP: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"insLpMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-627 / GH#1926: LpVaultWithdraw (tag 39)\r\n// ============================================================================\r\n\r\n/**\r\n * LpVaultWithdraw: 10 accounts (tag 39, PERC-627 / GH#1926 / PERC-8287)\r\n *\r\n * Burn LP vault tokens and withdraw proportional collateral from the LP vault.\r\n *\r\n * accounts[9] = creatorLockPda is REQUIRED since percolator-prog PR#170.\r\n * Non-creator withdrawers must pass the derived PDA key; if no lock exists\r\n * on-chain the enforcement is a no-op. Omitting it was the bypass vector\r\n * fixed in GH#1926. Use `deriveCreatorLockPda(programId, slab)` to compute.\r\n *\r\n * Accounts:\r\n * [0] withdrawer signer, read-only\r\n * [1] slab writable\r\n * [2] withdrawerAta writable (collateral destination)\r\n * [3] vault writable (collateral source)\r\n * [4] tokenProgram read-only\r\n * [5] lpVaultMint writable (LP tokens burned from here)\r\n * [6] withdrawerLpAta writable (LP tokens source)\r\n * [7] vaultAuthority read-only (PDA that signs token transfers)\r\n * [8] lpVaultState writable\r\n * [9] creatorLockPda writable (REQUIRED — derived from [\"creator_lock\", slab])\r\n */\r\nexport const ACCOUNTS_LP_VAULT_WITHDRAW: readonly AccountSpec[] = [\r\n { name: \"withdrawer\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"withdrawerLpAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"creatorLockPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * FundMarketInsurance: 5 accounts (PERC-306)\r\n * Fund per-market isolated insurance balance.\r\n */\r\nexport const ACCOUNTS_FUND_MARKET_INSURANCE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetInsuranceIsolation: 2 accounts (PERC-306)\r\n * Set max % of global fund this market can access.\r\n */\r\nexport const ACCOUNTS_SET_INSURANCE_ISOLATION: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-309: QueueWithdrawal / ClaimQueuedWithdrawal / CancelQueuedWithdrawal\r\n// ============================================================================\r\n\r\n/**\r\n * QueueWithdrawal: 5 accounts (PERC-309)\r\n * User queues a large LP withdrawal. Creates withdraw_queue PDA.\r\n */\r\nexport const ACCOUNTS_QUEUE_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"lpVaultState\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * ClaimQueuedWithdrawal: 10 accounts (PERC-309)\r\n * Burns LP tokens and releases one epoch tranche of SOL.\r\n */\r\nexport const ACCOUNTS_CLAIM_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"userAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * CancelQueuedWithdrawal: 3 accounts (PERC-309)\r\n * Cancels queue, closes withdraw_queue PDA, returns rent to user.\r\n */\r\nexport const ACCOUNTS_CANCEL_QUEUED_WITHDRAWAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"withdrawQueue\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-305: ExecuteAdl (tag 50) — Auto-Deleverage\r\n// ============================================================================\r\n\r\n/**\r\n * ExecuteAdl: 4+ accounts (PERC-305, tag 50)\r\n * Permissionless — surgically close/reduce the most profitable position\r\n * when pnl_pos_tot > max_pnl_cap. For non-Hyperp markets with backup oracles,\r\n * pass additional oracle accounts at accounts[4..].\r\n */\r\nexport const ACCOUNTS_EXECUTE_ADL: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_PERMISSIONLESS: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_FORCE_CLOSE_RESOLVED: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ADMIN_FORCE_CLOSE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n { name: \"oracle\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// CloseStaleSlabs (tag 51) / ReclaimSlabRent (tag 52)\r\n// ============================================================================\r\n\r\n/**\r\n * CloseStaleSlabs: 2 accounts (tag 51)\r\n * Admin closes a slab of an invalid/old layout and recovers rent SOL.\r\n */\r\nexport const ACCOUNTS_CLOSE_STALE_SLABS: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ReclaimSlabRent: 2 accounts (tag 52)\r\n * Reclaim rent from an uninitialised slab. Both dest and slab must sign.\r\n */\r\nexport const ACCOUNTS_RECLAIM_SLAB_RENT: readonly AccountSpec[] = [\r\n { name: \"dest\", signer: true, writable: true },\r\n { name: \"slab\", signer: true, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// AuditCrank (tag 53) — Permissionless invariant check\r\n// ============================================================================\r\n\r\n/**\r\n * AuditCrank: 1 account (tag 53)\r\n * Permissionless. Verifies conservation invariants; pauses market on violation.\r\n */\r\nexport const ACCOUNTS_AUDIT_CRANK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-622: AdvanceOraclePhase (permissionless)\r\n// ============================================================================\r\n\r\n/**\r\n * AdvanceOraclePhase: 1 account\r\n * Permissionless — no signer required beyond fee payer.\r\n */\r\nexport const ACCOUNTS_ADVANCE_ORACLE_PHASE: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_UPDATE_HYPERP_MARK: readonly AccountSpec[] = [\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dexPool\", signer: false, writable: false },\r\n { name: \"clock\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * CreateLpVault (tag 74): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_create_lp_vault):\r\n * [0] admin signer, writable (marketauth — pays for PDA creation)\r\n * [1] market read-only (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA — derived via deriveLpVaultRegistry())\r\n * [3] lpMint writable (LP share mint PDA — derived via deriveLpVaultMint())\r\n * [4] systemProgram read-only (required for create_account CPI)\r\n * [5] tokenProgram read-only\r\n *\r\n * v12 stale accounts removed: vaultAuthority, rent (Rent::get() used instead).\r\n * registry replaces lpVaultState; lpMint replaces lpVaultMint.\r\n */\r\nexport const ACCOUNTS_CREATE_LP_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * DepositToLpVault (tag 75): 10 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_deposit_to_lp_vault):\r\n * [0] depositor signer, writable (LP depositor; pays for ledger creation)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] lpMint writable (LP share mint PDA)\r\n * [4] depositorLpAta writable (depositor's LP token ATA — receives minted shares)\r\n * [5] sourceToken writable (depositor's collateral ATA — source)\r\n * [6] vaultToken writable (program vault token account — destination)\r\n * [7] ledger writable (LpBackingLedger PDA; lazily created on first deposit)\r\n * [8] tokenProgram read-only\r\n * [9] systemProgram read-only (required for ledger create_account CPI)\r\n * [10] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n *\r\n * v17 DUAL-DOMAIN: [10] is the OTHER pot's ledger. It is REQUIRED even when\r\n * uninitialised — NAV is summed across both pots, so omitting it understates NAV\r\n * and mints the depositor free shares at existing holders' expense. `ledger` at\r\n * [7] is always `registry.domain`'s; the instruction's `domain` argument selects\r\n * which of the two actually receives the backing.\r\n *\r\n * v12 stale accounts removed: vaultAuthority, lpVaultState. Added: ledger at [7],\r\n * systemProgram at [9]. registry replaces slab+lpVaultState. Reordered to match handler.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_DEPOSIT: readonly AccountSpec[] = [\r\n { name: \"depositor\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"lpMint\", signer: false, writable: true },\r\n { name: \"depositorLpAta\", signer: false, writable: true },\r\n { name: \"sourceToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * LpVaultCrankFees (tag 78): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_lp_vault_crank_fees):\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the target\r\n * ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry writable (LpVaultRegistry PDA)\r\n * [3] ledger writable (LpBackingLedger PDA for `registry.domain`)\r\n * [4] siblingLedger writable (LpBackingLedger PDA for `domain ^ 1`)\r\n * [5] systemProgram read-only (required to create a missing target ledger)\r\n *\r\n * v17 DUAL-DOMAIN: the instruction's `domain` argument picks which pot the fees\r\n * land in, and that pot's ledger is created on first use. Once deposits can be\r\n * routed, a vault whose money all went to the sibling has NO own-domain ledger,\r\n * so cranker had to become writable and the system program is now required.\r\n */\r\nexport const ACCOUNTS_LP_VAULT_CRANK_FEES: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: true },\r\n { name: \"ledger\", signer: false, writable: true },\r\n { name: \"siblingLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * RebalanceLpVaultBacking (tag 91): 6 accounts.\r\n *\r\n * Moves IDLE (fresh, unliened) backing between the two pots of the vault's asset,\r\n * carrying ledger principal in lockstep. No tokens move.\r\n *\r\n * [0] cranker signer, WRITABLE (permissionless; pays rent if the\r\n * destination ledger must be created)\r\n * [1] market writable (market-group slab; program-owned)\r\n * [2] registry read-only (LpVaultRegistry PDA)\r\n * [3] fromLedger writable (LpBackingLedger PDA for `fromDomain`)\r\n * [4] toLedger writable (LpBackingLedger PDA for `toDomain`)\r\n * [5] systemProgram read-only\r\n */\r\nexport const ACCOUNTS_REBALANCE_LP_VAULT_BACKING: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"registry\", signer: false, writable: false },\r\n { name: \"fromLedger\", signer: false, writable: true },\r\n { name: \"toLedger\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CHALLENGE_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"challenger\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESOLVE_DISPUTE: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"dispute\", signer: false, writable: true },\r\n { name: \"challengerAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_DEPOSIT_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_WITHDRAW_LP_COLLATERAL: readonly AccountSpec[] = [\r\n { name: \"user\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"userLpAta\", signer: false, writable: true },\r\n { name: \"lpVaultMint\", signer: false, writable: false },\r\n { name: \"lpVaultState\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"lpEscrow\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OFFSET_PAIR: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: true },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_ATTEST_CROSS_MARGIN: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slabA\", signer: false, writable: true },\r\n { name: \"slabB\", signer: false, writable: true },\r\n { name: \"attestation\", signer: false, writable: true },\r\n { name: \"pairPda\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8110: SetOiImbalanceHardBlock\r\n// ============================================================================\r\n\r\n/**\r\n * SetOiImbalanceHardBlock: 2 accounts\r\n * Sets the OI imbalance hard-block threshold (admin only)\r\n */\r\nexport const ACCOUNTS_SET_OI_IMBALANCE_HARD_BLOCK: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_MAX_PNL_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_OI_CAP_MULTIPLIER: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_DISPUTE_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_SET_LP_COLLATERAL_PARAMS: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-608: Position NFT Instructions (tags 64–69)\r\n// ============================================================================\r\n\r\n/**\r\n * MintPositionNft: 10 accounts\r\n * Creates a Token-2022 position NFT for an open position.\r\n */\r\nexport const ACCOUNTS_MINT_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"payer\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"owner\", signer: true, writable: false },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n { name: \"systemProgram\", signer: false, writable: false },\r\n { name: \"rent\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * TransferPositionOwnership: 8 accounts\r\n * Transfer position NFT and update on-chain owner. Requires pending_settlement == 0.\r\n */\r\nexport const ACCOUNTS_TRANSFER_POSITION_OWNERSHIP: readonly AccountSpec[] = [\r\n { name: \"currentOwner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"currentOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwnerAta\", signer: false, writable: true },\r\n { name: \"newOwner\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * BurnPositionNft: 7 accounts\r\n * Burns NFT and closes PositionNft + mint PDAs after position is closed.\r\n */\r\nexport const ACCOUNTS_BURN_POSITION_NFT: readonly AccountSpec[] = [\r\n { name: \"owner\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n { name: \"nftMint\", signer: false, writable: true },\r\n { name: \"ownerAta\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"token2022Program\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetPendingSettlement: 3 accounts\r\n * Keeper/admin sets pending_settlement flag before funding transfer.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_SET_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ClearPendingSettlement: 3 accounts\r\n * Keeper/admin clears pending_settlement flag after KeeperCrank.\r\n * Protected by admin allowlist (GH#1475).\r\n */\r\nexport const ACCOUNTS_CLEAR_PENDING_SETTLEMENT: readonly AccountSpec[] = [\r\n { name: \"keeper\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: false },\r\n { name: \"positionNftPda\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_TRANSFER_OWNERSHIP_CPI: readonly AccountSpec[] = [\r\n { name: \"caller\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"nftProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-8111: SetWalletCap\r\n// ============================================================================\r\n\r\n/**\r\n * SetWalletCap: 2 accounts\r\n * Sets the per-wallet position cap (admin only). capE6=0 disables.\r\n */\r\nexport const ACCOUNTS_SET_WALLET_CAP: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n] as const;\r\n\r\nexport const ACCOUNTS_RESCUE_ORPHAN_VAULT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"adminAta\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n { name: \"vaultPda\", signer: false, writable: false },\r\n] as const;\r\n\r\nexport const ACCOUNTS_CLOSE_ORPHAN_SLAB: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: true },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"vault\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// PERC-SetDexPool: SetDexPool (tag 74)\r\n// ============================================================================\r\n\r\n/**\r\n * SetDexPool: 3 accounts\r\n * Admin pins the approved DEX pool address for a HYPERP market.\r\n * After this call, UpdateHyperpMark rejects any pool that does not match.\r\n */\r\nexport const ACCOUNTS_SET_DEX_POOL: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"slab\", signer: false, writable: true },\r\n { name: \"poolAccount\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// InitMatcherCtx (tag 83) — v17 wire\r\n//\r\n// CONFIRMED (forensic rebuild + live simulateTransaction, 2026-07-15, see\r\n// ~/v17/DECISIONS-LEDGER.md \"Pinned deployed revisions\" section): the DEPLOYED\r\n// wrapper (69VUZ7… = percolator-prog@e26c97a4) HAS InitMatcherCtx live at tag\r\n// 83. The protocol-fee instructions below were renumbered to 84/85\r\n// (WithdrawProtocolFee, SetProtocolFeeAuthority) specifically to keep this\r\n// tag free for InitMatcherCtx — see ACCOUNTS_WITHDRAW_PROTOCOL_FEE /\r\n// ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY below.\r\n// ============================================================================\r\n\r\n/**\r\n * InitMatcherCtx (tag 83): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_init_matcher_ctx):\r\n * [0] lpOwner signer (LP portfolio owner wallet)\r\n * [1] market read-only (program-owned market slab)\r\n * [2] lpPortfolio read-only (LP's portfolio; wrapper verifies provenance + owner)\r\n * [3] matcherCtx writable (320-byte account pre-created, owned by matcherProg)\r\n * [4] matcherProg read-only, executable (the external matcher program)\r\n * [5] matcherDelegate read-only (PDA derived via deriveMatcherDelegate(); wrapper signs it)\r\n *\r\n * PREREQUISITE: SetMatcherConfig (tag 68, enabled=1) must be called first — the wrapper\r\n * reads the LP portfolio's matcher config tail and verifies all three keys match before\r\n * calling the matcher CPI.\r\n *\r\n * The wrapper uses invoke_signed with the delegate seeds to make matcherDelegate a signer\r\n * in the inner CPI to the matcher's process_init (tag 2). No client-side signing of\r\n * matcherDelegate is needed — it is passed as a regular (non-signer) account here.\r\n */\r\nexport const ACCOUNTS_INIT_MATCHER_CTX: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: true },\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK A — oracle-config account specs (tags 34, 35, 36, 62, 63)\r\n// ============================================================================\r\n\r\n/**\r\n * ConfigureHybridOracle (tag 34): 2 fixed accounts + variable oracle feed accounts.\r\n *\r\n * Fixed accounts:\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned market account)\r\n *\r\n * Dynamic accounts [2..2+oracle_leg_count]:\r\n * oracle feed accounts (read-only). Pass 1-3 Pyth/on-chain price feed accounts\r\n * matching the oracleLegFeeds pubkeys encoded in the instruction data.\r\n *\r\n * (v16_program.rs handle_configure_hybrid_oracle lines 10414-10438)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_HYBRID_ORACLE: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n // [2..] oracle feed accounts appended by caller per oracle_leg_count\r\n] as const;\r\n\r\n/**\r\n * ConfigureEwmaMark (tag 35): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * No feed accounts needed — EWMA-mark is authority-pushed, not oracle-polled.\r\n * (v16_program.rs handle_configure_ewma_mark lines 10553-10557)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushEwmaMark (tag 36): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_ewma_mark lines 10766-10770)\r\n */\r\nexport const ACCOUNTS_PUSH_EWMA_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ConfigureAuthMark (tag 62): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_configure_auth_mark lines 10660-10664)\r\n */\r\nexport const ACCOUNTS_CONFIGURE_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * PushAuthMark (tag 63): 2 accounts.\r\n *\r\n * [0] oracleAuthority signer (must be the asset's oracle_authority)\r\n * [1] market writable (program-owned)\r\n *\r\n * (v16_program.rs handle_push_auth_mark lines 10842-10846)\r\n */\r\nexport const ACCOUNTS_PUSH_AUTH_MARK: readonly AccountSpec[] = [\r\n { name: \"oracleAuthority\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// TASK B — SetMatcherConfig account spec (tag 68)\r\n// ============================================================================\r\n\r\n/**\r\n * SetMatcherConfig (tag 68): 3 accounts when disabling (enabled=0),\r\n * 6 accounts when enabling (enabled=1).\r\n *\r\n * [0] lpOwner signer (portfolio owner)\r\n * [1] market read-only (program-owned; owner-check only)\r\n * [2] lpPortfolio writable (program-owned portfolio)\r\n * [3] matcherProg read-only, executable (required when enabled=1 only)\r\n * [4] matcherCtx read-only (matcher context; owned by matcherProg; required when enabled=1)\r\n * [5] matcherDelegate read-only PDA (derived via deriveMatcherDelegate(); required when enabled=1)\r\n *\r\n * Note: accounts [3..5] are only validated by the on-chain handler when enabled=1.\r\n * When disabling (enabled=0), pass only accounts [0..2] or include [3..5] as no-ops.\r\n * (v16_program.rs handle_set_matcher_config lines 7516-7557)\r\n */\r\nexport const ACCOUNTS_SET_MATCHER_CONFIG: readonly AccountSpec[] = [\r\n { name: \"lpOwner\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: false },\r\n { name: \"lpPortfolio\", signer: false, writable: true },\r\n // When enabled=1, also pass:\r\n { name: \"matcherProg\", signer: false, writable: false },\r\n { name: \"matcherCtx\", signer: false, writable: false },\r\n { name: \"matcherDelegate\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// Protocol-fee program change (tags 84/85) — v17 wire, WrapperConfigV16 496B\r\n// See ~/v17/PROTOCOL-FEE-DESIGN.md §3. Verified against\r\n// percolator-prog/src/v16_program.rs (feat/protocol-fee-taker-only@626fb617)\r\n// handle_withdraw_protocol_fee / handle_set_protocol_fee_authority.\r\n//\r\n// Renumbered 2026-07-15 (83→84, 84→85) to keep tag 83 reserved for\r\n// InitMatcherCtx (see ACCOUNTS_INIT_MATCHER_CTX above and\r\n// ~/v17/DECISIONS-LEDGER.md, \"Pinned deployed revisions\").\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawProtocolFee (tag 84): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_protocol_fee):\r\n * [0] authority signer, writable (must equal cfg.protocol_fee_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account)\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * Pays out from the accrued-but-unwithdrawn protocol claim\r\n * (protocol_fee_accrued_atoms - protocol_fee_withdrawn_atoms). `amount == 0`\r\n * in the instruction data means \"withdraw all currently-available capacity\".\r\n * No insurance-withdraw-cooldown gate (that mechanism guards creator-facing\r\n * domain budgets; the protocol's claim is a separate, non-domain balance).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_PROTOCOL_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * SetProtocolFeeAuthority (tag 85): 3 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_set_protocol_fee_authority):\r\n * [0] upgradeAuthority signer (must equal the program's BPF upgrade authority)\r\n * [1] programData read-only (ProgramData PDA under bpf_loader_upgradeable,\r\n * seeds [program_id])\r\n * [2] market writable (program-owned market-group slab)\r\n *\r\n * Rotates cfg.protocol_fee_authority. Gated on the program's upgrade\r\n * authority — NOT marketauth, NOT insurance_authority, NOT any\r\n * creator-facing gate. No global fan-out: call once per market.\r\n */\r\nexport const ACCOUNTS_SET_PROTOCOL_FEE_AUTHORITY: readonly AccountSpec[] = [\r\n { name: \"upgradeAuthority\", signer: true, writable: false },\r\n { name: \"programData\", signer: false, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 FEE-COLLECTION SPLIT (tags 86/87/88)\r\n// percolator-prog feat/protocol-fee-taker-only@2b3a6a65\r\n// ============================================================================\r\n\r\n/**\r\n * UpdateFeeSplit (tag 86): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_fee_split):\r\n * [0] admin signer (must match cfg.marketauth via expect_live_authority)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors the neighbouring marketauth-gated single-field setters\r\n * (handle_update_fee_redirect_policy, handle_update_market_init_fee_policy) —\r\n * signer/writable/owner checks, then `expect_live_authority(&cfg.marketauth)`.\r\n *\r\n * ⚠ After `StakeInitPool` rotates cfg.marketauth to the stake-pool PDA, this\r\n * layout is unreachable at top level; use the stake CPI proxy (stake tag 25),\r\n * whose layout is ACCOUNTS_STAKE_ADMIN_UPDATE_FEE_SPLIT in solana/stake.ts.\r\n */\r\nexport const ACCOUNTS_UPDATE_FEE_SPLIT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * WithdrawInsuranceReserveToStake (tag 87): 7 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_withdraw_insurance_reserve_to_stake):\r\n * [0] cranker signer (permissionless — any signer, pays fees only)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] stakePool read-only (PDA [\"stake_pool\", market] under the\r\n * wrapper's PINNED stake program id; its owner is\r\n * asserted BEFORE any byte is read — the forgery gate)\r\n * [3] stakeVault writable (must equal pool.vault, read out of [2])\r\n * [4] vaultToken writable (this market's collateral vault token acct)\r\n * [5] vaultAuthority read-only (PDA derived by derive_vault_authority)\r\n * [6] tokenProgram read-only\r\n *\r\n * Note [2] is NOT writable — the wrapper only reads the pool to derive the\r\n * destination; percolator-stake's own AccrueFees is what later credits it.\r\n *\r\n * Failure codes are deliberately distinct so a keeper can tell the cases\r\n * apart: Custom(53) NoInsuranceReserveToClaim, Custom(54) StakePoolNotBound,\r\n * Custom(55) StakePoolOwnerMismatch, Custom(56) StakePoolAuthorityMismatch,\r\n * Custom(57) StakePoolMarketMismatch, Custom(58) StakePoolWrapperMismatch,\r\n * Custom(59) StakePoolModeMismatch, Custom(60) StakeProgramNotPinned.\r\n */\r\nexport const ACCOUNTS_WITHDRAW_INSURANCE_RESERVE_TO_STAKE: readonly AccountSpec[] = [\r\n { name: \"cranker\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"stakePool\", signer: false, writable: false },\r\n { name: \"stakeVault\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n/**\r\n * UpdateMaintenanceFeePerSlot (tag 88): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs\r\n * handle_update_maintenance_fee_per_slot) — identical to tag 86:\r\n * [0] admin signer (must match cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * ⚠ The instruction payload is a u128, not a u64. See\r\n * encodeUpdateMaintenanceFeePerSlot in abi/instructions.ts.\r\n *\r\n * Same StakeInitPool reachability caveat as tag 86; proxy is stake tag 26.\r\n */\r\nexport const ACCOUNTS_UPDATE_MAINTENANCE_FEE_PER_SLOT: readonly AccountSpec[] = [\r\n { name: \"admin\", signer: true, writable: false },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * UpdateTradeFeePolicy (tag 55): 2 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_update_trade_fee_policy):\r\n * [0] authority signer (must match ASSET 0's insurance_authority — NOT\r\n * cfg.marketauth)\r\n * [1] market writable (program-owned market-group slab)\r\n *\r\n * Mirrors ACCOUNTS_UPDATE_BACKING_FEE_POLICY (tag 51), which shares the\r\n * asset-0 insurance_authority gate. Stranded by BindInsuranceAuthority rather\r\n * than by StakeInitPool; proxy is stake tag 28.\r\n *\r\n * NOTE: `writable: true` on [0] matches the existing tag-51 spec and reflects\r\n * the authority normally also being the fee payer. The program itself only\r\n * calls `expect_signer(authority)` — it never writes to this account.\r\n */\r\nexport const ACCOUNTS_UPDATE_TRADE_FEE_POLICY: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n/**\r\n * ExpireBackingBucket (tag 89): 1 account. PERMISSIONLESS.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_expire_backing_bucket):\r\n * [0] market writable (program-owned market-group slab)\r\n *\r\n * That is the WHOLE list. The handler reads `account(accounts, 0)` and applies\r\n * exactly `expect_writable` + `expect_owner(market, program_id)`. There is NO\r\n * `expect_signer` anywhere in it, and no token/vault/authority account — the\r\n * instruction moves no tokens. The transaction still needs a fee payer, but\r\n * that signer is not an account of this instruction and is not checked against\r\n * anything.\r\n *\r\n * This is deliberate: a bricked market must be recoverable by ANY keeper, not\r\n * only by an authority that may be a cold key or a stake-pool PDA. The\r\n * safety gate is the engine's own precondition (bucket `Fresh` AND lapsed\r\n * against the runtime `Clock`), not an authority check. See\r\n * encodeExpireBackingBucket in abi/instructions.ts for the keeper contract and\r\n * the failure codes — Custom(21) not-Live, Custom(9) domain out of range,\r\n * Custom(19) bucket not `Fresh`-and-lapsed.\r\n */\r\nexport const ACCOUNTS_EXPIRE_BACKING_BUCKET: readonly AccountSpec[] = [\r\n { name: \"market\", signer: false, writable: true },\r\n] as const;\r\n\r\n// ============================================================================\r\n// v17 CREATOR FEE CLAIM (tag 90)\r\n// percolator-prog, 2026-07-23 creator-fee-claim design §3.\r\n// ============================================================================\r\n\r\n/**\r\n * WithdrawCreatorFee (tag 90): 6 accounts.\r\n *\r\n * v17 wire account layout (v16_program.rs handle_withdraw_creator_fee) —\r\n * BYTE-FOR-BYTE THE SAME SHAPE AS ACCOUNTS_WITHDRAW_PROTOCOL_FEE (tag 84);\r\n * only the authority the program checks [0] against differs:\r\n * [0] authority signer, writable (must equal ASSET 0's insurance_operator)\r\n * [1] market writable (program-owned market-group slab)\r\n * [2] destToken writable (destination token account, owned by [0])\r\n * [3] vaultToken writable (program vault token account — source)\r\n * [4] vaultAuthority read-only (PDA [\"vault\", market], derives via deriveVaultAuthority)\r\n * [5] tokenProgram read-only\r\n *\r\n * The handler applies expect_signer([0]) + expect_writable([1],[2],[3]) +\r\n * expect_owner([1], program_id) + verify_token_program([5]) + expect_key on the\r\n * derived vault authority. `writable: true` on [0] mirrors the tag-84 spec and\r\n * reflects the authority normally also being the transaction fee payer; the\r\n * program itself only calls expect_signer on it.\r\n *\r\n * ⚠ AUTHORITY IS asset 0's `insurance_operator`, NOT `cfg.marketauth` — and it\r\n * does NOT accept marketauth as an alternate the way\r\n * verify_domain_withdrawal_preflight does. That divergence is deliberate: on a\r\n * staked market marketauth IS the stake-pool PDA, so accepting it would let the\r\n * pool claim the creator's revenue. It also means claiming keeps working after\r\n * StakeInitPool, since staking never rotates insurance_operator.\r\n *\r\n * Pays out of `creator_fee_claimable_atoms` (WrapperConfigV17 byte 568) by an\r\n * EXACT debit — no withdraw-all sentinel, no partial fill, no\r\n * insurance-withdraw cooldown or backstop-health gate (this counter is disjoint\r\n * from the loss backstop, so backstop gating does not apply).\r\n */\r\nexport const ACCOUNTS_WITHDRAW_CREATOR_FEE: readonly AccountSpec[] = [\r\n { name: \"authority\", signer: true, writable: true },\r\n { name: \"market\", signer: false, writable: true },\r\n { name: \"destToken\", signer: false, writable: true },\r\n { name: \"vaultToken\", signer: false, writable: true },\r\n { name: \"vaultAuthority\", signer: false, writable: false },\r\n { name: \"tokenProgram\", signer: false, writable: false },\r\n] as const;\r\n\r\n// ============================================================================\r\n// WELL-KNOWN PROGRAM/SYSVAR KEYS\r\n// ============================================================================\r\n\r\nexport const WELL_KNOWN = {\r\n tokenProgram: TOKEN_PROGRAM_ID,\r\n clock: SYSVAR_CLOCK_PUBKEY,\r\n rent: SYSVAR_RENT_PUBKEY,\r\n systemProgram: SystemProgram.programId,\r\n} as const;\r\n","/**\r\n * Percolator v17 program error definitions.\r\n *\r\n * Source: v16_program.rs PercolatorError enum (lines 174-226 in v17 wrapper).\r\n * Ordinals 0-29 = toly base errors; 30-41 = fork LP-vault; 42-46 = fork NFT/B-3;\r\n * 47-48 = insurance withdrawal policy (F-1/F-2); 49 = EngineInsufficientInitialMargin;\r\n * 50 = LpVaultDepositBelowMinimumLiquidity (N7 dead-share floor); 51 =\r\n * FeeSplitFloorViolation (creator/LP/insurance split floor, meaning narrowed to\r\n * tag 86 — see its entry); 52-53 = fee-collection split; 54-60 =\r\n * load_bound_stake_pool diagnostics; 61 = AssetSlotAlreadyConfigured;\r\n * 62 = CreatorFeeOverClaim (creator fee claim, tag 90 — NOT yet deployed).\r\n *\r\n * Ordinals 0-61 read directly off the PercolatorError enum in\r\n * percolator-prog@10acb5ae, which is the source deployed to devnet wrapper\r\n * DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n * 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n * Ordinal 49 is CONFIRMED against that enum; an earlier \"discriminant\r\n * tentative\" TODO here is resolved.\r\n *\r\n * INVARIANT: ordinals must NOT be reordered (Rust enum discriminants are\r\n * sequential from 0). CI asserts each ordinal in tests/v16_kani.rs.\r\n *\r\n * v17 breaking changes vs v12.x:\r\n * - Errors 0-29 have completely different names and semantics from v12.\r\n * - Errors 30-41 are LP-vault (moved from v12.x range 30-41 to same ordinals).\r\n * - Errors 42-46 are NFT/B-3 (new in v17).\r\n * - v12.x errors 28-65 are entirely removed.\r\n */\r\nexport interface ErrorInfo {\r\n name: string;\r\n hint: string;\r\n}\r\n\r\nexport const PERCOLATOR_ERRORS: Record = {\r\n // ── toly base errors (0-29) ─────────────────────────────────────────────────\r\n 0: {\r\n name: \"InvalidMagic\",\r\n hint: \"Account magic mismatch — not a v17 percolator account. Check the market group address.\",\r\n },\r\n 1: {\r\n name: \"InvalidVersion\",\r\n hint: \"Account version mismatch. Expected VERSION=17 (WrapperConfigV16 576B after the fee-collection split; 496B before it). The program may need upgrading, or the account predates the protocol-fee redeploy.\",\r\n },\r\n 2: {\r\n name: \"AlreadyInitialized\",\r\n hint: \"Account is already initialized. Use a different account or check the market group address.\",\r\n },\r\n 3: {\r\n name: \"NotInitialized\",\r\n hint: \"Account is not initialized. Run InitMarket first.\",\r\n },\r\n 4: {\r\n name: \"InvalidAccountKind\",\r\n hint: \"Wrong account kind (market group vs portfolio vs insurance-ledger). Check account addresses.\",\r\n },\r\n 5: {\r\n name: \"InvalidAccountLen\",\r\n hint: \"Account data length is incorrect. The account may be from a different program version.\",\r\n },\r\n 6: {\r\n name: \"ExpectedSigner\",\r\n hint: \"Missing required signature. Ensure the correct authority wallet is signing.\",\r\n },\r\n 7: {\r\n name: \"ExpectedWritable\",\r\n hint: \"Account must be marked writable. This is likely a client-side account-list bug.\",\r\n },\r\n 8: {\r\n name: \"Unauthorized\",\r\n hint: \"Not authorized for this operation. Check marketauth or asset_admin authority.\",\r\n },\r\n 9: {\r\n name: \"InvalidInstruction\",\r\n hint: \"Unknown instruction tag. The SDK and program versions may be mismatched.\",\r\n },\r\n 10: {\r\n name: \"InvalidMint\",\r\n hint: \"Token mint does not match the market's collateral mint.\",\r\n },\r\n 11: {\r\n name: \"InvalidTokenAccount\",\r\n hint: \"Token account is invalid. Ensure you have a correctly configured ATA.\",\r\n },\r\n 12: {\r\n name: \"InvalidVaultAccount\",\r\n hint: \"Vault account is invalid or does not match the market vault PDA.\",\r\n },\r\n 13: {\r\n name: \"InvalidTokenProgram\",\r\n hint: \"Invalid token program. Expected SPL Token or Token-2022.\",\r\n },\r\n 14: {\r\n name: \"EngineInvalidConfig\",\r\n hint: \"Engine config is invalid. A required config field is missing or out of range.\",\r\n },\r\n 15: {\r\n name: \"EngineArithmeticOverflow\",\r\n hint: \"Arithmetic overflow in engine calculation. Try a smaller amount or position size.\",\r\n },\r\n 16: {\r\n name: \"EngineProvenanceMismatch\",\r\n hint: \"Portfolio provenance mismatch — the portfolio was not created for this market group.\",\r\n },\r\n 17: {\r\n name: \"EngineHiddenLeg\",\r\n hint: \"Engine detected a hidden leg (unexpected zero-size outstanding position). Internal error.\",\r\n },\r\n 18: {\r\n name: \"EngineInvalidLeg\",\r\n hint: \"Engine received an invalid trade leg. Check asset_index and size.\",\r\n },\r\n 19: {\r\n name: \"EngineStale\",\r\n hint: \"Engine position is stale — the market mark price has not been updated recently.\",\r\n },\r\n 20: {\r\n name: \"EngineBStale\",\r\n hint: \"Engine B-side (batch) position stale. The batch crank needs to run.\",\r\n },\r\n 21: {\r\n name: \"EngineLockActive\",\r\n hint: \"Engine lock is active — a close or recovery is in progress. Wait for it to complete.\",\r\n },\r\n 22: {\r\n name: \"EngineNonProgress\",\r\n hint: \"Engine operation made no progress. This usually means a crank was called with nothing to do.\",\r\n },\r\n 23: {\r\n name: \"EngineRecoveryRequired\",\r\n hint: \"Engine requires a recovery crank before normal operations can resume.\",\r\n },\r\n 24: {\r\n name: \"EngineCounterOverflow\",\r\n hint: \"Engine counter overflow — too many assets or positions. Contact support.\",\r\n },\r\n 25: {\r\n name: \"EngineCounterUnderflow\",\r\n hint: \"Engine counter underflow — attempted to decrement a zero counter. Internal error.\",\r\n },\r\n 26: {\r\n name: \"OracleInvalid\",\r\n hint: \"Oracle data is invalid. Check the oracle account is a valid Pyth PriceUpdateV2 feed.\",\r\n },\r\n 27: {\r\n name: \"OracleStale\",\r\n hint: \"Oracle price is stale. Wait for the oracle to publish a fresh price.\",\r\n },\r\n 28: {\r\n name: \"OracleConfTooWide\",\r\n hint: \"Oracle confidence interval too wide. Wait for more stable market conditions.\",\r\n },\r\n 29: {\r\n name: \"InvalidOracleKey\",\r\n hint: \"Oracle account key does not match the market's configured oracle feed ID.\",\r\n },\r\n // ── Fork LP-vault errors (30-41) ─────────────────────────────────────────────\r\n 30: {\r\n name: \"LpVaultAlreadyExists\",\r\n hint: \"LP vault already created for this asset domain. Each domain can only have one LP vault.\",\r\n },\r\n 31: {\r\n name: \"LpVaultNotFound\",\r\n hint: \"LP vault does not exist for this asset domain. Call CreateLpVault (tag 74) first.\",\r\n },\r\n 32: {\r\n name: \"LpVaultPaused\",\r\n hint: \"LP vault is paused. Wait for the vault to be unpaused by the admin.\",\r\n },\r\n 33: {\r\n name: \"LpVaultSharesOutstanding\",\r\n hint: \"Cannot close LP vault — shares are still outstanding. All redeemers must exit first.\",\r\n },\r\n 34: {\r\n name: \"LpVaultZeroAmount\",\r\n hint: \"LP vault deposit or redemption amount must be greater than zero.\",\r\n },\r\n 35: {\r\n name: \"LpVaultInsufficientShares\",\r\n hint: \"Insufficient LP vault shares to redeem. Check your share balance.\",\r\n },\r\n 36: {\r\n name: \"LpVaultCooldownActive\",\r\n hint: \"LP vault redemption cooldown is still active. Wait for the cooldown period to elapse.\",\r\n },\r\n 37: {\r\n name: \"LpVaultOiReservationViolated\",\r\n hint: \"LP vault deposit would violate the OI reservation limit. The vault has insufficient capacity.\",\r\n },\r\n 38: {\r\n name: \"LpVaultNoFeesToCrank\",\r\n hint: \"No new fees to distribute to the LP vault. Wait for more trading activity.\",\r\n },\r\n 39: {\r\n name: \"LpVaultSupplyMismatch\",\r\n hint: \"LP vault share supply / capital mismatch. Internal invariant violation — please report.\",\r\n },\r\n 40: {\r\n name: \"LpVaultAuthorityMismatch\",\r\n hint: \"LP vault authority mismatch. The vault belongs to a different market group or admin.\",\r\n },\r\n 41: {\r\n name: \"LpVaultZeroSharesMinted\",\r\n hint: \"First LP deposit minted zero shares (capital too small relative to existing NAV). Deposit a larger amount.\",\r\n },\r\n // ── Fork NFT / B-3 errors (42-46) ────────────────────────────────────────────\r\n 42: {\r\n name: \"NftRegistryNotFound\",\r\n hint: \"NFT registry not found. Call SetNftProgramId (tag 73) to register the percolator-nft program first.\",\r\n },\r\n 43: {\r\n name: \"NftPortfolioNotTransferable\",\r\n hint: \"Portfolio is not in a transferable state. Ensure the portfolio has no open positions or pending operations.\",\r\n },\r\n 44: {\r\n name: \"NftTransferSelfOrZero\",\r\n hint: \"Cannot transfer portfolio to the zero address or to the current owner.\",\r\n },\r\n 45: {\r\n name: \"NftInvalidMintAuthority\",\r\n hint: \"NFT mint authority mismatch. The percolator-nft program may not match the registered NFT program ID.\",\r\n },\r\n 46: {\r\n name: \"NftPortfolioProvenance\",\r\n hint: \"Portfolio provenance mismatch for NFT transfer. The portfolio was not created for this market group.\",\r\n },\r\n // ── Insurance withdrawal policy enforcement (F-1 / F-2) (47-48) ─────────────\r\n // Source: v16_program.rs PercolatorError variants appended after NftPortfolioProvenance.\r\n 47: {\r\n name: \"InsuranceWithdrawCooldownActive\",\r\n hint: \"Insurance withdrawal cooldown is still active (F-1). Wait for the cooldown period to elapse before withdrawing.\",\r\n },\r\n 48: {\r\n name: \"InsuranceWithdrawCeilingExceeded\",\r\n hint: \"Insurance withdrawal would exceed the deposits-only ceiling (F-2). Reduce the withdrawal amount or wait for more deposits.\",\r\n },\r\n // ── EngineInsufficientInitialMargin (49) ─────────────────────────────────────\r\n // Ordinal 49 CONFIRMED against the PercolatorError enum in\r\n // percolator-prog@10acb5ae (appended after InsuranceWithdrawCeilingExceeded=48,\r\n // before LpVaultDepositBelowMinimumLiquidity=50). This is a distinct error for\r\n // initial-margin failure, previously collapsed into the opaque\r\n // EngineInvalidConfig=14.\r\n 49: {\r\n name: \"EngineInsufficientInitialMargin\",\r\n hint: \"Insufficient initial margin for this trade or position open. Deposit more collateral or reduce the position size.\",\r\n },\r\n // ── BUG-2 / N7: LP vault genesis dead-share floor (50) ───────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // EngineInsufficientInitialMargin=49 (confirmed on-chain 2026-07-16 against\r\n // fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit a3cb4390).\r\n 50: {\r\n name: \"LpVaultDepositBelowMinimumLiquidity\",\r\n hint: \"The LP vault's true first deposit must exceed LP_VAULT_MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening). Increase the first deposit amount.\",\r\n },\r\n // ── Fee-split floor enforcement (51) ──────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // LpVaultDepositBelowMinimumLiquidity=50 (confirmed on-chain 2026-07-16\r\n // against fresh wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj, commit\r\n // a3cb4390).\r\n //\r\n // ⚠ MEANING NARROWED as of percolator-prog@10acb5ae (devnet 2026-07-22).\r\n // This code originally came from `policy_v16::fee_split_floor_ok`, a\r\n // TOLERANCE-based check on the two-rate (trade_fee_base_bps +\r\n // backing_fee_bps) split raised from UpdateBackingFeePolicy (tag 51) /\r\n // UpdateTradeFeePolicy. That function is RETIRED and has no live call sites.\r\n // The ordinal is REUSED (not vacated — it is wire-visible) and is now raised\r\n // only by `policy_v16::validate_fee_split` from UpdateFeeSplit (tag 86),\r\n // EXACTLY and with no tolerance, against the bps floors below.\r\n 51: {\r\n name: \"FeeSplitFloorViolation\",\r\n hint: \"UpdateFeeSplit (tag 86) shares violate the on-chain floors: creator_share_bps must be <= 3600 (45% of the 8000 remainder), lp_share_bps >= 3200 (40%), insurance_share_bps >= 1200 (15%). Enforced exactly, with no rounding tolerance. Use validateFeeSplit() before sending. Note the shares must ALSO sum to exactly 8000 — that separate failure is Custom(52) FeeSplitSumInvalid.\",\r\n },\r\n // ── Fee-collection split (52-53) ──────────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variants appended after\r\n // FeeSplitFloorViolation=51 on percolator-prog\r\n // feat/protocol-fee-taker-only@2b3a6a65. DEPLOYED as of 2026-07-22: the\r\n // devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj now carries\r\n // percolator-prog@10acb5ae (hash 6b2fda2363352aba0ef88abde0d398f9dd477b12\r\n // 08507e7e8393586ed5458931), so 52-61 are observable on-chain.\r\n 52: {\r\n name: \"FeeSplitSumInvalid\",\r\n hint: \"UpdateFeeSplit (tag 86) shares do not sum to exactly FEE_SHARE_TOTAL_BPS (8000 = 10_000 - PROTOCOL_FEE_BPS). creator_share_bps + lp_share_bps + insurance_share_bps must equal 8000. Use validateFeeSplit() before sending.\",\r\n },\r\n 53: {\r\n name: \"NoInsuranceReserveToClaim\",\r\n hint: \"WithdrawInsuranceReserveToStake (tag 87) was called with nothing available (insurance_reserve_accrued_atoms == insurance_reserve_withdrawn_atoms). Not an error condition for a keeper — the leg is simply already fully pushed; back off and retry after more trade volume.\",\r\n },\r\n // ── load_bound_stake_pool diagnostics (54-60) ─────────────────────────────\r\n // Source: v16_program.rs, same branch. These seven previously ALL returned\r\n // Unauthorized, which left a keeper unable to tell \"this market never bound a\r\n // pool\" from \"someone pointed a forged pool at us\". Each failure of tag 87's\r\n // destination-resolution now has its own code.\r\n //\r\n // ⚠ ORDINAL 55 CHANGED MEANING during development: it was briefly\r\n // StakePoolAssetAdminNotBurned, an ineffective mitigation that has been\r\n // removed. That variant existed only on an unmerged branch and was NEVER\r\n // deployed, so no on-chain consumer has ever observed the old meaning.\r\n 54: {\r\n name: \"StakePoolNotBound\",\r\n hint: \"Asset 0's insurance_authority is still zero: no stake pool has ever been bound to this market, so there is no staker constituency owed the insurance leg. Call the stake program's BindInsuranceAuthority (stake tag 19) first — it is required, or the insurance/staker leg has no exit.\",\r\n },\r\n 55: {\r\n name: \"StakePoolOwnerMismatch\",\r\n hint: \"The supplied stake-pool account is not owned by the wrapper's pinned STAKE_PROGRAM_ID. THIS IS THE FORGERY GATE — it is checked before any byte of the account is read. Pass the pool PDA ['stake_pool', market] derived under the canonical stake program (devnet GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3).\",\r\n },\r\n 56: {\r\n name: \"StakePoolAuthorityMismatch\",\r\n hint: \"The PDA ['vault_auth', pool] derived under the pool account's owning program does not equal the bound insurance_authority. The supplied pool is not the one that bound itself to this market.\",\r\n },\r\n 57: {\r\n name: \"StakePoolMarketMismatch\",\r\n hint: \"The stake pool's own stored `slab` field does not name this market. You passed a pool belonging to a different market.\",\r\n },\r\n 58: {\r\n name: \"StakePoolWrapperMismatch\",\r\n hint: \"The stake pool's stored `percolator_program` (its CPI target) is not this wrapper deployment. The pool was initialized against a different wrapper program id.\",\r\n },\r\n 59: {\r\n name: \"StakePoolModeMismatch\",\r\n hint: \"The stake pool is not in insurance-LP mode (pool_mode != 0). Trading-mode pools carry no FlushToInsurance loss exposure, so they are not owed the insurance/staker fee leg.\",\r\n },\r\n 60: {\r\n name: \"StakeProgramNotPinned\",\r\n hint: \"This wrapper build has no pinned stake program id, so WithdrawInsuranceReserveToStake (tag 87) has no destination it is willing to trust and refuses to move tokens. Emitted by every non-devnet build: v17 percolator-stake has no mainnet deployment. The atoms stay safe in header.insurance.\",\r\n },\r\n // ── Program bug fixes, 2026-07-22 (61) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // StakeProgramNotPinned=60, percolator-prog@10acb5ae. DEPLOYED to devnet\r\n // wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj (hash-verified\r\n // 6b2fda2363352aba0ef88abde0d398f9dd477b1208507e7e8393586ed5458931).\r\n 61: {\r\n name: \"AssetSlotAlreadyConfigured\",\r\n hint: \"UpdateAssetLifecycle(ACTIVATE) named an asset slot BELOW max_market_slots that is already configured and live (Active / DrainOnly / Recovery). Only two activations are legal: APPEND at asset_index == max_market_slots, or RE-ACTIVATE a slot whose lifecycle is Retired. InitMarket pre-configures slots 0..max_portfolio_assets, so on a market created with max_portfolio_assets > 1 every one of those slots hits this. Previously surfaced as the misleading Custom(21) EngineLockActive.\",\r\n },\r\n // ── Creator fee claim, 2026-07-24 (62) ────────────────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // AssetSlotAlreadyConfigured=61. Ordinals 0-61 are unmoved (pinned by\r\n // v16_cu.rs::v17_new_error_ordinals_are_appended_at_the_tail and\r\n // v16_fee_split.rs::fee_split_error_ordinals_are_pinned).\r\n // ⚠ NOT YET DEPLOYED — this ships with the creator-fee-claim wrapper\r\n // upgrade (tag 90 WithdrawCreatorFee). Against the currently-deployed\r\n // wrapper this code is unreachable.\r\n 62: {\r\n name: \"CreatorFeeOverClaim\",\r\n hint: \"WithdrawCreatorFee (tag 90) requested more than the market has accrued: amount > creator_fee_claimable_atoms (WrapperConfigV16 bytes 568..576, u64 LE). The claim is exact-amount — it does NOT partial-fill, and nothing is debited on rejection. Read the current claimable balance and retry with amount <= it. Note the distinct codes on this handler: Custom(9) InvalidInstruction for amount == 0 (tag 90 does not use tag 84's '0 means withdraw everything' convention), and Custom(25) EngineCounterUnderflow only for the fail-closed internal checked_sub, which is unreachable behind this check and would indicate a broken invariant.\",\r\n },\r\n\r\n // ── LP-vault reachability guard, 2026-08-29 (63) ───────────────────────────\r\n // Source: v16_program.rs PercolatorError variant appended after\r\n // CreatorFeeOverClaim=62. Ordinals 0-62 are unmoved.\r\n // ✅ DEPLOYED to devnet 2026-08-29 — wrapper 02326f4f, sha c9827970bf02098b,\r\n // slot 490057417, verified byte-identical.\r\n 63: {\r\n name: \"LpVaultBackingBucketNotEmpty\",\r\n hint: \"CreateLpVault (tag 72) targeted a domain whose backing bucket is ALREADY funded at an expiry that is not LP_VAULT_BACKING_EXPIRY_SLOT (u64::MAX/2). The range check on `domain` passed; this is the separate REACHABILITY check, and it fires BEFORE the registry PDA takes backing_bucket_authority so a refusal leaves the existing bucket owner intact. Without it the vault would be created dead: DepositToLpVault refuses for the whole remaining term on the expiry mismatch, the provider who funded that bucket can no longer withdraw because the authority is gone, and the only exit is CloseLpVault — which permanently forfeits this market's ability to ever have an LP vault, because it leaves the LP share mint on-chain and CreateLpVault requires both PDAs to be system-owned and empty. Fix: pick a domain whose bucket is Empty, or wait for the existing backing to expire. Do NOT confuse this with Custom(9) InvalidInstruction, which this handler also returns for an out-of-range domain (domain >= configured_slots * 2) and for fee_share_bps / oi_reservation_threshold_bps > 10_000.\",\r\n },\r\n};\r\nfor (const v of Object.values(PERCOLATOR_ERRORS)) Object.freeze(v);\r\nObject.freeze(PERCOLATOR_ERRORS);\r\n\r\n/**\r\n * Decode a custom program error code to its info.\r\n *\r\n * @param code Custom error code from `custom program error: 0x`.\r\n * @returns ErrorInfo with name and hint, or undefined if the code is not recognized.\r\n */\r\nexport function decodeError(code: number): ErrorInfo | undefined {\r\n return PERCOLATOR_ERRORS[code];\r\n}\r\n\r\n/**\r\n * Get error name from code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Human-readable error name, or \"Unknown()\" if not recognized.\r\n */\r\nexport function getErrorName(code: number): string {\r\n return PERCOLATOR_ERRORS[code]?.name ?? `Unknown(${code})`;\r\n}\r\n\r\n/**\r\n * Get actionable hint for error code.\r\n *\r\n * @param code Custom error code.\r\n * @returns Actionable hint string, or undefined if not recognized.\r\n */\r\nexport function getErrorHint(code: number): string | undefined {\r\n return PERCOLATOR_ERRORS[code]?.hint;\r\n}\r\n\r\n/** Max hex digits for `custom program error: 0x...` — Solana custom errors are u32. */\r\nconst CUSTOM_ERROR_HEX_MAX_LEN = 8;\r\n\r\n/**\r\n * Parse a custom program error from transaction logs.\r\n *\r\n * Looks for \"Program ... failed: custom program error: 0x...\" in the log lines.\r\n * Returns null if no custom error is found.\r\n *\r\n * @param logs Array of transaction log strings from the RPC response.\r\n * @returns Parsed error with code, name, and hint — or null if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * const err = parseErrorFromLogs(txResult.meta?.logMessages ?? []);\r\n * if (err) console.error(`${err.name}: ${err.hint}`);\r\n * ```\r\n */\r\nexport function parseErrorFromLogs(logs: string[]): {\r\n code: number;\r\n name: string;\r\n hint?: string;\r\n} | null {\r\n if (!Array.isArray(logs)) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n `custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,\r\n \"i\",\r\n );\r\n for (const log of logs) {\r\n if (typeof log !== \"string\") {\r\n continue;\r\n }\r\n const match = log.match(re);\r\n if (match) {\r\n const code = parseInt(match[1], 16);\r\n if (!Number.isFinite(code) || code < 0 || code > 0xffff_ffff) {\r\n continue;\r\n }\r\n const info = decodeError(code);\r\n return {\r\n code,\r\n name: info?.name ?? `Unknown(${code})`,\r\n hint: info?.hint,\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n","/**\r\n * Standalone percolator-nft program SDK module.\r\n *\r\n * This covers the NFT program at `PERCOLATOR_NFT_PROGRAM_ID` which is\r\n * separate from the main Percolator program. It handles:\r\n * - MintPositionNft (tag 0)\r\n * - BurnPositionNft (tag 1)\r\n * - SettleFunding (tag 2)\r\n * - GetPositionValue (tag 3)\r\n * - ExecuteTransferHook (tag 4, SPL interface — not called directly)\r\n * - EmergencyBurn (tag 5)\r\n * - RepairExtraMetas (tag 6)\r\n * - ReconcileBurnedNft (tag 7)\r\n *\r\n * PDA seeds (matches percolator-nft/src/state_v16.rs):\r\n * PositionNft state : [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n * Mint authority : [\"mint_authority\"]\r\n *\r\n * NOTE: the PositionNft seed is keyed on `market_id`, NOT `asset_index` — see\r\n * #108 and `deriveNftPda` below. This header claimed `asset_index_u16_LE` until\r\n * 2026-08-31; the code was always correct.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport { PROGRAM_IDS_V17 } from \"../config/program-ids.js\";\r\nimport { safeEnv } from \"../config/program-ids.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Program ID\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Allowlist of known NFT program addresses. */\r\nconst KNOWN_NFT_PROGRAM_IDS = new Set([\r\n \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\", // mainnet\r\n PROGRAM_IDS_V17.nft, // v17 devnet — the default below\r\n]);\r\n\r\nconst NFT_PROGRAM_OVERRIDE = safeEnv(\"NFT_PROGRAM_ID\");\r\nif (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) {\r\n throw new Error(\r\n `[percolator-sdk] NFT_PROGRAM_ID env var \"${NFT_PROGRAM_OVERRIDE}\" is not a known NFT program address. ` +\r\n `Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(\", \")}. ` +\r\n `Pass the programId argument explicitly to bypass env resolution.`,\r\n );\r\n}\r\n\r\n/**\r\n * The standalone percolator-nft program (TransferHook + mint authority).\r\n *\r\n * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant\r\n * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET\r\n * address while every other id in the SDK is devnet, so any consumer importing it built\r\n * transactions against a program that does not exist on devnet and failed late with\r\n * \"Account not found on-chain\". The frontend hit exactly that and had to define its own\r\n * constant to work around it.\r\n */\r\nexport const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft);\r\n\r\nexport function getNftProgramId(): PublicKey {\r\n return NFT_PROGRAM_ID;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction tags (standalone NFT program — NOT the main Percolator tags)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const NFT_IX_TAG = {\r\n MintPositionNft: 0,\r\n BurnPositionNft: 1,\r\n SettleFunding: 2,\r\n GetPositionValue: 3,\r\n ExecuteTransferHook: 4,\r\n EmergencyBurn: 5,\r\n RepairExtraMetas: 6,\r\n ReconcileBurnedNft: 7,\r\n} as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Instruction encoders\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encode MintPositionNft (tag 0). Data: tag(1) + asset_index(u16). */\r\nexport function encodeNftMint(assetIndex: number): Uint8Array {\r\n const assetIndexBuf = u16Buf(assetIndex, \"assetIndex\");\r\n const buf = new Uint8Array(3);\r\n buf[0] = NFT_IX_TAG.MintPositionNft;\r\n buf.set(assetIndexBuf, 1);\r\n return buf;\r\n}\r\n\r\n/** Encode BurnPositionNft (tag 1). Data: tag(1). */\r\nexport function encodeNftBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.BurnPositionNft]);\r\n}\r\n\r\n/** Encode SettleFunding (tag 2). Data: tag(1). */\r\nexport function encodeNftSettleFunding(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.SettleFunding]);\r\n}\r\n\r\n/** Encode EmergencyBurn (tag 5). Data: tag(1). */\r\nexport function encodeNftEmergencyBurn(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.EmergencyBurn]);\r\n}\r\n\r\n/**\r\n * Encode ReconcileBurnedNft (tag 7, #138). Data: tag(1). Permissionless: releases\r\n * a position stranded by an out-of-band Token-2022 Burn (supply==0, escrow not\r\n * released) back to the recorded last holder, then closes the PositionNft PDA.\r\n */\r\nexport function encodeNftReconcile(): Uint8Array {\r\n return new Uint8Array([NFT_IX_TAG.ReconcileBurnedNft]);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account meta templates\r\n// ---------------------------------------------------------------------------\r\n\r\ntype AccountMeta = \"s\" | \"w\" | \"sw\" | \"r\";\r\n\r\n/**\r\n * BUG FOUND + FIXED (2026-07-16, uncommitted, branch feat/protocol-fee-v17):\r\n * the shorthand `AccountMeta` codes above (\"s\"|\"w\"|\"sw\"|\"r\") are a DIFFERENT,\r\n * incompatible type from `AccountSpec` (`{name, signer, writable}`) used by\r\n * `buildAccountMetas()` in `./accounts.js`. Passing `ACCOUNTS_NFT_MINT` /\r\n * `ACCOUNTS_NFT_BURN` / etc. into `buildAccountMetas()` silently produces\r\n * `isSigner: undefined` and `isWritable: undefined` for every account\r\n * (`spec.signer` / `spec.writable` read off a plain string) — Solana coerces\r\n * both to falsy, so EVERY account in the built instruction ends up\r\n * non-signer/read-only. The NFT program's own writable/signer checks then\r\n * reject the transaction (confirmed live against the deployed NFT program:\r\n * MintPositionNft fails with `InvalidAccountData` at ~2.4k CU, before any\r\n * CPI — matching its `if !nft_pda.is_writable { return\r\n * Err(InvalidAccountData) }`-style guards in percolator-nft/src/processor.rs).\r\n *\r\n * Use `buildNftAccountMetas()` below with these shorthand arrays instead of\r\n * `buildAccountMetas()` from `./accounts.js`. No consumer in this repo (or\r\n * percolator-launch, grepped) was actually calling `buildAccountMetas()` with\r\n * these arrays and working — the only prior working reference\r\n * (playground/flowtest/07-nft-mint.ts) builds the account list by hand,\r\n * bypassing the mismatch entirely.\r\n */\r\nexport function buildNftAccountMetas(\r\n spec: readonly AccountMeta[],\r\n keys: readonly PublicKey[],\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n if (keys.length !== spec.length) {\r\n throw new Error(\r\n `buildNftAccountMetas: account count mismatch: expected ${spec.length}, got ${keys.length}`,\r\n );\r\n }\r\n return spec.map((code, i) => ({\r\n pubkey: keys[i],\r\n isSigner: code === \"s\" || code === \"sw\",\r\n isWritable: code === \"w\" || code === \"sw\",\r\n }));\r\n}\r\n\r\n/**\r\n * Account metas for MintPositionNft (tag 0). 12 accounts.\r\n *\r\n * 0. [signer, writable] payer / position owner\r\n * 1. [writable] PositionNft PDA (created)\r\n * 2. [writable, signer] NFT mint (Token-2022, fresh keypair)\r\n * 3. [writable] Owner's NFT ATA (created)\r\n * 4. [writable] Portfolio account (#105: B-3 escrow CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [] Associated token account program\r\n * 8. [] System program\r\n * 9. [writable] ExtraAccountMetaList PDA\r\n * 10. [] Per-market NftRegistry PDA (#109 — was missing from this template)\r\n * 11. [] Percolator wrapper program (#105 — escrow CPI target)\r\n *\r\n * #105 escrow-at-mint: mint now CPIs the wrapper's B-3 TransferPortfolioOwnership\r\n * to escrow the position to the NFT program's mint-authority PDA, so #4 must be\r\n * writable and #10/#11 are required.\r\n */\r\nexport const ACCOUNTS_NFT_MINT: AccountMeta[] = [\r\n \"sw\", \"w\", \"sw\", \"w\", \"w\", \"r\", \"r\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for BurnPositionNft (tag 1). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient — receives the ATA, mint,\r\n * PositionNft PDA and ExtraAccountMetaList rent)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint (supply → 0)\r\n * 3. [writable] Holder's NFT ATA (closed)\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n *\r\n * #105 escrow-at-mint: burn now CPIs the wrapper's UnwrapEscrowedPortfolio to\r\n * release the escrow back to the holder, so #4 must be writable and #8/#9 are required.\r\n */\r\nexport const ACCOUNTS_NFT_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for EmergencyBurn (tag 5). 10 accounts.\r\n *\r\n * 0. [signer, writable] NFT holder (rent recipient)\r\n * 1. [writable] PositionNft PDA (closed)\r\n * 2. [writable] NFT mint\r\n * 3. [writable] Holder's NFT ATA\r\n * 4. [writable] Portfolio account (#105: UnwrapEscrowedPortfolio CPI mutates owner)\r\n * 5. [] Mint authority PDA\r\n * 6. [] Token-2022 program\r\n * 7. [writable] ExtraAccountMetaList PDA (closed on burn — rent refunded to holder; #102)\r\n * 8. [] Per-market NftRegistry PDA (#105 — unwrap CPI)\r\n * 9. [] Percolator wrapper program (#105 — unwrap CPI target)\r\n */\r\nexport const ACCOUNTS_NFT_EMERGENCY_BURN: AccountMeta[] = [\r\n \"sw\", \"w\", \"w\", \"w\", \"w\", \"r\", \"r\", \"w\", \"r\", \"r\",\r\n];\r\n\r\n/**\r\n * Account metas for ReconcileBurnedNft (tag 7, #138). 9 accounts. Permissionless.\r\n *\r\n * 0. [writable] PositionNft PDA (closed)\r\n * 1. [writable] NFT mint (Token-2022 — supply must be 0; closed, #182)\r\n * 2. [writable] Portfolio account (escrow released to the last holder)\r\n * 3. [] Mint authority PDA (unwrap + mint-close CPI signer)\r\n * 4. [] Per-market NftRegistry PDA\r\n * 5. [] Percolator wrapper program (unwrap CPI target)\r\n * 6. [writable] Recorded last-holder wallet (escrow + all rent recipient)\r\n * 7. [writable] ExtraAccountMetaList PDA (closed, #182)\r\n * 8. [] Token-2022 program (mint-close CPI target, #182)\r\n *\r\n * dcccrypto/percolator-nft#182: Reconcile previously abandoned the NFT mint and\r\n * the ExtraAccountMetaList PDA — 7,676,880 lamports per NFT, unrecoverable,\r\n * because it closes the PositionNft PDA and every path that could later reclaim\r\n * those two requires it to still be live. Accounts 7 and 8 are REQUIRED rather\r\n * than optional: Reconcile is permissionless, irreversible and runs at most\r\n * once, so an opt-in could be defeated permanently by whoever called first.\r\n *\r\n * Forward-compatible with the currently deployed programs: their handler pulls\r\n * seven accounts off an iterator and never checks `accounts.len()`, so the two\r\n * extra metas are simply unread, and it never checks `nft_mint.is_writable`.\r\n * A nine-account call therefore behaves identically on both, which is why this\r\n * can ship ahead of the program change rather than behind it.\r\n */\r\nexport const ACCOUNTS_NFT_RECONCILE: AccountMeta[] = [\r\n \"w\", \"w\", \"w\", \"r\", \"r\", \"r\", \"w\", \"w\", \"r\",\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// PDA derivation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\nfunction u16Buf(value: number, label: string): Uint8Array {\r\n if (!Number.isInteger(value) || value < 0 || value > 0xffff) {\r\n throw new Error(`${label} must be a u16`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, true);\r\n return buf;\r\n}\r\n\r\nfunction u64Buf(value: bigint | number, label: string): Uint8Array {\r\n const v = typeof value === \"bigint\" ? value : BigInt(value);\r\n if (v < 0n || v > 0xffff_ffff_ffff_ffffn) {\r\n throw new Error(`${label} must be a u64`);\r\n }\r\n const buf = new Uint8Array(8);\r\n new DataView(buf.buffer).setBigUint64(0, v, true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive the PositionNft state PDA.\r\n * Seeds: [\"position_nft\", portfolio_account, market_id_u64_LE]\r\n *\r\n * #108: the seed is keyed on the position-instance `marketId` (the engine's\r\n * monotonic, never-reused `legs[].market_id`), NOT `asset_index` — which the\r\n * engine reuses across close/re-open of the same asset and which therefore\r\n * aliased the PDA (a stale NFT could squat the slot and brick re-wrapping the\r\n * new position). Pass `marketId` = the active leg's `market_id` at mint, or the\r\n * NFT's stored `marketIdAtMint` for any later op.\r\n */\r\nexport function deriveNftPda(\r\n portfolioAccount: PublicKey,\r\n marketId: bigint | number,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"position_nft\"), portfolioAccount.toBytes(), u64Buf(marketId, \"marketId\")],\r\n programId,\r\n );\r\n}\r\n\r\n// The per-market NftRegistry PDA — required as an account for MintPositionNft\r\n// (#109) and for Burn/EmergencyBurn (#105 unwrap CPI) — is derived by\r\n// `deriveNftRegistry(wrapperProgramId, marketGroup)` in `../solana/pda`\r\n// (seeds [\"nft_registry\", marketGroup] under the WRAPPER program id).\r\n\r\n/**\r\n * @deprecated v16 Position NFT mints are fresh signer keypairs, not PDAs.\r\n */\r\nexport function deriveNftMint(\r\n _portfolioAccount: PublicKey,\r\n _assetIndex: number,\r\n _programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n throw new Error(\"deriveNftMint: v16 NFT mint is a fresh signer keypair, not a PDA\");\r\n}\r\n\r\n/**\r\n * Derive the program-wide mint authority PDA.\r\n * Seeds: [\"mint_authority\"]\r\n */\r\nexport function deriveMintAuthority(\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"mint_authority\")],\r\n programId,\r\n );\r\n}\r\n\r\n/**\r\n * Derive the Token-2022 ExtraAccountMetaList PDA for a Position NFT mint.\r\n * Seeds: [\"extra-account-metas\", nft_mint]. This is account #9 of MintPositionNft\r\n * and (since #102) account #7 of BurnPositionNft / EmergencyBurn — the burn paths\r\n * close it and refund its rent to the holder.\r\n */\r\nexport function deriveExtraAccountMetas(\r\n nftMint: PublicKey,\r\n programId: PublicKey = NFT_PROGRAM_ID,\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode(\"extra-account-metas\"), nftMint.toBytes()],\r\n programId,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Account parser\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * On-chain PositionNftV16 state (199 bytes, matches percolator-nft/src/state_v16.rs).\r\n *\r\n * [0..8] magic u64 (\"PERCNFT\\0\")\r\n * [8] version u8\r\n * [9] bump u8\r\n * [10..42] portfolio_account [u8; 32]\r\n * [42..74] nft_mint [u8; 32]\r\n * [74..78] asset_index u32 LE\r\n * [78] side_at_mint u8\r\n * [79..95] basis_pos_q_at_mint i128\r\n * [95..111] f_snap_at_mint i128\r\n * [111..119] market_id_at_mint u64\r\n * [119..127] epoch_snap_at_mint u64\r\n * [127..159] position_owner_at_mint [u8; 32]\r\n * [159..167] minted_at i64\r\n * [167..199] last_holder [u8; 32]\r\n *\r\n * NOTE: [167..199] is `last_holder`, not reserved space. #138 claimed those\r\n * bytes for the field the transfer hook rewrites on every transfer, and\r\n * `ReconcileBurnedNft` reads it to decide who receives the released escrow and\r\n * the rent — it is account 6 of that instruction and cannot be derived, only\r\n * read from here.\r\n */\r\nexport const POSITION_NFT_STATE_LEN = 199;\r\nconst POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n;\r\nconst POSITION_NFT_VERSION = 2;\r\n\r\nexport interface PositionNftState {\r\n version: number;\r\n bump: number;\r\n portfolioAccount: PublicKey;\r\n nftMint: PublicKey;\r\n assetIndex: number;\r\n sideAtMint: number;\r\n basisPosQAtMint: bigint;\r\n fSnapAtMint: bigint;\r\n marketIdAtMint: bigint;\r\n epochSnapAtMint: bigint;\r\n positionOwnerAtMint: PublicKey;\r\n /** Backward-compatible alias for positionOwnerAtMint. */\r\n positionOwner: PublicKey;\r\n mintedAt: bigint;\r\n /**\r\n * The wallet the transfer hook last recorded as holding this NFT (#138).\r\n *\r\n * This is the sole authorisation for `ReconcileBurnedNft`: the program\r\n * releases the escrowed portfolio and all rent to whichever account matches\r\n * it, and refuses any other. Supply it as account 6 of\r\n * `ACCOUNTS_NFT_RECONCILE` — there is no way to derive it.\r\n */\r\n lastHolder: PublicKey;\r\n}\r\n\r\n/**\r\n * Read a little-endian signed i128 from a DataView at `offset`.\r\n *\r\n * Both 64-bit halves are read as UNSIGNED to avoid the sign-extension that\r\n * `getBigInt64` applies to the low half. If bit 127 of the combined 128-bit\r\n * value is set the result is negative and two's-complement sign extension is\r\n * applied explicitly.\r\n *\r\n * Bug fixed (S-3): the prior code used `getBigInt64` for the low half, which\r\n * returns a *signed* BigInt. When bit 63 of the low half is set the value is\r\n * negative (e.g. -1 rather than 0xffffffffffffffff), so OR-ing it with the\r\n * shifted high half collapses the sign bit into all high bits and corrupts the\r\n * result.\r\n *\r\n * @param view DataView wrapping the raw account bytes\r\n * @param offset Byte offset of the i128 field (little-endian)\r\n * @returns Signed BigInt in the range [-2^127, 2^127)\r\n */\r\nfunction readI128FromView(view: DataView, offset: number): bigint {\r\n const lo = view.getBigUint64(offset, true);\r\n const hi = view.getBigUint64(offset + 8, true);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Parse a PositionNft account from raw bytes.\r\n * @throws if data is shorter than POSITION_NFT_STATE_LEN (199 bytes) or has an invalid magic/version.\r\n */\r\nexport function parsePositionNftAccount(data: Uint8Array): PositionNftState {\r\n if (data.length < POSITION_NFT_STATE_LEN) {\r\n throw new Error(\r\n `PositionNft account too small: ${data.length} < ${POSITION_NFT_STATE_LEN}`,\r\n );\r\n }\r\n\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n const magic = view.getBigUint64(0, true);\r\n if (magic !== POSITION_NFT_MAGIC) {\r\n throw new Error(\"PositionNft account has invalid magic\");\r\n }\r\n if (data[8] !== POSITION_NFT_VERSION) {\r\n throw new Error(`PositionNft account has invalid version: ${data[8]}`);\r\n }\r\n\r\n const positionOwnerAtMint = new PublicKey(data.subarray(127, 159));\r\n\r\n return {\r\n version: data[8],\r\n bump: data[9],\r\n portfolioAccount: new PublicKey(data.subarray(10, 42)),\r\n nftMint: new PublicKey(data.subarray(42, 74)),\r\n assetIndex: view.getUint32(74, true),\r\n sideAtMint: data[78],\r\n basisPosQAtMint: readI128FromView(view, 79),\r\n fSnapAtMint: readI128FromView(view, 95),\r\n marketIdAtMint: view.getBigUint64(111, true),\r\n epochSnapAtMint: view.getBigUint64(119, true),\r\n positionOwnerAtMint,\r\n positionOwner: positionOwnerAtMint,\r\n mintedAt: view.getBigInt64(159, true),\r\n lastHolder: new PublicKey(data.subarray(167, 199)),\r\n };\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\n/**\r\n * Read an environment variable safely. Returns `undefined` in browser\r\n * environments where `process` is not defined, avoiding a\r\n * `ReferenceError` crash at import time.\r\n */\r\nexport function safeEnv(key: string): string | undefined {\r\n try {\r\n return typeof process !== \"undefined\" && process?.env\r\n ? process.env[key]\r\n : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Centralized PROGRAM_ID configuration\r\n * \r\n * Default to environment variable, then fall back to network-specific defaults.\r\n * This prevents hard-coded program IDs scattered across the codebase.\r\n */\r\n\r\nexport const PROGRAM_IDS = {\r\n devnet: {\r\n // v17 deployed devnet programs — fresh triple, deployed + upgraded 2026-07-17,\r\n // hash-verified on-chain. Supersedes the 2026-06-26 wrapper (69VUZ7a2...), which\r\n // remains live on devnet with ~152 existing markets but is no longer the SDK default.\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n },\r\n mainnet: {\r\n percolator: \"ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv\",\r\n matcher: \"GDK8wx38kpiSVSfGTVNiSdptX3Z5R4kQyqh6Q3QX6wmi\",\r\n },\r\n} as const;\r\nObject.freeze(PROGRAM_IDS.devnet);\r\nObject.freeze(PROGRAM_IDS.mainnet);\r\nObject.freeze(PROGRAM_IDS);\r\n\r\n/**\r\n * v17 program IDs — fresh devnet triple, deployed + upgraded 2026-07-17,\r\n * hash-verified on-chain (wrapper + stake/vault + nft; matcher was already live\r\n * and upgraded in place at the same address).\r\n *\r\n * This supersedes the 2026-06-26 triple (wrapper 69VUZ7a2..., vault 51CeUNpb...,\r\n * nft 5TnritLt...). Those OLD addresses are STILL LIVE on devnet with ~152 existing\r\n * markets — they were not migrated in place, so anything still pointed at them\r\n * (e.g. the percolator-launch playground config, which hardcodes its own program\r\n * ID rather than reading this module) keeps working against the old markets until\r\n * it is explicitly cut over to this fresh triple. That playground cutover is a\r\n * separate, later step — NOT performed by this change.\r\n */\r\nexport const PROGRAM_IDS_V17 = {\r\n /** v17 wrapper — deployed devnet 2026-07-17, hash-verified. */\r\n percolator: \"DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\",\r\n /** v17 matcher — deployed devnet 2026-06-26, unchanged (same address). */\r\n matcher: \"4seJWjv3R5qfXY8R5ntuPHWsoqcVvaxvfFSnU2AnGMhT\",\r\n /** v17 nft — deployed devnet 2026-07-17, hash-verified. */\r\n nft: \"CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3\",\r\n /** v17 vault — deployed devnet 2026-07-17, hash-verified. */\r\n vault: \"GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3\",\r\n} as const;\r\nObject.freeze(PROGRAM_IDS_V17);\r\n\r\n/** The v17 wrapper PublicKey (devnet deployed + upgraded 2026-07-17, hash-verified). */\r\nexport const PROGRAM_ID_V17 = new PublicKey(PROGRAM_IDS_V17.percolator);\r\n\r\nexport type Network = \"devnet\" | \"mainnet\";\r\n\r\n/** Allowlist of legitimate percolator program addresses (all networks). */\r\nconst KNOWN_PROGRAM_IDS = new Set([\r\n PROGRAM_IDS.devnet.percolator,\r\n PROGRAM_IDS.mainnet.percolator,\r\n PROGRAM_IDS_V17.percolator,\r\n]);\r\n\r\n/** Allowlist of legitimate matcher program addresses (all networks). */\r\nconst KNOWN_MATCHER_IDS = new Set([\r\n PROGRAM_IDS.devnet.matcher,\r\n PROGRAM_IDS.mainnet.matcher,\r\n]);\r\n\r\n/**\r\n * #308 escape hatch: an env program-ID override that is NOT in the allowlist is rejected\r\n * UNLESS the operator explicitly opts in with `PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1`. This\r\n * blocks ambient env poisoning (a supply-chain attacker who sets PROGRAM_ID but not the opt-in\r\n * flag) while preserving the legitimate ability to point the SDK at a freshly-deployed program\r\n * during pre-deploy / devnet testing — which the allowlist alone would break.\r\n */\r\nfunction programOverrideOptIn(): boolean {\r\n return safeEnv(\"PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE\") === \"1\";\r\n}\r\n\r\n/**\r\n * Get the Percolator program ID for the current network\r\n * \r\n * Priority:\r\n * 1. PROGRAM_ID env var (explicit override)\r\n * 2. Network-specific default (NETWORK env var)\r\n * 3. Devnet default (safest fallback — bug bounty PERC-697)\r\n */\r\nexport function getProgramId(network?: Network): PublicKey {\r\n // #249: an explicit `network` argument is authoritative and must NOT be silently\r\n // overridden by the PROGRAM_ID env var. The env override applies ONLY when the caller\r\n // did not specify a network (ambient/default resolution) — so e.g. getProgramId(\"mainnet\")\r\n // always returns the canonical mainnet id regardless of a stale PROGRAM_ID env.\r\n if (network === undefined) {\r\n const override = safeEnv(\"PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_PROGRAM_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] PROGRAM_ID env var \"${override}\" is not a known program address. ` +\r\n `Allowed values: ${[...KNOWN_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].percolator;\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the Matcher program ID for the current network\r\n */\r\nexport function getMatcherProgramId(network?: Network): PublicKey {\r\n // #249: explicit `network` is authoritative — env override applies only when unspecified.\r\n if (network === undefined) {\r\n const override = safeEnv(\"MATCHER_PROGRAM_ID\");\r\n if (override) {\r\n if (!KNOWN_MATCHER_IDS.has(override) && !programOverrideOptIn()) {\r\n throw new Error(\r\n `[percolator-sdk] MATCHER_PROGRAM_ID env var \"${override}\" is not a known matcher program address. ` +\r\n `Allowed values: ${[...KNOWN_MATCHER_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override}`);\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n // Use provided network or detect from env — default to devnet (never mainnet silently)\r\n const detectedNetwork = getCurrentNetwork();\r\n const targetNetwork = network ?? detectedNetwork;\r\n const programId = PROGRAM_IDS[targetNetwork].matcher;\r\n\r\n if (!programId) {\r\n throw new Error(`Matcher program not deployed on ${targetNetwork}`);\r\n }\r\n\r\n return new PublicKey(programId);\r\n}\r\n\r\n/**\r\n * Get the current network from environment.\r\n *\r\n * SECURITY (PERC-697): Removed silent mainnet default.\r\n * Previously defaulted to \"mainnet\" when NETWORK was unset, which could cause\r\n * crank/keeper scripts run without env vars to silently target mainnet program IDs.\r\n *\r\n * Now defaults to \"devnet\" — the safer fallback for a devnet-first protocol.\r\n * Production deployments always set NETWORK explicitly via Railway/env.\r\n * For mainnet operations use networkValidation.ts (ensureNetworkConfigValid) which\r\n * enforces FORCE_MAINNET=1.\r\n */\r\nexport function getCurrentNetwork(): Network {\r\n const network = safeEnv(\"NETWORK\")?.toLowerCase();\r\n if (network === \"mainnet\" || network === \"mainnet-beta\") {\r\n return \"mainnet\";\r\n }\r\n // devnet, testnet, or unset → devnet (fail-open to devnet, not mainnet)\r\n return \"devnet\";\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\n\r\n// =============================================================================\r\n// Browser-compatible read helpers using DataView\r\n// (the npm 'buffer' polyfill lacks readBigUInt64LE / readBigInt64LE)\r\n// =============================================================================\r\n\r\n/** Wrap a Uint8Array in a DataView sharing the same underlying buffer. */\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\n/** Read a single unsigned byte at `off`. */\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n if (off >= data.length) {\r\n throw new RangeError(`readU8: offset ${off} out of bounds (length ${data.length})`);\r\n }\r\n return data[off];\r\n}\r\n/** Read a little-endian u16 at `off`. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\n/** Read a little-endian u32 at `off`. */\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint32(off, true);\r\n}\r\n/** Read a little-endian u64 at `off` as a BigInt. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\n/** Read a little-endian signed i64 at `off` as a BigInt. */\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\n\r\n// =============================================================================\r\n// Helper: read signed/unsigned i128 from buffer\r\n// =============================================================================\r\n\r\n/**\r\n * Read a little-endian signed i128 at `offset`.\r\n * Composed from two u64 halves; sign-extends if the high bit is set.\r\n */\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) {\r\n return unsigned - (1n << 128n);\r\n }\r\n return unsigned;\r\n}\r\n\r\n/** Read a little-endian unsigned u128 at `offset` as a BigInt. */\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// =============================================================================\r\n// Slab Layout Version Detection\r\n// =============================================================================\r\n// The deployed devnet program uses a different struct layout (V0) than the SDK\r\n// was updated for (V1). V1 includes PERC-120/121/122/298/299/300/301/306/328\r\n// struct changes that have NOT been deployed to devnet yet.\r\n//\r\n// V0 (deployed devnet): HEADER=72, CONFIG=408, ENGINE_OFF=480, ACCOUNT_SIZE=240\r\n// - InsuranceFund: {balance: U128, fee_revenue: U128} (32 bytes)\r\n// - RiskParams: 56 bytes (basic fields only)\r\n// - No mark_price, no long_oi/short_oi, no emergency OI cap fields\r\n// - No partial liquidation field in Account (240 bytes)\r\n//\r\n// V1 (future upgrade): HEADER=104, CONFIG=536, ENGINE_OFF=640, ACCOUNT_SIZE=248\r\n// - InsuranceFund: expanded with isolation fields (72 bytes)\r\n// - RiskParams: 288 bytes (premium funding, partial liq, dynamic fees)\r\n// - Has mark_price, long_oi/short_oi, emergency fields\r\n// - Account has last_partial_liquidation_slot (248 bytes)\r\n// =============================================================================\r\n\r\nconst MAGIC: bigint = 0x504552434f4c4154n; // \"PERCOLAT\"\r\n\r\n/** Slab magic number (\"PERCOLAT\" as little-endian u64). */\r\nexport const SLAB_MAGIC = MAGIC;\r\n\r\n// Flag bits in header._padding[0] at offset 13\r\nconst FLAG_RESOLVED = 1 << 0;\r\n\r\n/**\r\n * Full slab layout descriptor. Returned by detectSlabLayout().\r\n * All engine field offsets are relative to engineOff.\r\n */\r\nexport interface SlabLayout {\r\n version: 0 | 1 | 2;\r\n headerLen: number;\r\n configOffset: number;\r\n configLen: number;\r\n reservedOff: number; // offset of _reserved in header\r\n engineOff: number;\r\n accountSize: number;\r\n maxAccounts: number;\r\n bitmapWords: number;\r\n accountsOff: number; // absolute offset of accounts array in slab\r\n\r\n // Engine field offsets (relative to engineOff)\r\n engineInsuranceOff: number;\r\n engineParamsOff: number;\r\n paramsSize: number;\r\n engineCurrentSlotOff: number;\r\n engineFundingIndexOff: number;\r\n engineLastFundingSlotOff: number;\r\n engineFundingRateBpsOff: number;\r\n engineMarkPriceOff: number; // -1 if not present (V0)\r\n engineLastCrankSlotOff: number;\r\n engineMaxCrankStalenessOff: number;\r\n engineTotalOiOff: number;\r\n engineLongOiOff: number; // -1 if not present (V0)\r\n engineShortOiOff: number; // -1 if not present (V0)\r\n engineCTotOff: number;\r\n enginePnlPosTotOff: number;\r\n engineLiqCursorOff: number;\r\n engineGcCursorOff: number;\r\n engineLastSweepStartOff: number;\r\n engineLastSweepCompleteOff: number;\r\n engineCrankCursorOff: number;\r\n engineSweepStartIdxOff: number;\r\n engineLifetimeLiquidationsOff: number;\r\n engineLifetimeForceClosesOff: number;\r\n engineNetLpPosOff: number;\r\n engineLpSumAbsOff: number;\r\n engineLpMaxAbsOff: number;\r\n engineLpMaxAbsSweepOff: number;\r\n engineEmergencyOiModeOff: number; // -1 if not present (V0)\r\n engineEmergencyStartSlotOff: number; // -1 if not present (V0)\r\n engineLastBreakerSlotOff: number; // -1 if not present (V0)\r\n engineBitmapOff: number; // relative to engineOff\r\n postBitmap: number; // 2 = free_head only (V1D), 18 = num_used + pad + next_account_id + free_head\r\n acctOwnerOff: number; // byte offset of owner pubkey within an account slot\r\n\r\n // Insurance fund layout\r\n hasInsuranceIsolation: boolean;\r\n engineInsuranceIsolatedOff: number; // -1 if not present (V0)\r\n engineInsuranceIsolationBpsOff: number; // -1 if not present (V0)\r\n\r\n // Optional fallback for engines without a stored mark_price field (v12.17+):\r\n // absolute offset into the slab of `config.mark_ewma_e6` (u64 little-endian,\r\n // scaled 1e6). Consumers that previously read `engine.mark_price` should\r\n // check this when `engineMarkPriceOff < 0`. Undefined on layouts that\r\n // predate v12.17 and already expose a real engine.mark_price.\r\n configMarkEwmaOff?: number;\r\n}\r\n\r\n// ---- V0 layout constants (deployed devnet program) ----\r\nconst V0_HEADER_LEN = 72;\r\nconst V0_CONFIG_LEN = 408;\r\nconst V0_ENGINE_OFF = 480; // align_up(72 + 408, 8) = 480\r\nconst V0_ACCOUNT_SIZE = 240;\r\nconst V0_RESERVED_OFF = 48; // magic(8)+version(4)+bump(1)+pad(3)+admin(32) = 48\r\n\r\n// V0 engine: vault(16) + insurance{balance(16),fee_revenue(16)}=32 → params at 48\r\n// V0 RiskParams: 56 bytes → runtime state at 104\r\nconst V0_ENGINE_PARAMS_OFF = 48;\r\nconst V0_PARAMS_SIZE = 56;\r\nconst V0_ENGINE_CURRENT_SLOT_OFF = 104;\r\nconst V0_ENGINE_FUNDING_INDEX_OFF = 112;\r\nconst V0_ENGINE_LAST_FUNDING_SLOT_OFF = 128;\r\nconst V0_ENGINE_FUNDING_RATE_BPS_OFF = 136;\r\nconst V0_ENGINE_LAST_CRANK_SLOT_OFF = 144;\r\nconst V0_ENGINE_MAX_CRANK_STALENESS_OFF = 152;\r\nconst V0_ENGINE_TOTAL_OI_OFF = 160;\r\nconst V0_ENGINE_C_TOT_OFF = 176;\r\nconst V0_ENGINE_PNL_POS_TOT_OFF = 192;\r\nconst V0_ENGINE_LIQ_CURSOR_OFF = 208;\r\nconst V0_ENGINE_GC_CURSOR_OFF = 210;\r\nconst V0_ENGINE_LAST_SWEEP_START_OFF = 216;\r\nconst V0_ENGINE_LAST_SWEEP_COMPLETE_OFF = 224;\r\nconst V0_ENGINE_CRANK_CURSOR_OFF = 232;\r\nconst V0_ENGINE_SWEEP_START_IDX_OFF = 234;\r\nconst V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 240;\r\nconst V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 248;\r\nconst V0_ENGINE_NET_LP_POS_OFF = 256;\r\nconst V0_ENGINE_LP_SUM_ABS_OFF = 272;\r\nconst V0_ENGINE_LP_MAX_ABS_OFF = 288;\r\nconst V0_ENGINE_LP_MAX_ABS_SWEEP_OFF = 304;\r\nconst V0_ENGINE_BITMAP_OFF = 320;\r\n\r\n// ---- V1 layout constants (deployed devnet program, PERC-1094 corrected) ----\r\n// BPF (SBF) target: u128 alignment = 8, so CONFIG_LEN = 496 on-chain.\r\n// ENGINE_OFF = align_up(HEADER=104 + CONFIG=496, 8) = 600.\r\n// Previous value (640) was wrong — it assumed CONFIG_LEN=536 from the native build assertion.\r\nconst V1_HEADER_LEN = 104;\r\nconst V1_CONFIG_LEN = 496; // BPF (SBF) on-chain value; native test build would be 512\r\nconst V1_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600 (was 640 — corrected in PERC-1094)\r\n// Legacy: CONFIG_LEN=536 was used in pre-PERC-1094 SDK. Some orphaned slabs on devnet may use\r\n// ENGINE_OFF=640 (65352 bytes for small). We add them to V1_SIZES_LEGACY for read-only parsing.\r\nconst V1_ENGINE_OFF_LEGACY = 640;\r\nconst V1_ACCOUNT_SIZE = 248;\r\nconst V1_RESERVED_OFF = 80;\r\n\r\n// V1 engine: vault(16) + insurance expanded(56) → params at 72\r\n// V1 RiskParams: 288 bytes → runtime state at 360\r\nconst V1_ENGINE_PARAMS_OFF = 72;\r\nconst V1_PARAMS_SIZE = 288;\r\nconst V1_ENGINE_CURRENT_SLOT_OFF = 360;\r\nconst V1_ENGINE_FUNDING_INDEX_OFF = 368;\r\nconst V1_ENGINE_LAST_FUNDING_SLOT_OFF = 384;\r\nconst V1_ENGINE_FUNDING_RATE_BPS_OFF = 392;\r\nconst V1_ENGINE_MARK_PRICE_OFF = 400;\r\nconst V1_ENGINE_LAST_CRANK_SLOT_OFF = 424;\r\nconst V1_ENGINE_MAX_CRANK_STALENESS_OFF = 432;\r\nconst V1_ENGINE_TOTAL_OI_OFF = 440;\r\nconst V1_ENGINE_LONG_OI_OFF = 456;\r\nconst V1_ENGINE_SHORT_OI_OFF = 472;\r\nconst V1_ENGINE_C_TOT_OFF = 488;\r\nconst V1_ENGINE_PNL_POS_TOT_OFF = 504;\r\nconst V1_ENGINE_LIQ_CURSOR_OFF = 520;\r\nconst V1_ENGINE_GC_CURSOR_OFF = 522;\r\nconst V1_ENGINE_LAST_SWEEP_START_OFF = 528;\r\nconst V1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 536;\r\nconst V1_ENGINE_CRANK_CURSOR_OFF = 544;\r\nconst V1_ENGINE_SWEEP_START_IDX_OFF = 546;\r\nconst V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 552;\r\nconst V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 560;\r\nconst V1_ENGINE_NET_LP_POS_OFF = 568;\r\nconst V1_ENGINE_LP_SUM_ABS_OFF = 584;\r\nconst V1_ENGINE_LP_MAX_ABS_OFF = 600;\r\nconst V1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 616;\r\nconst V1_ENGINE_EMERGENCY_OI_MODE_OFF = 632;\r\nconst V1_ENGINE_EMERGENCY_START_SLOT_OFF = 640;\r\nconst V1_ENGINE_LAST_BREAKER_SLOT_OFF = 648;\r\nconst V1_ENGINE_BITMAP_OFF = 656;\r\n// On-chain V1_LEGACY slabs (65352 bytes) place the bitmap 16 bytes later than\r\n// computeSlabSize predicts (formula bitmapOff=656 gives size=65352 correctly, but\r\n// the deployed program stores the bitmap at rel=672 and the owner field at +200).\r\n// These corrected values must be used for actual byte-level parsing.\r\nconst V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL = 672; // relative to engineOff (abs = 640+672 = 1312)\r\nconst V1_LEGACY_ACCT_OWNER_OFF = 200; // vs the usual ACCT_OWNER_OFF=184\r\n\r\n// ---- V1D layout constants (actually deployed devnet V1 program, rev ac18a0e) ----\r\n// The deployed V1 program has a DIFFERENT struct layout than the V1 constants above.\r\n// Key differences:\r\n// - MarketConfig is smaller (BPF CONFIG_LEN=320 vs V1's 496) — older revision\r\n// - InsuranceFund is 80 bytes (V1 assumed 56), so params starts at engine+96 (not 72)\r\n// - Engine lacks lp_max_abs, lp_max_abs_sweep, emergency_oi, trade_twap fields\r\n// - Bitmap at engine+624 (not 656)\r\n// Confirmed by on-chain probing of slab 6ZytbpV4 (the only active V1 market).\r\nconst V1D_CONFIG_LEN = 320;\r\nconst V1D_ENGINE_OFF = 424; // align_up(104 + 320, 8) = 424\r\nconst V1D_ACCOUNT_SIZE = 248;\r\n\r\n// V1D engine field offsets (relative to engineOff):\r\n// vault(16) + InsuranceFund(80) → params at 96; RiskParams(288) → runtime at 384\r\nconst V1D_ENGINE_INSURANCE_OFF = 16;\r\nconst V1D_ENGINE_PARAMS_OFF = 96;\r\nconst V1D_PARAMS_SIZE = 288;\r\nconst V1D_ENGINE_CURRENT_SLOT_OFF = 384;\r\nconst V1D_ENGINE_FUNDING_INDEX_OFF = 392;\r\nconst V1D_ENGINE_LAST_FUNDING_SLOT_OFF = 408;\r\nconst V1D_ENGINE_FUNDING_RATE_BPS_OFF = 416;\r\nconst V1D_ENGINE_MARK_PRICE_OFF = 424;\r\n// funding_frozen(1+7pad) at 432, funding_frozen_rate(8) at 440\r\nconst V1D_ENGINE_LAST_CRANK_SLOT_OFF = 448;\r\nconst V1D_ENGINE_MAX_CRANK_STALENESS_OFF = 456;\r\nconst V1D_ENGINE_TOTAL_OI_OFF = 464;\r\nconst V1D_ENGINE_LONG_OI_OFF = 480;\r\nconst V1D_ENGINE_SHORT_OI_OFF = 496;\r\nconst V1D_ENGINE_C_TOT_OFF = 512;\r\nconst V1D_ENGINE_PNL_POS_TOT_OFF = 528;\r\nconst V1D_ENGINE_LIQ_CURSOR_OFF = 544;\r\nconst V1D_ENGINE_GC_CURSOR_OFF = 546;\r\nconst V1D_ENGINE_LAST_SWEEP_START_OFF = 552;\r\nconst V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF = 560;\r\nconst V1D_ENGINE_CRANK_CURSOR_OFF = 568;\r\nconst V1D_ENGINE_SWEEP_START_IDX_OFF = 570;\r\nconst V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 576;\r\nconst V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 584;\r\nconst V1D_ENGINE_NET_LP_POS_OFF = 592;\r\nconst V1D_ENGINE_LP_SUM_ABS_OFF = 608;\r\n// lp_max_abs, lp_max_abs_sweep, emergency_*, trade_twap_* do NOT exist in this version\r\nconst V1D_ENGINE_BITMAP_OFF = 624;\r\n\r\n// ---- V2 layout constants (BPF intermediate layout, ENGINE_OFF=600, BITMAP_OFF=432) ----\r\n// V2 shares ENGINE_OFF=600 with V1, but has a completely different engine struct layout:\r\n// - CONFIG_LEN=496 (same as V1 on-chain), HEADER_LEN=104, ACCOUNT_SIZE=248\r\n// - Engine lacks mark_price, long_oi, short_oi, emergency OI fields\r\n// - Different field offsets than V1D (which has ENGINE_OFF=424)\r\n// V2 is identified by reading the version field at slab header offset 8 (u32 LE) == 2.\r\n// Without data, V2 cannot be distinguished from V1D by size alone (postBitmap=18 produces\r\n// identical sizes to V1D postBitmap=2 — both 65088 for 256 accounts).\r\nconst V2_HEADER_LEN = 104;\r\nconst V2_CONFIG_LEN = 496;\r\nconst V2_ENGINE_OFF = 600; // align_up(104 + 496, 8) = 600\r\nconst V2_ACCOUNT_SIZE = 248;\r\nconst V2_ENGINE_BITMAP_OFF = 432;\r\n\r\n// V2 engine field offsets (relative to engineOff)\r\nconst V2_ENGINE_CURRENT_SLOT_OFF = 352;\r\nconst V2_ENGINE_FUNDING_INDEX_OFF = 360;\r\nconst V2_ENGINE_LAST_FUNDING_SLOT_OFF = 376;\r\nconst V2_ENGINE_FUNDING_RATE_BPS_OFF = 384;\r\nconst V2_ENGINE_LAST_CRANK_SLOT_OFF = 392;\r\nconst V2_ENGINE_MAX_CRANK_STALENESS_OFF = 400;\r\nconst V2_ENGINE_TOTAL_OI_OFF = 408;\r\nconst V2_ENGINE_C_TOT_OFF = 424;\r\nconst V2_ENGINE_PNL_POS_TOT_OFF = 440;\r\nconst V2_ENGINE_LIQ_CURSOR_OFF = 456;\r\nconst V2_ENGINE_GC_CURSOR_OFF = 458;\r\nconst V2_ENGINE_LAST_SWEEP_START_OFF = 464;\r\nconst V2_ENGINE_LAST_SWEEP_COMPLETE_OFF = 472;\r\nconst V2_ENGINE_CRANK_CURSOR_OFF = 480;\r\nconst V2_ENGINE_SWEEP_START_IDX_OFF = 482;\r\nconst V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 488;\r\nconst V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 496;\r\nconst V2_ENGINE_NET_LP_POS_OFF = 504;\r\nconst V2_ENGINE_LP_SUM_ABS_OFF = 520;\r\nconst V2_ENGINE_LP_MAX_ABS_OFF = 536;\r\nconst V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;\r\n\r\n// ---- V_ADL layout constants (ADL-upgraded program, PERC-8270/8271) ----\r\n// This layout corresponds to the percolator lib at commit ed01137 (PERC-8270) which adds:\r\n// - Account: position_basis_q(i128,16)+adl_a_basis(u128,16)+adl_k_snap(i128,16)+adl_epoch_snap(u64,8) = +56 bytes\r\n// Plus 8-byte padding before position_basis_q (i128 requires 16-byte align on BPF) → +64 bytes/account\r\n// - RiskEngine: last_market_slot(u64)+funding_price_sample_last(u64)+materialized_account_count(u64)+last_oracle_price(u64) = +32 bytes\r\n// - Also adds: InsuranceFund expanded to 80 bytes (balance_incentive_reserve + _rebate_pad + _isolation_padding),\r\n// RiskParams expanded to 336 bytes (min_nonzero_mm_req, min_nonzero_im_req, insurance_floor, etc.),\r\n// pnl_matured_pos_tot(u128,16) field in RiskEngine (PERC-8267),\r\n// ADL side state fields (PERC-8268, +224 bytes engine before bitmap)\r\n//\r\n// BPF SLAB_LEN: 1288304 (large/4096-account tier) — verified by cargo build-sbf (PERC-8271)\r\n// ENGINE_OFF = 624 (HEADER=104 + CONFIG=520 native, aligned to 8 = 624)\r\n// ACCOUNT_SIZE = 312 (248 old + 8 pad for i128 alignment + 16+16+16+8 new ADL fields)\r\n// ENGINE_BITMAP_OFF = 1008 (empirically verified: mainnet CCTegYZ... slab, 323312 bytes, 1024 accts)\r\n// Prior value of 1006 was an arithmetic transcription error.\r\n// Derivation: trade_twap_e6(8)@992 + twap_last_slot(8)@1000 = bitmap@1008.\r\nconst V_ADL_ENGINE_OFF = 624; // align_up(HEADER=104 + CONFIG=520, 8) = 624\r\nconst V_ADL_CONFIG_LEN = 520; // BPF/native MarketConfig with current fields (pre-SetDexPool)\r\n\r\n// V_SETDEXPOOL: PERC-SetDexPool security fix — adds dex_pool: [u8; 32] to MarketConfig.\r\n// BPF CONFIG_LEN: 496→528 (+32). ENGINE_OFF: align_up(104+528,8) = 632 (+8 from V_ADL=624).\r\n// Engine struct and account layout are identical to V_ADL — only CONFIG_LEN/ENGINE_OFF changed.\r\nconst V_SETDEXPOOL_CONFIG_LEN = 544; // SBF on-chain CONFIG_LEN after PERC-SetDexPool (target_arch=sbf uses native alignment)\r\nconst V_SETDEXPOOL_ENGINE_OFF = 648; // align_up(HEADER=104 + CONFIG=544, 8) = 648\r\n// All engine field offsets are identical to V_ADL (same engine struct, only engineOff differs).\r\nconst V_ADL_ACCOUNT_SIZE = 312; // 248 + 8(pad) + 56(new ADL fields) = 312 bytes\r\nconst V_ADL_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96\r\n\r\n// V_ADL RiskParams: 336 bytes (same as V1M, includes all dynamic fee params)\r\nconst V_ADL_PARAMS_SIZE = 336;\r\n\r\n// V_ADL engine field offsets (relative to engineOff=624):\r\n// vault(16) + InsuranceFund(80) + RiskParams(336) = 432 bytes before current_slot\r\nconst V_ADL_ENGINE_CURRENT_SLOT_OFF = 432; // 96 + 336 = 432\r\nconst V_ADL_ENGINE_FUNDING_INDEX_OFF = 440; // 432 + 8\r\nconst V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF = 456; // 440 + 16\r\nconst V_ADL_ENGINE_FUNDING_RATE_BPS_OFF = 464; // 456 + 8\r\n// PERC-8270 new fields at 472-504:\r\n// last_market_slot(8)@472, funding_price_sample_last(8)@480, materialized_account_count(8)@488, last_oracle_price(8)@496\r\nconst V_ADL_ENGINE_MARK_PRICE_OFF = 504; // 464+8+32 = 504 (shifted +104 from V1's 400)\r\n// funding_frozen(1+7pad=8)@512, funding_frozen_rate_snapshot(i64,8)@520\r\nconst V_ADL_ENGINE_LAST_CRANK_SLOT_OFF = 528; // was 424 in V1, +104\r\nconst V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF = 536;\r\nconst V_ADL_ENGINE_TOTAL_OI_OFF = 544; // was 440 in V1, +104\r\nconst V_ADL_ENGINE_LONG_OI_OFF = 560; // was 456 in V1, +104\r\nconst V_ADL_ENGINE_SHORT_OI_OFF = 576; // was 472 in V1, +104\r\nconst V_ADL_ENGINE_C_TOT_OFF = 592; // was 488 in V1, +104\r\nconst V_ADL_ENGINE_PNL_POS_TOT_OFF = 608; // was 504 in V1, +104\r\n// pnl_matured_pos_tot(u128,16)@624 — NEW in PERC-8267\r\nconst V_ADL_ENGINE_LIQ_CURSOR_OFF = 640; // was 520 in V1, +120 (extra 16 for pnl_matured)\r\nconst V_ADL_ENGINE_GC_CURSOR_OFF = 642;\r\n// last_sweep_start(u64)@648, last_sweep_complete(u64)@656, crank_cursor(u16)@664, sweep_idx(u16)@666\r\nconst V_ADL_ENGINE_LAST_SWEEP_START_OFF = 648;\r\nconst V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF = 656;\r\nconst V_ADL_ENGINE_CRANK_CURSOR_OFF = 664;\r\nconst V_ADL_ENGINE_SWEEP_START_IDX_OFF = 666;\r\n// lifetime_liquidations(u64)@672, lifetime_force_closes(u64)@680\r\nconst V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 672;\r\nconst V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 680;\r\n// ADL side state (PERC-8268, 224 bytes):\r\n// adl_mult_long/short(16ea), adl_coeff_long/short(16ea), adl_epoch_long/short(8ea),\r\n// adl_epoch_start_k_long/short(16ea), oi_eff_long/short_q(16ea),\r\n// side_mode_long(u8)+side_mode_short(u8)+pad(6), stored_pos_count×2, stale_count×2(all u64,8),\r\n// phantom_dust_bound_long/short_q(16ea) = 224 bytes at offsets 688–911\r\n// Then LP aggregates:\r\nconst V_ADL_ENGINE_NET_LP_POS_OFF = 904; // after ADL side state\r\nconst V_ADL_ENGINE_LP_SUM_ABS_OFF = 920;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_OFF = 936;\r\nconst V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;\r\n// emergency fields:\r\nconst V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\n// trade_twap_e6(8)@992, twap_last_slot(8)@1000, bitmap([u64;N])@1008\r\n// Corrected from 1006 → 1008: 992+8(trade_twap_e6)+8(twap_last_slot)=1008. Arithmetic\r\n// transcription error in prior constant — 1008+512+18+8192=9730 rounds to 9736 (8-byte align),\r\n// but empirically mainnet CCTegYZ... slab (323312 bytes, 1024 accts) confirms bitmapOff=1008.\r\nconst V_ADL_ENGINE_BITMAP_OFF = 1008; // Empirically verified: mainnet slab CCTegYZ...\r\n\r\n// V_ADL account field offsets (relative to account slot start):\r\n// account_id(8)+capital(U128,16)+kind(u8+pad7=8)+pnl(I128,16)+reserved_pnl(u128,16)=64\r\nconst V_ADL_ACCT_WARMUP_STARTED_OFF = 64; // was 56\r\nconst V_ADL_ACCT_WARMUP_SLOPE_OFF = 72; // was 64\r\nconst V_ADL_ACCT_POSITION_SIZE_OFF = 88; // was 80\r\nconst V_ADL_ACCT_ENTRY_PRICE_OFF = 104; // was 96\r\nconst V_ADL_ACCT_FUNDING_INDEX_OFF = 112; // was 104\r\nconst V_ADL_ACCT_MATCHER_PROGRAM_OFF = 128; // was 120\r\nconst V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160; // was 152\r\nconst V_ADL_ACCT_OWNER_OFF = 192; // was 184 (shifted +8 from reserved_pnl u64→u128)\r\nconst V_ADL_ACCT_FEE_CREDITS_OFF = 224; // was 216\r\nconst V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240; // was 232\r\n\r\n// ---- V12_1 layout constants (percolator-core v12.1 merge) ----\r\n// Account struct grew: 312→320 bytes on SBF (new fields: position_basis_q, adl_a_basis,\r\n// adl_k_snap, adl_epoch_snap, fees_earned_total; fee_credits/last_fee_slot reordered).\r\n// RiskParams grew: 336→352 bytes on SBF (new fields: min_initial_deposit, insurance_floor,\r\n// risk_reduction_threshold, liquidation_buffer_bps, funding premium params, partial liq,\r\n// dynamic fee tiers, fee splits).\r\n// Engine field ordering completely reorganized from V_ADL.\r\n// All values verified by cargo build-sbf compile-time assertions.\r\n// V12_1 layout constants — verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n// IMPORTANT: The deployed `percolator` library is DIFFERENT from `percolator-core`.\r\n// The deployed struct has a simpler InsuranceFund (16 bytes), simpler RiskParams (184 bytes),\r\n// and NO fields for: total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs,\r\n// mark_price_e6, funding_index, last_funding_slot, emergency_*, lifetime_force_closes.\r\n// Those fields exist in percolator-core but NOT in the deployed binary.\r\n//\r\n// HOST constants below are for aarch64 test builds (percolator-core).\r\n// SBF constants are for the actual deployed program.\r\nconst V12_1_ENGINE_OFF = 648; // HOST: align_up(72 + 576, 16) = 648\r\nconst V12_1_ACCOUNT_SIZE = 320; // HOST aarch64 size\r\nconst V12_1_ACCOUNT_SIZE_SBF = 280; // SBF: verified by cargo build-sbf\r\nconst V12_1_ENGINE_BITMAP_OFF = 1016; // HOST bitmap offset (used field in percolator-core RiskEngine)\r\n// SBF layout: InsuranceFund = {balance: U128} = 16 bytes. RiskParams = 184 bytes.\r\n// vault(16) + InsuranceFund(16) = 32 → params at engine+32.\r\nconst V12_1_ENGINE_PARAMS_OFF_SBF = 32; // offset_of!(RiskEngine, params) on SBF\r\nconst V12_1_ENGINE_PARAMS_OFF_HOST = 96; // HOST value (percolator-core with 80-byte InsuranceFund)\r\nconst V12_1_ENGINE_PARAMS_OFF = 96;\r\nconst V12_1_PARAMS_SIZE_SBF = 184; // SBF: size_of::() = 184\r\nconst V12_1_PARAMS_SIZE = 352; // HOST: percolator-core RiskParams\r\n// SBF engine field offsets (relative to engineOff=616), verified by compiler:\r\nconst V12_1_SBF_OFF_CURRENT_SLOT = 216;\r\nconst V12_1_SBF_OFF_FUNDING_RATE = 224;\r\nconst V12_1_SBF_OFF_LAST_CRANK_SLOT = 232;\r\nconst V12_1_SBF_OFF_MAX_CRANK_STALENESS = 240;\r\nconst V12_1_SBF_OFF_C_TOT = 248;\r\nconst V12_1_SBF_OFF_PNL_POS_TOT = 264;\r\nconst V12_1_SBF_OFF_LIQ_CURSOR = 296;\r\nconst V12_1_SBF_OFF_GC_CURSOR = 298;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_START = 304;\r\nconst V12_1_SBF_OFF_LAST_SWEEP_COMPLETE = 312;\r\nconst V12_1_SBF_OFF_CRANK_CURSOR = 320;\r\nconst V12_1_SBF_OFF_SWEEP_START_IDX = 322;\r\nconst V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS = 328;\r\n// Probed from mainnet slab FLF9ghf6H4sfSexcQzDwse4gcGZKPb6qYCqo5Btat98 (290120 bytes).\r\n// These fields DO exist in the deployed SBF binary despite earlier \"not in deployed struct\" notes.\r\nconst V12_1_SBF_OFF_TOTAL_OI = 448; // u128: totalOpenInterest (verified: 907109 matches sum of abs positions)\r\nconst V12_1_SBF_OFF_LONG_OI = 464; // u128: longOi (verified: 907109 = all positions are long)\r\nconst V12_1_SBF_OFF_SHORT_OI = 480; // u128: shortOi (verified: 0)\r\nconst V12_1_SBF_OFF_MARK_PRICE_E6 = 560; // u64: markPriceE6 (verified: 85187279 = $85.19)\r\nconst V12_1_SBF_OFF_MARK_PRICE_SLOT = 568; // u64: slot when mark price was last updated\r\nconst V12_1_SBF_OFF_EFFECTIVE_PRICE_E6 = 576; // u64: lastEffectivePriceE6 (verified: matches mark)\r\n// ADL state: 336–576 (adl_mult, adl_coeff, adl_epoch, oi_eff, side_mode, etc.)\r\n// last_oracle_price: 560, last_market_slot: 568, funding_price_sample: 576\r\n// Bitmap (used field): 584\r\n// Fields NOT present in deployed program (return -1):\r\n// total_oi, long_oi, short_oi, net_lp_pos, lp_sum_abs, lp_max_abs, lp_max_abs_sweep,\r\n// mark_price, funding_index, last_funding_slot, emergency_*, lifetime_force_closes\r\n//\r\n// HOST engine field offsets (percolator-core, for test builds):\r\nconst V12_1_ENGINE_CURRENT_SLOT_OFF = 448;\r\nconst V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;\r\nconst V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;\r\nconst V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;\r\nconst V12_1_ENGINE_C_TOT_OFF = 480;\r\nconst V12_1_ENGINE_PNL_POS_TOT_OFF = 496;\r\nconst V12_1_ENGINE_LIQ_CURSOR_OFF = 528;\r\nconst V12_1_ENGINE_GC_CURSOR_OFF = 530;\r\nconst V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;\r\nconst V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;\r\nconst V12_1_ENGINE_CRANK_CURSOR_OFF = 552;\r\nconst V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;\r\nconst V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;\r\n// HOST-only fields (percolator-core has these, deployed percolator does not):\r\nconst V12_1_ENGINE_TOTAL_OI_OFF = 816;\r\nconst V12_1_ENGINE_LONG_OI_OFF = 832;\r\nconst V12_1_ENGINE_SHORT_OI_OFF = 848;\r\nconst V12_1_ENGINE_NET_LP_POS_OFF = 864;\r\nconst V12_1_ENGINE_LP_SUM_ABS_OFF = 880;\r\nconst V12_1_ENGINE_LP_MAX_ABS_OFF = 896;\r\nconst V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;\r\nconst V12_1_ENGINE_MARK_PRICE_OFF = 928;\r\nconst V12_1_ENGINE_FUNDING_INDEX_OFF = 936;\r\nconst V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;\r\nconst V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;\r\nconst V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;\r\nconst V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;\r\nconst V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;\r\n// V12_1 account field offsets (relative to account slot start):\r\n// New fields position_basis_q(i128@88), adl_a_basis(u128@104), adl_k_snap(i128@120),\r\n// adl_epoch_snap(u64@136) inserted before matcher_*, shifting everything from offset 128+ by +16.\r\nconst V12_1_ACCT_MATCHER_PROGRAM_OFF = 144; // was 128 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_MATCHER_CONTEXT_OFF = 176; // was 160 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_OWNER_OFF = 208; // was 192 in V_ADL (+16 from new ADL fields)\r\nconst V12_1_ACCT_FEE_CREDITS_OFF = 240; // was 224 in V_ADL\r\nconst V12_1_ACCT_LAST_FEE_SLOT_OFF = 256; // was 240 in V_ADL\r\nconst V12_1_ACCT_POSITION_SIZE_OFF = 88; // position_basis_q: i128 at offset 88 (SBF)\r\nconst V12_1_ACCT_ENTRY_PRICE_OFF = -1; // -1 for old V12_1 slabs (280-byte accounts)\r\nconst V12_1_ACCT_FUNDING_INDEX_OFF = -1; // does not exist in SBF layout\r\n\r\n// ---- V12_1_EP: V12_1 with entry_price re-added (accountSize=288 on SBF, 304 on host) ----\r\n// entry_price(u64) inserted after adl_epoch_snap, shifting matcher/owner/fees +8.\r\n// SBF layout (u128 align=8):\r\n// ...adl_epoch_snap(u64@136) → entry_price(u64@144) → matcher_program(@152)\r\n// → matcher_context(@184) → owner(@216) → fee_credits(@248) → last_fee_slot(@264)\r\n// → fees_earned_total(@272) = 288 bytes\r\nconst V12_1_EP_SBF_ACCOUNT_SIZE = 288;\r\nconst V12_1_EP_ACCT_ENTRY_PRICE_OFF = 144;\r\nconst V12_1_EP_ACCT_MATCHER_PROGRAM_OFF = 152;\r\nconst V12_1_EP_ACCT_MATCHER_CONTEXT_OFF = 184;\r\nconst V12_1_EP_ACCT_OWNER_OFF = 216;\r\nconst V12_1_EP_ACCT_FEE_CREDITS_OFF = 248;\r\nconst V12_1_EP_ACCT_LAST_FEE_SLOT_OFF = 264;\r\n\r\n// ---- V12_15 layout constants (percolator engine+prog v12.15 sync) ----\r\n// Account struct completely redesigned: sizeof=4400 bytes (SBF and host identical — all fields\r\n// explicitly sized, no pointer-derived alignment differences).\r\n// Fields REMOVED: warmupStartedAtSlot, warmupSlopePerStep, lastFeeSlot.\r\n// Fields ADDED: entry_price(u64@120), exact_reserve_cohorts(62*64=3968 bytes@256),\r\n// exact_cohort_count(u8@4224), overflow_older(ReserveCohort=64 bytes@4240),\r\n// overflow_older_present(u8@4304), overflow_newest(ReserveCohort=64@4320),\r\n// overflow_newest_present(u8@4384).\r\n// RiskParams sizeof=192: warmup_period_slots split into h_min(u64@160) + h_max(u64@168).\r\n// Field max_accounts moved to offset 24, insurance_floor at 144.\r\n// RiskEngine: ENGINE_OFF=624 (HEADER=72 + CONFIG=552, SBF aligned).\r\n// funding_rate renamed funding_rate_e9, now i128 (16 bytes) at offset 240 (was i64 at 224).\r\n// market_mode(u8) added at offset 256. pnl_matured_pos_tot(u128) added at 384.\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// SBF SLAB_LEN for --features small (MAX_ACCOUNTS=256): 1,128,448 bytes (verified by native test).\r\n// All account offsets below match both SBF and native (no alignment divergence for this struct).\r\nconst V12_15_ENGINE_OFF = 624; // native: align_up(616, 16) = 624\r\nconst V12_15_ENGINE_OFF_SBF = 616; // SBF: align_up(616, 8) = 616 (i128 align=8)\r\nconst V12_15_ACCOUNT_SIZE = 4400; // sizeof(Account) with 62 cohorts (default)\r\nconst V12_15_ACCOUNT_SIZE_SMALL = 920; // SBF sizeof(Account) with 8 cohorts (--features small, u128 align=8)\r\nconst V12_15_DEFAULT_MAX_ACCOUNTS = 2048; // was 4096, changed in v12.15\r\n\r\n// V12_15 account field offsets (relative to account slot start):\r\nconst V12_15_ACCT_ACCOUNT_ID_OFF = 0; // u64\r\nconst V12_15_ACCT_CAPITAL_OFF = 8; // u128\r\nconst V12_15_ACCT_KIND_OFF = 24; // u8 + 7 pad\r\nconst V12_15_ACCT_PNL_OFF = 32; // i128\r\nconst V12_15_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_15_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_15_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_15_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_15_ACCT_ADL_EPOCH_SNAP_OFF = 112; // u64\r\nconst V12_15_ACCT_ENTRY_PRICE_OFF = 120; // u64 (NEW — re-added in v12.15)\r\nconst V12_15_ACCT_MATCHER_PROGRAM_OFF = 128; // Pubkey\r\nconst V12_15_ACCT_MATCHER_CONTEXT_OFF = 160; // Pubkey\r\nconst V12_15_ACCT_OWNER_OFF = 192; // Pubkey\r\nconst V12_15_ACCT_FEE_CREDITS_OFF = 224; // i128 (16)\r\nconst V12_15_ACCT_FEES_EARNED_TOTAL_OFF = 240; // u128 (16)\r\n// exact_reserve_cohorts: [ReserveCohort; 62], each 64 bytes = 3968 bytes\r\nconst V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF = 256; // 62 * 64 = 3968 bytes\r\nconst V12_15_ACCT_EXACT_COHORT_COUNT_OFF = 4224; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_OFF = 4240; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF = 4304; // u8 (+ 15 pad = 16 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_OFF = 4320; // ReserveCohort (64 bytes)\r\nconst V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF = 4384; // u8 (+ 15 pad = 16 bytes)\r\n\r\n// V12_15 RiskParams offsets (relative to params base):\r\n// sizeof(RiskParams) = 192\r\nconst V12_15_PARAMS_SIZE = 192;\r\nconst V12_15_PARAMS_MAX_ACCOUNTS_OFF = 24; // u64 (moved from 32)\r\nconst V12_15_PARAMS_INSURANCE_FLOOR_OFF = 144; // u128\r\nconst V12_15_PARAMS_H_MIN_OFF = 160; // u64 (was warmup_period_slots)\r\nconst V12_15_PARAMS_H_MAX_OFF = 168; // u64 (NEW)\r\n\r\n// V12_15 RiskEngine offsets (relative to ENGINE_OFF):\r\n// vault(16) + InsuranceFund(16) + RiskParams(192) = 224 before current_slot\r\nconst V12_15_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16) = 32\r\nconst V12_15_ENGINE_CURRENT_SLOT_OFF = 224; // u64\r\n// 8-byte gap at 232 (padding or auxiliary field before i128-aligned funding_rate_e9)\r\nconst V12_15_ENGINE_FUNDING_RATE_E9_OFF = 240; // i128 (NEW — was i64 funding_rate at 224)\r\nconst V12_15_ENGINE_MARKET_MODE_OFF = 256; // u8 (NEW — 0=Live, 1=Resolved)\r\n// c_tot at 344, pnl_pos_tot at 368, pnl_matured_pos_tot at 384 (NEW)\r\nconst V12_15_ENGINE_C_TOT_OFF = 344; // u128\r\nconst V12_15_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128 (NEW)\r\n// Bitmap offset derived from SLAB_LEN=1,128,448 for n=256 and accountsOff_rel=1424:\r\n// bitmapOff = 1424 - ceil(256/64)*8 - 18 - 256*2 = 1424 - 32 - 18 - 512 = 862\r\nconst V12_15_ENGINE_BITMAP_OFF = 862;\r\n\r\n// V12_15 size map for layout detection\r\nconst V12_15_SIZES = new Map();\r\n\r\n// ---- V12_17 layout constants (two-bucket warmup, per-side funding) ----\r\n// Account: 368 bytes (native, i128 align=16) / 352 bytes (SBF, i128 align=8).\r\n// 62-cohort reserve queue → two-bucket warmup (sched_* + pending_*).\r\n// Removed: account_id, entry_price, fees_earned_total, cohort arrays.\r\n// Added: f_snap(i128), sched_present/remaining_q/anchor_q/start_slot/horizon/release_q,\r\n// pending_present/remaining_q/horizon/created_slot.\r\n// RiskParams sizeof=192 (native) / 184 (SBF). Same fields as v12.15.\r\n// RiskEngine: vault(16) + InsuranceFund(16) + RiskParams = 224 (native) / 216 (SBF) before current_slot.\r\n// Removed: funding_rate_e9 (stored). Added: per-side f_long_num/f_short_num cumulative funding.\r\n// Added: market_mode, resolved_*, neg_pnl_account_count, fund_px_last.\r\n// MAX_ACCOUNTS default=4096 (was 2048 in v12.15).\r\n// RISK_BUF_OFF = ENGINE_OFF + ENGINE_LEN; RISK_BUF_LEN = 160.\r\n// On-chain (SBF) SLAB_LEN includes RISK_BUF; native test SLAB_LEN also includes it.\r\n\r\n// MarketConfig size — 512 bytes post Phase A/B/E (fork addition of 80 bytes:\r\n// max_pnl_cap, last_audit_pause_slot, oi_cap_multiplier_bps, dispute_window_slots,\r\n// dispute_bond_amount, lp_collateral_enabled, lp_collateral_ltv_bps,\r\n// _new_fields_pad, pending_admin[32]).\r\n// Verified against percolator-prog/src/percolator.rs::MarketConfig via\r\n// size_of::() = 512 (both native and SBF — u128 fields happen\r\n// to land on 16-aligned offsets, so the u128 align=8 vs 16 rule is a no-op).\r\n\r\n// Native (i128 align=16)\r\nconst V12_17_ENGINE_OFF = 592; // align_up(72 + 512, 16) = 592\r\nconst V12_17_ACCOUNT_SIZE = 368;\r\nconst V12_17_ENGINE_BITMAP_OFF = 752; // offset_of!(RiskEngine, used) on native — relative, unchanged\r\nconst V12_17_DEFAULT_MAX_ACCOUNTS = 4096;\r\nconst V12_17_RISK_BUF_LEN = 160;\r\n// Per-account generation table appended after RISK_BUF in percolator-prog.\r\n// See percolator-prog/src/percolator.rs:87 — GEN_TABLE_LEN = MAX_ACCOUNTS * 8.\r\nconst V12_17_GEN_TABLE_ENTRY = 8;\r\n\r\n// SBF (i128 align=8)\r\nconst V12_17_ENGINE_OFF_SBF = 584; // align_up(72 + 512, 8) = 584\r\nconst V12_17_ACCOUNT_SIZE_SBF = 352;\r\nconst V12_17_ENGINE_BITMAP_OFF_SBF = 712; // offset_of!(RiskEngine, used) on SBF — relative, unchanged\r\n\r\n// V12_17 account field offsets (native — SBF offsets are 8 bytes less for fields after kind)\r\nconst V12_17_ACCT_CAPITAL_OFF = 0; // U128=[u64;2]\r\nconst V12_17_ACCT_KIND_OFF = 16; // u8\r\nconst V12_17_ACCT_PNL_OFF = 32; // i128 (native 16-align pad from 17→32)\r\nconst V12_17_ACCT_RESERVED_PNL_OFF = 48; // u128\r\nconst V12_17_ACCT_POSITION_BASIS_Q_OFF = 64; // i128\r\nconst V12_17_ACCT_ADL_A_BASIS_OFF = 80; // u128\r\nconst V12_17_ACCT_ADL_K_SNAP_OFF = 96; // i128\r\nconst V12_17_ACCT_F_SNAP_OFF = 112; // i128\r\nconst V12_17_ACCT_ADL_EPOCH_SNAP_OFF = 128; // u64\r\nconst V12_17_ACCT_MATCHER_PROGRAM_OFF = 136; // [u8;32]\r\nconst V12_17_ACCT_MATCHER_CONTEXT_OFF = 168; // [u8;32]\r\nconst V12_17_ACCT_OWNER_OFF = 200; // [u8;32]\r\nconst V12_17_ACCT_FEE_CREDITS_OFF = 232; // I128=[u64;2]\r\nconst V12_17_ACCT_SCHED_PRESENT_OFF = 248; // u8\r\nconst V12_17_ACCT_SCHED_REMAINING_Q_OFF = 256; // u128\r\nconst V12_17_ACCT_SCHED_ANCHOR_Q_OFF = 272; // u128\r\nconst V12_17_ACCT_SCHED_START_SLOT_OFF = 288; // u64\r\nconst V12_17_ACCT_SCHED_HORIZON_OFF = 296; // u64\r\nconst V12_17_ACCT_SCHED_RELEASE_Q_OFF = 304; // u128\r\nconst V12_17_ACCT_PENDING_PRESENT_OFF = 320; // u8\r\nconst V12_17_ACCT_PENDING_REMAINING_Q_OFF = 336; // u128\r\nconst V12_17_ACCT_PENDING_HORIZON_OFF = 352; // u64\r\nconst V12_17_ACCT_PENDING_CREATED_SLOT_OFF = 360; // u64\r\n\r\n// V12_17 RiskEngine field offsets (native, relative to engine start)\r\nconst V12_17_ENGINE_PARAMS_OFF = 32; // vault(16) + InsuranceFund(16)\r\nconst V12_17_ENGINE_CURRENT_SLOT_OFF = 224; // params starts at 32, size 192 → 224\r\nconst V12_17_ENGINE_MARKET_MODE_OFF = 232; // u8 (MarketMode enum)\r\nconst V12_17_ENGINE_RESOLVED_PRICE_OFF = 240; // u64\r\nconst V12_17_ENGINE_RESOLVED_K_LONG_OFF = 304; // i128\r\nconst V12_17_ENGINE_RESOLVED_K_SHORT_OFF = 320; // i128\r\nconst V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF = 336; // u64\r\nconst V12_17_ENGINE_LAST_CRANK_SLOT_OFF = 344; // u64 — verified via offset_of!(RiskEngine, last_crank_slot)\r\nconst V12_17_ENGINE_C_TOT_OFF = 352; // U128\r\nconst V12_17_ENGINE_PNL_POS_TOT_OFF = 368; // u128\r\nconst V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF = 384; // u128\r\nconst V12_17_ENGINE_GC_CURSOR_OFF = 400; // u16\r\nconst V12_17_ENGINE_OI_EFF_LONG_OFF = 528; // u128 — oi_eff_long_q\r\nconst V12_17_ENGINE_OI_EFF_SHORT_OFF = 544; // u128 — oi_eff_short_q\r\nconst V12_17_ENGINE_NEG_PNL_COUNT_OFF = 648; // u64\r\nconst V12_17_ENGINE_LAST_ORACLE_PRICE_OFF = 656; // u64\r\nconst V12_17_ENGINE_FUND_PX_LAST_OFF = 664; // u64\r\nconst V12_17_ENGINE_F_LONG_NUM_OFF = 688; // i128\r\nconst V12_17_ENGINE_F_SHORT_NUM_OFF = 704; // i128\r\n\r\n// SBF engine field offsets differ because RiskParams=184 (not 192) shifts everything after params.\r\n// Offset delta: native params=192, SBF params=184, so diff=8 starting from current_slot.\r\n// Additional differences accumulate from i128 alignment padding changes within the engine struct.\r\nconst V12_17_SBF_ENGINE_CURRENT_SLOT_OFF = 216;\r\nconst V12_17_SBF_ENGINE_MARKET_MODE_OFF = 224;\r\nconst V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF = 328; // u64 — native 344 − 16 (resolved u128 pad)\r\nconst V12_17_SBF_ENGINE_C_TOT_OFF = 336;\r\nconst V12_17_SBF_ENGINE_PNL_POS_TOT_OFF = 352;\r\nconst V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 368;\r\nconst V12_17_SBF_ENGINE_GC_CURSOR_OFF = 384; // u16 — native 400 − 16\r\nconst V12_17_SBF_ENGINE_OI_EFF_LONG_OFF = 504; // u128 — native 528 − 24 (adl u128 pad)\r\nconst V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF = 520; // u128 — native 544 − 24\r\nconst V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF = 616;\r\nconst V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_17_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_17_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_17_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_17 size map for layout detection\r\nconst V12_17_SIZES = new Map();\r\n\r\n// ---- V1M layout constants (mainnet-deployed V1 program, ESa89R5) ----\r\n// The mainnet program has a LARGER RiskParams (336 bytes vs V1's 288) and 22 extra\r\n// bytes in the runtime state (trade_twap_e6 + twap_last_slot + alignment padding).\r\n// ENGINE_OFF=640 (same as V1_LEGACY), CONFIG_LEN=536, ACCOUNT_SIZE=248.\r\n// Confirmed by byte-level probing of mainnet slab 8NY7rvQ (SOL/USDC Perpetual).\r\nconst V1M_ENGINE_OFF = 640; // align_up(104 + 536, 8) = 640 (same as V1_LEGACY)\r\nconst V1M_CONFIG_LEN = 536; // MarketConfig size in native/mainnet build\r\nconst V1M_ACCOUNT_SIZE = 248;\r\n// V1M2: rebuilt from main@4861c56, CONFIG_LEN=512 on SBF → ENGINE_OFF=616\r\nconst V1M2_ENGINE_OFF = 616; // align_up(104 + 512, 8) = 616\r\nconst V1M2_CONFIG_LEN = 512; // MarketConfig with u128 native alignment on SBF\r\nconst V1M_ENGINE_PARAMS_OFF = 72; // vault(16) + InsuranceFund(56) = 72 (same as V1)\r\nconst V1M2_ENGINE_PARAMS_OFF = 96; // vault(16) + InsuranceFund(80) = 96 (expanded in main@4861c56)\r\n\r\n// V1M RiskParams: 336 bytes (+48 over V1's 288)\r\n// Extra fields: fee_utilization_surge_bps(8) [in SDK V1 already? no → +8],\r\n// balance_incentive_reserve configs (+8?), min_nonzero_mm_req(u128=16),\r\n// min_nonzero_im_req(u128=16) = +48 total\r\nconst V1M_PARAMS_SIZE = 336;\r\n\r\n// V1M runtime state starts at engine+408 (72 + 336) instead of V1's +360\r\nconst V1M_ENGINE_CURRENT_SLOT_OFF = 408;\r\nconst V1M_ENGINE_FUNDING_INDEX_OFF = 416;\r\nconst V1M_ENGINE_LAST_FUNDING_SLOT_OFF = 432;\r\nconst V1M_ENGINE_FUNDING_RATE_BPS_OFF = 440;\r\nconst V1M_ENGINE_MARK_PRICE_OFF = 448;\r\n// funding_frozen(1+7pad) at 456, funding_frozen_rate(8) at 464\r\nconst V1M_ENGINE_LAST_CRANK_SLOT_OFF = 472;\r\nconst V1M_ENGINE_MAX_CRANK_STALENESS_OFF = 480;\r\nconst V1M_ENGINE_TOTAL_OI_OFF = 488;\r\nconst V1M_ENGINE_LONG_OI_OFF = 504;\r\nconst V1M_ENGINE_SHORT_OI_OFF = 520;\r\nconst V1M_ENGINE_C_TOT_OFF = 536;\r\nconst V1M_ENGINE_PNL_POS_TOT_OFF = 552;\r\nconst V1M_ENGINE_LIQ_CURSOR_OFF = 568;\r\nconst V1M_ENGINE_GC_CURSOR_OFF = 570;\r\nconst V1M_ENGINE_LAST_SWEEP_START_OFF = 576;\r\nconst V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF = 584;\r\nconst V1M_ENGINE_CRANK_CURSOR_OFF = 592;\r\nconst V1M_ENGINE_SWEEP_START_IDX_OFF = 594;\r\nconst V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 600;\r\nconst V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 608;\r\nconst V1M_ENGINE_NET_LP_POS_OFF = 616;\r\nconst V1M_ENGINE_LP_SUM_ABS_OFF = 632;\r\nconst V1M_ENGINE_LP_MAX_ABS_OFF = 648;\r\nconst V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF = 664;\r\nconst V1M_ENGINE_EMERGENCY_OI_MODE_OFF = 680;\r\nconst V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;\r\nconst V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;\r\n// trade_twap_e6(8) at 704, twap_last_slot(8) at 712 → bitmap at 720\r\n// No padding between twap_last_slot and used bitmap (u64 array is 8-byte\r\n// aligned and 720 % 8 == 0). Previous value of 726 was wrong — 726 % 8 = 6\r\n// which is invalid for a [u64; N] array under #[repr(C)].\r\nconst V1M_ENGINE_BITMAP_OFF = 720;\r\n\r\n// V1M2: mainnet program rebuilt from main@4861c56 with --features medium.\r\n// ENGINE_OFF=616 (not 640): CONFIG_LEN=512 on SBF because cfg(target_arch=\"bpf\")\r\n// doesn't match the SBF toolchain (target_arch=\"sbf\"), so u128 align=16 (native) applies.\r\n// align_up(HEADER=104 + CONFIG=512, 8) = 616.\r\n// Slab sizes match V_ADL exactly — disambiguation required via data inspection.\r\n// Confirmed by on-chain probing of slab 7T1Efij9 (SOL-PERP, 323312 bytes, medium tier).\r\n// Engine struct is larger than V1M (990 vs 720 bitmap offset = +270 runtime bytes).\r\n// New runtime fields inserted between fundingRateBps and markPrice:\r\n// +408: currentSlot, +416: fundingIndex(i128), +432: lastFundingSlot, +440: fundingRateBps\r\n// +448: NEW lastOracleUpdateSlot(?), +456: authorityPriceE6(?), +464-471: reserved\r\n// +472: lastEffectivePriceE6(?), +480: markPriceE6, +488-503: reserved\r\n// +504: lastCrankSlot, +512: maxCrankStaleness\r\nconst V1M2_ACCOUNT_SIZE = 312; // 248 + 64 bytes of new fields per account\r\n// V1M2 bitmap offset: empirically verified from mainnet slab CCTegYZ... (323312 bytes, 1024 accts).\r\n// The V1M2 engine struct is layout-identical to V_ADL — same relative field offsets from engineOff.\r\n// V_ADL_ENGINE_BITMAP_OFF (1008) is correct for V1M2 as well; prior value of 990 was wrong.\r\nconst V1M2_ENGINE_BITMAP_OFF = 1008; // Same as V_ADL_ENGINE_BITMAP_OFF — V1M2 uses V_ADL engine struct\r\n\r\n// For backward compatibility, export ENGINE_OFF and ENGINE_MARK_PRICE_OFF\r\n// (used by reinit-slab and other scripts). These refer to V1 layout.\r\nexport const ENGINE_OFF = V1_ENGINE_OFF;\r\nexport const ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;\r\n\r\n// ---- Known slab sizes per version and tier ----\r\n\r\n/**\r\n * Compute the total byte size of a slab given its layout parameters.\r\n * Used to pre-populate the known-size lookup maps at module load time.\r\n */\r\nfunction computeSlabSize(\r\n engineOff: number,\r\n bitmapOff: number,\r\n accountSize: number,\r\n maxAccounts: number,\r\n // postBitmap bytes immediately after the free-slot bitmap:\r\n // SDK default (V0/V1/V1-legacy): 18 = num_used(u16,2) + pad(6) + next_account_id(u64,8) + free_head(u16,2)\r\n // V1D deployed program: 2 = free_head(u16,2) only — no num_used, pad, or next_account_id\r\n postBitmap = 18,\r\n): number {\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return engineOff + accountsOff + maxAccounts * accountSize;\r\n}\r\n\r\nconst TIERS = [64, 256, 1024, 4096] as const;\r\n\r\n// Pre-compute known slab sizes for fast lookup\r\nconst V0_SIZES = new Map();\r\nconst V1_SIZES = new Map();\r\n// Legacy V1 sizes using incorrect ENGINE_OFF=640 (pre-PERC-1094). Orphaned on devnet; read-only.\r\nconst V1_SIZES_LEGACY = new Map();\r\n// V1D: actually deployed V1 program (ENGINE_OFF=424, BITMAP_OFF=624)\r\nconst V1D_SIZES = new Map();\r\n// V1D_SIZES_LEGACY: on-chain slabs created before GH#1234 when SDK assumed postBitmap=18.\r\n// These are 16 bytes larger per tier (micro=17080, small=65104, medium=257200, large=1025584).\r\n// The top active market (6ZytbpV4, $14k 24h vol) was created with postBitmap=18 and uses 65104.\r\n// PR #1236 fixed postBitmap for new slabs (→2) but broke recognition of these legacy 65104 slabs.\r\n// GH#1237: add both size variants so detectSlabLayout handles both old and new V1D on-chain data.\r\n// V2: ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18\r\nconst V2_SIZES = new Map();\r\n// V1M: mainnet-deployed V1 program (ENGINE_OFF=640, BITMAP_OFF=726, expanded RiskParams)\r\nconst V1M_SIZES = new Map();\r\n// V_ADL: PERC-8270/8271 ADL-upgraded program (ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\nconst V_ADL_SIZES = new Map();\r\n// V1M2: main@4861c56 with 312-byte accounts (ENGINE_OFF=616, BITMAP_OFF=1008, ACCOUNT_SIZE=312)\r\n// After fixing bitmapOff to 1008 for both V1M2 and V_ADL, sizes differ because engineOff differs:\r\n// V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n// V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n// No disambiguation probe required — size-based detection works correctly.\r\nconst V1M2_SIZES = new Map();\r\n// V_SETDEXPOOL: PERC-SetDexPool — ENGINE_OFF=648, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n// Same engine and account layout as V_ADL; only ENGINE_OFF changed (+8 from config growth).\r\n// e.g. large (4096 accts): computeSlabSize(632, 1008, 312, 4096, 18) = 1288336\r\nconst V_SETDEXPOOL_SIZES = new Map();\r\n// V12_1: percolator-core v12.1 merge — engineOff=648, bitmapOff=1016, accountSize=320.\r\n// Verified by cargo build-sbf compile-time assertions. Account grew 8 bytes, bitmap shifted 8.\r\n// e.g. large (4096 accts): computeSlabSize(648, 1016, 320, 4096, 18) = 1321112\r\nconst V12_1_SIZES = new Map();\r\nconst V1D_SIZES_LEGACY = new Map();\r\nfor (const n of TIERS) {\r\n V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);\r\n V1_SIZES.set(computeSlabSize(V1_ENGINE_OFF, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n V1_SIZES_LEGACY.set(computeSlabSize(V1_ENGINE_OFF_LEGACY, V1_ENGINE_BITMAP_OFF, V1_ACCOUNT_SIZE, n), n);\r\n // GH#1234: V1D deployed program omits num_used/pad/next_account_id → postBitmap=2 (free_head only).\r\n // This yields 65088 (n=256) and 1025568 (n=4096) matching actual devnet account sizes.\r\n V1D_SIZES.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 2), n);\r\n // GH#1237: also register the legacy postBitmap=18 sizes for slabs created before GH#1234 fix.\r\n V1D_SIZES_LEGACY.set(computeSlabSize(V1D_ENGINE_OFF, V1D_ENGINE_BITMAP_OFF, V1D_ACCOUNT_SIZE, n, 18), n);\r\n // V2: postBitmap=18 — produces same sizes as V1D postBitmap=2 (e.g. 65088 for n=256).\r\n // Disambiguation requires peeking at the version field in the slab header.\r\n V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);\r\n // V1M: mainnet program with expanded RiskParams (336 bytes) and trade_twap fields.\r\n // e.g. n=1024 → 257512 bytes (confirmed on-chain for slab 8NY7rvQ).\r\n V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);\r\n // V_ADL: PERC-8270 ADL-upgraded program — new account size (312) and expanded engine layout.\r\n // e.g. n=4096 → 1288320 bytes (engineOff=624, bitmapOff=1008).\r\n V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V1M2: main@4861c56 rebuild — engineOff=616, bitmapOff=1008, accountSize=312.\r\n // e.g. n=1024 → 323312 bytes (confirmed on-chain for slab CCTegYZ...).\r\n V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);\r\n // V_SETDEXPOOL: PERC-SetDexPool — engineOff=648, bitmapOff=1008, accountSize=312.\r\n // e.g. n=4096 → 1288336 bytes.\r\n V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);\r\n // V12_1: percolator-core v12.1 — accountSize=320 on aarch64, 280 on SBF.\r\n // The SBF binary has different struct alignment (u128 align=8 vs 16 on aarch64).\r\n // Register BOTH host-computed and SBF-empirical sizes for detection.\r\n V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);\r\n // V12_15: account_size=4400, ENGINE_OFF=624. MAX_ACCOUNTS default=2048, also support 256/1024/4096.\r\n V12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18), n);\r\n}\r\n// V12_15 additional tier: MAX_ACCOUNTS=2048 (new default, changed from 4096 in v12.15).\r\nV12_15_SIZES.set(computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, 2048, 18), 2048);\r\n// V12_15_SMALL: --features small (8 cohorts, 944-byte accounts). Hardcoded sizes verified via cargo test.\r\nV12_15_SIZES.set(237512, 256); // small (SBF): 256 accounts, 8 cohorts, SLAB_LEN=237512 (SBF u128 align=8)\r\n\r\n// V12_17 sizes — native and SBF, with and without RISK_BUF (160 bytes).\r\n// Native: Account align=16 → accountsOff alignment is 16, not 8.\r\n// SBF: Account align=8 → accountsOff alignment is 8.\r\n// Both on-chain and wrapper tests use SLAB_LEN which includes RISK_BUF.\r\n// postBitmap=4 (num_used_accounts: u16 + free_head: u16, no next_account_id or pad).\r\nconst V12_17_TIERS = [256, 1024, 4096] as const;\r\nfor (const n of V12_17_TIERS) {\r\n const bitmapWords = Math.ceil(n / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = n * 2;\r\n\r\n // Native (i128 align=16, Account align=16)\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16; // align to Account alignment (16)\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + n * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(nativeSize, n);\r\n\r\n // SBF (i128 align=8, Account align=8)\r\n const preAccSbf = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffSbf = Math.ceil(preAccSbf / 8) * 8;\r\n const sbfSize = V12_17_ENGINE_OFF_SBF + accountsOffSbf + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n V12_17_SIZES.set(sbfSize, n);\r\n}\r\n\r\n// ---- V12_19 layout constants ----\r\n// AUTHORITATIVE SBF VALUES extracted via deliberately-wrong const assertions\r\n// in the wrapper compiled with `cargo build-sbf --features small`. Every value\r\n// below comes from a Rust compile-error message that revealed the real SBF\r\n// offset. Source: 2026-04-28 SBF probe session, see audit notes.\r\n//\r\n// V12_19 vs V12_17 SBF differences:\r\n// - HEADER_LEN: 72 -> 136 (header gained insurance_authority + insurance_operator)\r\n// - CONFIG_LEN: 512 -> 480 (dropped max_insurance_floor and _iw_padding2)\r\n// - ENGINE_OFF: 584 -> 616\r\n// - ACCOUNT_SIZE: 352 -> 360\r\n// - SLAB_LEN small: 94168 -> 96784 (cu_benchmark.rs constant is stale)\r\n// - RiskEngine grew substantially; accounts now inline within engine struct.\r\nconst V12_19_HEADER_LEN_SBF = 136;\r\nconst V12_19_CONFIG_LEN = 480;\r\nconst V12_19_ENGINE_OFF_SBF = 616;\r\nconst V12_19_ACCOUNT_SIZE_SBF = 360;\r\nconst V12_19_SBF_RISK_BUF_LEN = 160;\r\nconst V12_19_SBF_GEN_TABLE_ENTRY = 8;\r\n\r\n// Within RiskEngine, relative to engine start (probe-confirmed on the live\r\n// af43efc mainnet small-tier slab). Some bitmap-region offsets depend on\r\n// MAX_ACCOUNTS; small (256) shown here.\r\nconst V12_19_SBF_ENGINE_BITMAP_OFF = 736; // [u64; ceil(MAX/64)] starts here\r\nconst V12_19_SBF_ENGINE_NUM_USED_OFF_S = 768; // small: bitmap is 32 bytes\r\nconst V12_19_SBF_ENGINE_FREE_HEAD_OFF_S = 770;\r\nconst V12_19_SBF_ENGINE_NEXT_FREE_OFF_S = 772; // [u16; 256] for small\r\nconst V12_19_SBF_ENGINE_PREV_FREE_OFF_S = 1284; // small: after next_free 512 bytes\r\nconst V12_19_SBF_ENGINE_ACCOUNTS_OFF_S = 1800; // small: after prev_free + 4-byte align\r\n\r\n// V12_19 SBF RiskEngine field offsets (rel to engine start, probe-confirmed):\r\nconst V12_19_SBF_ENGINE_PARAMS_OFF = 32;\r\nconst V12_19_SBF_ENGINE_PARAMS_SIZE = 168; // current_slot at 200, params is 168 bytes\r\nconst V12_19_SBF_ENGINE_CURRENT_SLOT_OFF = 200;\r\nconst V12_19_SBF_ENGINE_MARKET_MODE_OFF = 208;\r\nconst V12_19_SBF_ENGINE_RESOLVED_PRICE_OFF = 216;\r\nconst V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF = 304;\r\nconst V12_19_SBF_ENGINE_C_TOT_OFF = 312;\r\nconst V12_19_SBF_ENGINE_PNL_POS_TOT_OFF = 328;\r\nconst V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF = 344;\r\nconst V12_19_SBF_ENGINE_OI_EFF_LONG_OFF = 472;\r\nconst V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF = 488;\r\nconst V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF = 584;\r\nconst V12_19_SBF_ENGINE_RR_CURSOR_OFF = 592; // replaces V12_17 gc_cursor\r\nconst V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF = 624;\r\nconst V12_19_SBF_ENGINE_FUND_PX_LAST_OFF = 632;\r\nconst V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF = 640; // replaces V12_17 last_crank_slot\r\nconst V12_19_SBF_ENGINE_F_LONG_NUM_OFF = 648;\r\nconst V12_19_SBF_ENGINE_F_SHORT_NUM_OFF = 664;\r\n\r\n// V12_19 SBF MarketConfig field offsets (rel to config start, probe-confirmed):\r\nconst V12_19_SBF_CONFIG_HYPERP_AUTH_OFF = 144;\r\nconst V12_19_SBF_CONFIG_LAST_EFFECTIVE_OFF = 192;\r\nconst V12_19_SBF_CONFIG_TVL_INSURANCE_CAP_OFF = 202;\r\nconst V12_19_SBF_CONFIG_ORACLE_PRICE_CAP_OFF = 216;\r\nconst V12_19_SBF_CONFIG_MIN_ORACLE_CAP_OFF = 224;\r\nconst V12_19_SBF_CONFIG_MAINTENANCE_FEE_OFF = 320;\r\nconst V12_19_SBF_CONFIG_DEX_POOL_OFF = 368;\r\nconst V12_19_SBF_CONFIG_MAX_PNL_CAP_OFF = 400;\r\nconst V12_19_SBF_CONFIG_OI_CAP_MULT_OFF = 416;\r\nconst V12_19_SBF_CONFIG_PENDING_ADMIN_OFF = 448;\r\n\r\n// V12_19 SLAB_LEN values: probe-confirmed for small. Derived for other tiers\r\n// via the same formula: SLAB_LEN = ENGINE_OFF + ENGINE_LEN(N) + RISK_BUF_LEN\r\n// + GEN_TABLE_LEN(N), where ENGINE_LEN(N) = 712 + bitmap_bytes\r\n// + 4 (num_used + free_head) + 2N (next_free) + 2N (prev_free)\r\n// + (8-byte align pad) + N*360 (accounts).\r\n// Result after af43efc wrapper redeploy: micro=26872, small=96784\r\n// (mainnet probe-confirmed), medium=376432, large=1495024.\r\n// NOTE: cu_benchmark.rs constants (19640/94168/372280/1484728) are STALE for v12.19.\r\nconst V12_19_SIZES = new Map([\r\n [26872, 64], // --features micro (derived)\r\n [96784, 256], // --features small (probe-confirmed; deployed mainnet ESa89R5...)\r\n [376432, 1024], // --features medium (derived)\r\n [1495024, 4096], // default features / large (derived)\r\n]);\r\n\r\n/**\r\n * V12_19 slab layout. Probe-confirmed SBF values from compiled wrapper.\r\n *\r\n * Major structural difference vs V12_17 SBF: accounts array is INLINE within\r\n * RiskEngine (was separate region in V12_17). Bitmap moved from rel-engine\r\n * 736 area to same offset but the post-bitmap region now contains both\r\n * `next_free` and `prev_free` arrays (v12.19 added prev_free), plus padding\r\n * before the inline accounts.\r\n *\r\n * For the small tier (MAX_ACCOUNTS=256), accounts start at engineOff + 1800.\r\n * For other tiers, the offset shifts because next_free/prev_free sizes scale\r\n * linearly with MAX_ACCOUNTS.\r\n */\r\nfunction buildLayoutV12_19(maxAccounts: number, _dataLen: number): SlabLayout {\r\n // Compute layout-dependent offsets for this tier.\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const numUsedOff = V12_19_SBF_ENGINE_BITMAP_OFF + bitmapBytes; // bitmap end\r\n const freeHeadOff = numUsedOff + 2; // after num_used u16\r\n const nextFreeOff = freeHeadOff + 2; // after free_head u16\r\n const prevFreeOff = nextFreeOff + maxAccounts * 2; // after next_free [u16; N]\r\n const accountsRelEnd = prevFreeOff + maxAccounts * 2; // after prev_free [u16; N]\r\n const accountsOffRel = Math.ceil(accountsRelEnd / 8) * 8; // 8-align Account\r\n const accountsOff = V12_19_ENGINE_OFF_SBF + accountsOffRel; // absolute slab offset\r\n\r\n // Inherit Account-internal field offsets from V12_17 (they're the same since\r\n // the Account struct definition is identical between v12.17 and v12.19;\r\n // the +8 byte size diff is from trailing padding, not field reordering).\r\n const base = buildLayoutV12_17(maxAccounts, /* synthetic V12_17 SBF size */ 94168);\r\n\r\n return {\r\n ...base,\r\n headerLen: V12_19_HEADER_LEN_SBF,\r\n configLen: V12_19_CONFIG_LEN,\r\n configOffset: V12_19_HEADER_LEN_SBF, // header runs 0..136 in v12.19\r\n engineOff: V12_19_ENGINE_OFF_SBF,\r\n accountSize: V12_19_ACCOUNT_SIZE_SBF,\r\n accountsOff,\r\n bitmapWords,\r\n paramsSize: V12_19_SBF_ENGINE_PARAMS_SIZE,\r\n engineBitmapOff: V12_19_SBF_ENGINE_BITMAP_OFF,\r\n // V12_19-specific engine field offsets (probe-confirmed):\r\n engineCurrentSlotOff: V12_19_SBF_ENGINE_CURRENT_SLOT_OFF,\r\n engineCTotOff: V12_19_SBF_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V12_19_SBF_ENGINE_PNL_POS_TOT_OFF,\r\n engineLongOiOff: V12_19_SBF_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF,\r\n // last_market_slot replaces V12_17 last_crank_slot semantics.\r\n engineLastCrankSlotOff: V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF,\r\n // rr_cursor_position replaces V12_17 gc_cursor semantics.\r\n engineGcCursorOff: V12_19_SBF_ENGINE_RR_CURSOR_OFF,\r\n };\r\n}\r\n\r\n// SBF-specific V12_1 sizes (verified via cargo build-sbf compile-time offset_of! assertions).\r\n// SBF has ENGINE_OFF=616 (not 648) because HEADER=72 + CONFIG=544 = 616, align_up(616,8)=616.\r\n// Account=280 bytes on SBF (vs 320 on aarch64) due to u128 align=8 vs 16.\r\n// Bitmap at engine+584 (used field in RiskEngine).\r\nconst V12_1_SBF_ACCOUNT_SIZE = 280;\r\nconst V12_1_SBF_ENGINE_OFF = 616;\r\nconst V12_1_SBF_BITMAP_OFF = 584; // offset_of!(RiskEngine, used) on SBF\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;\r\n V12_1_SIZES.set(total, n);\r\n}\r\n// V12_1_EP: entry_price re-added, accountSize=288 on SBF. Same engineOff/bitmapOff.\r\nconst V12_1_EP_SIZES = new Map();\r\nfor (const [, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAccLen = V12_1_SBF_BITMAP_OFF + bitmapBytes + 18 + n * 2;\r\n const accountsOff = Math.ceil(preAccLen / 8) * 8;\r\n const total = V12_1_SBF_ENGINE_OFF + accountsOff + n * V12_1_EP_SBF_ACCOUNT_SIZE;\r\n V12_1_EP_SIZES.set(total, n);\r\n}\r\n\r\n/**\r\n * V2 slab tier sizes (small and large) for discovery.\r\n * V2 uses ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Sizes overlap with V1D (postBitmap=2) — disambiguation requires reading the version field.\r\n */\r\nexport const SLAB_TIERS_V2 = Object.freeze({\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V2 BPF intermediate)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V2 BPF intermediate)\" },\r\n} as const);\r\n\r\n/**\r\n * V1M slab tier sizes — mainnet-deployed V1 program (ESa89R5).\r\n * ENGINE_OFF=640, BITMAP_OFF=726, ACCOUNT_SIZE=248, postBitmap=18.\r\n * Expanded RiskParams (336 bytes) and trade_twap runtime fields.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (SOL/USDC Perpetual, 257512 bytes).\r\n */\r\nexport const SLAB_TIERS_V1M: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M mainnet)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M);\r\n\r\n/**\r\n * V1M2 slab tier sizes — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616, BITMAP_OFF=1008 (empirically verified from CCTegYZ...).\r\n * Engine struct is layout-identical to V_ADL; differs only in engineOff (616 vs 624).\r\n * Sizes are unique from V_ADL after the bitmap correction: medium=323312 vs V_ADL=323320.\r\n */\r\nexport const SLAB_TIERS_V1M2: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V1M2[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V1M2 mainnet upgraded)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V1M2);\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account including alignment padding).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288320 bytes.\r\n */\r\nexport const SLAB_TIERS_V_ADL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_ADL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_ADL PERC-8270)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_ADL);\r\n\r\n/**\r\n * Build a complete SlabLayout descriptor for V0 or V1 (including V1-legacy) slabs.\r\n * Pass `engineOffOverride` to handle orphaned pre-PERC-1094 slabs that used ENGINE_OFF=640.\r\n */\r\nfunction buildLayout(version: 0 | 1, maxAccounts: number, engineOffOverride?: number): SlabLayout {\r\n const isV0 = version === 0;\r\n const engineOff = engineOffOverride ?? (isV0 ? V0_ENGINE_OFF : V1_ENGINE_OFF);\r\n const isV1Legacy = !isV0 && engineOffOverride === V1_ENGINE_OFF_LEGACY;\r\n // For accountsOff calculation, V1_LEGACY must use its actual bitmap offset (672, not 656).\r\n // Using the formula bitmapOff (656) produces accountsOff=1864, but accounts actually\r\n // start at 1880 — a 16-byte gap caused by the extra fields in the V1_LEGACY engine.\r\n // Non-V1_LEGACY slabs: actualBitmapOff === bitmapOff, so no change.\r\n const bitmapOff = isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF;\r\n const actualBitmapOff = isV1Legacy ? V1_LEGACY_ENGINE_BITMAP_OFF_ACTUAL\r\n : (isV0 ? V0_ENGINE_BITMAP_OFF : V1_ENGINE_BITMAP_OFF);\r\n const accountSize = isV0 ? V0_ACCOUNT_SIZE : V1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n // Use actualBitmapOff so V1_LEGACY gets accountsOff=1880 (not 1864).\r\n const preAccountsLen = actualBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version,\r\n headerLen: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configOffset: isV0 ? V0_HEADER_LEN : V1_HEADER_LEN,\r\n configLen: isV0 ? V0_CONFIG_LEN : V1_CONFIG_LEN,\r\n reservedOff: isV0 ? V0_RESERVED_OFF : V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isV0 ? V0_ENGINE_PARAMS_OFF : V1_ENGINE_PARAMS_OFF,\r\n paramsSize: isV0 ? V0_PARAMS_SIZE : V1_PARAMS_SIZE,\r\n engineCurrentSlotOff: isV0 ? V0_ENGINE_CURRENT_SLOT_OFF : V1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isV0 ? V0_ENGINE_FUNDING_INDEX_OFF : V1_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: isV0 ? V0_ENGINE_LAST_FUNDING_SLOT_OFF : V1_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: isV0 ? V0_ENGINE_FUNDING_RATE_BPS_OFF : V1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isV0 ? -1 : V1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isV0 ? V0_ENGINE_LAST_CRANK_SLOT_OFF : V1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isV0 ? V0_ENGINE_MAX_CRANK_STALENESS_OFF : V1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isV0 ? V0_ENGINE_TOTAL_OI_OFF : V1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isV0 ? -1 : V1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isV0 ? -1 : V1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isV0 ? V0_ENGINE_C_TOT_OFF : V1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isV0 ? V0_ENGINE_PNL_POS_TOT_OFF : V1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isV0 ? V0_ENGINE_LIQ_CURSOR_OFF : V1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isV0 ? V0_ENGINE_GC_CURSOR_OFF : V1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isV0 ? V0_ENGINE_LAST_SWEEP_START_OFF : V1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isV0 ? V0_ENGINE_LAST_SWEEP_COMPLETE_OFF : V1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isV0 ? V0_ENGINE_CRANK_CURSOR_OFF : V1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isV0 ? V0_ENGINE_SWEEP_START_IDX_OFF : V1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isV0 ? V0_ENGINE_LIFETIME_LIQUIDATIONS_OFF : V1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isV0 ? V0_ENGINE_LIFETIME_FORCE_CLOSES_OFF : V1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: isV0 ? V0_ENGINE_NET_LP_POS_OFF : V1_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: isV0 ? V0_ENGINE_LP_SUM_ABS_OFF : V1_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: isV0 ? V0_ENGINE_LP_MAX_ABS_OFF : V1_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: isV0 ? V0_ENGINE_LP_MAX_ABS_SWEEP_OFF : V1_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: isV0 ? -1 : V1_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: isV0 ? -1 : V1_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: actualBitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: isV1Legacy ? V1_LEGACY_ACCT_OWNER_OFF : ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: !isV0,\r\n engineInsuranceIsolatedOff: isV0 ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isV0 ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build layout for V1D (actually deployed V1 program, rev ac18a0e).\r\n * Uses correct field offsets derived from on-chain probing.\r\n *\r\n * @param maxAccounts - Number of account slots in the slab\r\n * @param postBitmap - Bytes after the bitmap before next_free array.\r\n * 2 = free_head(u16) only — deployed program (GH#1234, default for new slabs)\r\n * 18 = num_used(u16)+pad(6)+next_account_id(u64)+free_head(u16) — legacy on-chain slabs (GH#1237)\r\n */\r\n/**\r\n * Build a SlabLayout for the actually-deployed V1D program (ENGINE_OFF=424).\r\n * `postBitmap` is 2 for new slabs (free_head only) and 18 for legacy on-chain slabs\r\n * created before the GH#1234 fix that removed num_used/pad/next_account_id.\r\n */\r\nfunction buildLayoutV1D(maxAccounts: number, postBitmap = 2): SlabLayout {\r\n const engineOff = V1D_ENGINE_OFF;\r\n const bitmapOff = V1D_ENGINE_BITMAP_OFF;\r\n const accountSize = V1D_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1D_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: V1D_ENGINE_INSURANCE_OFF,\r\n engineParamsOff: V1D_ENGINE_PARAMS_OFF,\r\n paramsSize: V1D_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1D_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1D_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1D_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1D_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1D_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1D_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1D_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1D_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1D_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1D_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1D_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1D_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1D_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1D_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1D_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1D_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1D_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1D_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1D_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1D_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1D_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1D_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: -1, // not present in deployed V1\r\n engineLpMaxAbsSweepOff: -1, // not present in deployed V1\r\n engineEmergencyOiModeOff: -1, // not present in deployed V1\r\n engineEmergencyStartSlotOff: -1, // not present in deployed V1\r\n engineLastBreakerSlotOff: -1, // not present in deployed V1\r\n engineBitmapOff: V1D_ENGINE_BITMAP_OFF,\r\n postBitmap,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48, // same within InsuranceFund\r\n engineInsuranceIsolationBpsOff: 64, // same within InsuranceFund\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V2 (BPF intermediate layout).\r\n * ENGINE_OFF=600, BITMAP_OFF=432, ACCOUNT_SIZE=248, postBitmap=18.\r\n * V2 lacks mark_price, long_oi, short_oi, emergency OI fields.\r\n */\r\nfunction buildLayoutV2(maxAccounts: number): SlabLayout {\r\n const engineOff = V2_ENGINE_OFF;\r\n const bitmapOff = V2_ENGINE_BITMAP_OFF;\r\n const accountSize = V2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V2_HEADER_LEN,\r\n configOffset: V2_HEADER_LEN,\r\n configLen: V2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF, // V2 shares V1's header layout (reserved at 80)\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1_ENGINE_PARAMS_OFF, // same as V1: 72\r\n paramsSize: V1_PARAMS_SIZE, // same as V1: 288\r\n engineCurrentSlotOff: V2_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V2_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V2_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V2_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: -1, // V2 has no mark_price\r\n engineLastCrankSlotOff: V2_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V2_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V2_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: -1, // V2 has no long_oi\r\n engineShortOiOff: -1, // V2 has no short_oi\r\n engineCTotOff: V2_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V2_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V2_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V2_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V2_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V2_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V2_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V2_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V2_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V2_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V2_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V2_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V2_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V2_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: -1, // V2 has no emergency OI fields\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: V2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the V1M mainnet program (ESa89R5).\r\n * ENGINE_OFF=640 (same as V1_LEGACY), but expanded RiskParams (336 bytes)\r\n * and trade_twap runtime fields push the bitmap to offset 726.\r\n * Confirmed by on-chain probing of slab 8NY7rvQ (257512 bytes, medium tier).\r\n */\r\nfunction buildLayoutV1M(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M_ENGINE_OFF;\r\n const bitmapOff = V1M_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M_ENGINE_PARAMS_OFF,\r\n paramsSize: V1M_PARAMS_SIZE,\r\n engineCurrentSlotOff: V1M_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V1M_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V1M_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V1M_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V1M_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V1M_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V1M_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V1M_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V1M_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V1M_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V1M_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V1M_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V1M_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V1M_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V1M_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V1M_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V1M_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V1M_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V1M_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V1M_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V1M_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V1M_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V1M_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V1M_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V1M_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V1M_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V1M_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V1M_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V1M2 — mainnet program rebuilt from main@4861c56 with 312-byte accounts.\r\n * ENGINE_OFF=616 (align_up(104+512,8)=616), CONFIG_LEN=512.\r\n * The engine struct is layout-identical to V_ADL (same relative field offsets from engineOff),\r\n * so all runtime field offsets reuse V_ADL constants. bitmapOff=1008 (same as V_ADL).\r\n * This differs from V_ADL only in engineOff (616 vs 624) and configLen (512 vs 520).\r\n * Confirmed by empirical probing of mainnet slab CCTegYZ... (323312 bytes, 1024-account medium tier).\r\n */\r\nfunction buildLayoutV1M2(maxAccounts: number): SlabLayout {\r\n const engineOff = V1M2_ENGINE_OFF;\r\n const bitmapOff = V1M2_ENGINE_BITMAP_OFF;\r\n const accountSize = V1M2_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V1M2_CONFIG_LEN,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V1M2_ENGINE_PARAMS_OFF, // 96 — expanded InsuranceFund (same as V_ADL)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336 — same as V_ADL\r\n // Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192 — same shift as V_ADL (reserved_pnl u64→u128)\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for the ADL-upgraded program (PERC-8270/8271).\r\n * ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312.\r\n *\r\n * Verified slab sizes (BPF, cargo build-sbf, bitmapOff corrected to 1008):\r\n * large (4096 accounts): 1288320 bytes\r\n * medium (1024 accounts): 323320 bytes\r\n * small (256 accounts): 82064 bytes\r\n */\r\nfunction buildLayoutVADL(maxAccounts: number): SlabLayout {\r\n const engineOff = V_ADL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN, // 104 (unchanged)\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_ADL_CONFIG_LEN, // 520\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF, // 96 (vault=16 + InsuranceFund=80)\r\n paramsSize: V_ADL_PARAMS_SIZE, // 336\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF, // 432\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF, // 440\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF, // 456\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF, // 464\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF, // 504\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF, // 528\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF, // 536\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF, // 544\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF, // 560\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF, // 576\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF, // 592\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF, // 608\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF, // 640\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF, // 642\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF, // 648\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF, // 656\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF, // 664\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF, // 666\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF, // 672\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // 680\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF, // 904\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF, // 920\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF, // 936\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF, // 952\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF, // 968\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF, // 976\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF, // 984\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF, // 1008\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\n/**\r\n * V_SETDEXPOOL slab tier sizes — PERC-SetDexPool security fix.\r\n * ENGINE_OFF=632, BITMAP_OFF=1008, ACCOUNT_SIZE=312, CONFIG_LEN=528.\r\n * e.g. large (4096 accts) = 1288336 bytes.\r\n */\r\nexport const SLAB_TIERS_V_SETDEXPOOL: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V_SETDEXPOOL);\r\n\r\n/**\r\n * V12_1 slab tier sizes — percolator-core v12.1 merge.\r\n * ENGINE_OFF=648, BITMAP_OFF=1016, ACCOUNT_SIZE=320.\r\n * Verified by cargo build-sbf compile-time assertions.\r\n */\r\nexport const SLAB_TIERS_V12_1: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_1);\r\n\r\n/**\r\n * V12_15 slab tier sizes — percolator v12.15 (engine+prog sync).\r\n * ENGINE_OFF=624, BITMAP_OFF=862 (relative), ACCOUNT_SIZE=4400, postBitmap=18.\r\n * MAX_ACCOUNTS default changed from 4096 to 2048. Verified SLAB_LEN=1,128,448 for small (256).\r\n * Account layout completely redesigned with reserve cohort arrays.\r\n */\r\nexport const SLAB_TIERS_V12_15: Record = {};\r\nfor (const [label, n] of [[\"Micro\", 64], [\"Small\", 256], [\"Medium\", 1024], [\"Medium2048\", 2048], [\"Large\", 4096]] as const) {\r\n const size = computeSlabSize(V12_15_ENGINE_OFF, V12_15_ENGINE_BITMAP_OFF, V12_15_ACCOUNT_SIZE, n, 18);\r\n SLAB_TIERS_V12_15[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.15)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_15);\r\n\r\n/**\r\n * V12_17 slab tier sizes — percolator v12.17 (two-bucket warmup, per-side funding).\r\n * Uses SBF sizes (on-chain layout) for the dataSize values.\r\n * ENGINE_OFF=504 (SBF), ACCOUNT_SIZE=352 (SBF), BITMAP_OFF=712 (SBF), postBitmap=4.\r\n * RISK_BUF_LEN=160 appended after engine.\r\n * Supported tiers: small(256), medium(1024), large(4096).\r\n */\r\nexport const SLAB_TIERS_V12_17: Record = {};\r\nfor (const [label, n] of [[\"Small\", 256], [\"Medium\", 1024], [\"Large\", 4096]] as const) {\r\n const bitmapBytes = Math.ceil(n / 64) * 8;\r\n const preAcc = V12_17_ENGINE_BITMAP_OFF_SBF + bitmapBytes + 4 + n * 2;\r\n const accountsOff = Math.ceil(preAcc / 8) * 8;\r\n const size = V12_17_ENGINE_OFF_SBF + accountsOff + n * V12_17_ACCOUNT_SIZE_SBF + V12_17_RISK_BUF_LEN + n * V12_17_GEN_TABLE_ENTRY;\r\n SLAB_TIERS_V12_17[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.17)` };\r\n}\r\nObject.freeze(SLAB_TIERS_V12_17);\r\n\r\n/**\r\n * V12_19 slab tier sizes (probe-confirmed via cargo build-sbf compile-time\r\n * assertions on 2026-04-28). Used by `discoverMarkets` to filter program\r\n * accounts by dataSize. Without this tier set, v12.19 slabs (the only kind\r\n * the deployed mainnet program ESa89R5... produces post-2026-04-28 upgrade)\r\n * fall through to the memcmp fallback path with no layout hint.\r\n *\r\n * Sizes derived from V12_19_SIZES Map (defined earlier in this file at the\r\n * V12_19 layout block). Kept as Record for parity with other SLAB_TIERS_*\r\n * exports consumed by discovery.ts.\r\n */\r\nexport const SLAB_TIERS_V12_19: Record = Object.freeze({\r\n micro: { maxAccounts: 64, dataSize: 26_872, label: \"Micro\", description: \"64 slots (v12.19, --features micro)\" },\r\n small: { maxAccounts: 256, dataSize: 96_784, label: \"Small\", description: \"256 slots (v12.19, --features small) — deployed mainnet ESa89R5...\" },\r\n medium: { maxAccounts: 1024, dataSize: 376_432, label: \"Medium\", description: \"1024 slots (v12.19, --features medium)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_495_024, label: \"Large\", description: \"4096 slots (v12.19, default features)\" },\r\n});\r\n\r\n/**\r\n * Build a SlabLayout for V_SETDEXPOOL slabs (PERC-SetDexPool security fix).\r\n * ENGINE_OFF=632 (+8 from V_ADL=624 due to CONFIG_LEN growing 520→528).\r\n * All engine and account field offsets are identical to V_ADL.\r\n */\r\nfunction buildLayoutVSetDexPool(maxAccounts: number): SlabLayout {\r\n const engineOff = V_SETDEXPOOL_ENGINE_OFF;\r\n const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;\r\n const accountSize = V_ADL_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V1_HEADER_LEN,\r\n configOffset: V1_HEADER_LEN,\r\n configLen: V_SETDEXPOOL_CONFIG_LEN, // 544\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,\r\n paramsSize: V_ADL_PARAMS_SIZE,\r\n engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,\r\n engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,\r\n engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,\r\n engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,\r\n engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,\r\n engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,\r\n engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,\r\n engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,\r\n engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,\r\n engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,\r\n engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,\r\n postBitmap: 18,\r\n acctOwnerOff: V_ADL_ACCT_OWNER_OFF,\r\n\r\n hasInsuranceIsolation: true,\r\n engineInsuranceIsolatedOff: 48,\r\n engineInsuranceIsolationBpsOff: 64,\r\n };\r\n}\r\n\r\nfunction buildLayoutV12_1(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF vs host detection via size comparison.\r\n // SBF (deployed): HEADER=72, CONFIG=544, ENGINE_OFF=616, ACCOUNT=280, BITMAP=engine+584\r\n // Host (tests): HEADER=72, CONFIG=576, ENGINE_OFF=648, ACCOUNT=320, BITMAP=engine+1016\r\n // All SBF offsets verified via `cargo build-sbf` compile-time offset_of! assertions.\r\n const hostSize = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, maxAccounts, 18);\r\n const isSbf = dataLen !== undefined && dataLen !== hostSize;\r\n const engineOff = isSbf ? V12_1_SBF_ENGINE_OFF : V12_1_ENGINE_OFF;\r\n const bitmapOff = isSbf ? V12_1_SBF_BITMAP_OFF : V12_1_ENGINE_BITMAP_OFF;\r\n const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: isSbf ? 544 : 576,\r\n reservedOff: V1_RESERVED_OFF,\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: isSbf ? V12_1_ENGINE_PARAMS_OFF_SBF : V12_1_ENGINE_PARAMS_OFF_HOST,\r\n paramsSize: isSbf ? V12_1_PARAMS_SIZE_SBF : V12_1_PARAMS_SIZE,\r\n // SBF engine offsets — all verified by cargo build-sbf offset_of! assertions.\r\n // Fields that don't exist in the deployed program are set to -1 on SBF.\r\n engineCurrentSlotOff: isSbf ? V12_1_SBF_OFF_CURRENT_SLOT : V12_1_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: isSbf ? -1 : V12_1_ENGINE_FUNDING_INDEX_OFF, // not in deployed struct\r\n engineLastFundingSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_FUNDING_SLOT_OFF, // not in deployed struct\r\n engineFundingRateBpsOff: isSbf ? V12_1_SBF_OFF_FUNDING_RATE : V12_1_ENGINE_FUNDING_RATE_BPS_OFF,\r\n engineMarkPriceOff: isSbf ? V12_1_SBF_OFF_MARK_PRICE_E6 : V12_1_ENGINE_MARK_PRICE_OFF,\r\n engineLastCrankSlotOff: isSbf ? V12_1_SBF_OFF_LAST_CRANK_SLOT : V12_1_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: isSbf ? V12_1_SBF_OFF_MAX_CRANK_STALENESS : V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,\r\n engineTotalOiOff: isSbf ? V12_1_SBF_OFF_TOTAL_OI : V12_1_ENGINE_TOTAL_OI_OFF,\r\n engineLongOiOff: isSbf ? V12_1_SBF_OFF_LONG_OI : V12_1_ENGINE_LONG_OI_OFF,\r\n engineShortOiOff: isSbf ? V12_1_SBF_OFF_SHORT_OI : V12_1_ENGINE_SHORT_OI_OFF,\r\n engineCTotOff: isSbf ? V12_1_SBF_OFF_C_TOT : V12_1_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_1_SBF_OFF_PNL_POS_TOT : V12_1_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: isSbf ? V12_1_SBF_OFF_LIQ_CURSOR : V12_1_ENGINE_LIQ_CURSOR_OFF,\r\n engineGcCursorOff: isSbf ? V12_1_SBF_OFF_GC_CURSOR : V12_1_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_START : V12_1_ENGINE_LAST_SWEEP_START_OFF,\r\n engineLastSweepCompleteOff: isSbf ? V12_1_SBF_OFF_LAST_SWEEP_COMPLETE : V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,\r\n engineCrankCursorOff: isSbf ? V12_1_SBF_OFF_CRANK_CURSOR : V12_1_ENGINE_CRANK_CURSOR_OFF,\r\n engineSweepStartIdxOff: isSbf ? V12_1_SBF_OFF_SWEEP_START_IDX : V12_1_ENGINE_SWEEP_START_IDX_OFF,\r\n engineLifetimeLiquidationsOff: isSbf ? V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS : V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,\r\n engineLifetimeForceClosesOff: isSbf ? -1 : V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF, // not in deployed struct\r\n engineNetLpPosOff: isSbf ? -1 : V12_1_ENGINE_NET_LP_POS_OFF, // not in deployed struct\r\n engineLpSumAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_SUM_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_OFF, // not in deployed struct\r\n engineLpMaxAbsSweepOff: isSbf ? -1 : V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF, // not in deployed struct\r\n engineEmergencyOiModeOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_OI_MODE_OFF, // not in deployed struct\r\n engineEmergencyStartSlotOff: isSbf ? -1 : V12_1_ENGINE_EMERGENCY_START_SLOT_OFF, // not in deployed struct\r\n engineLastBreakerSlotOff: isSbf ? -1 : V12_1_ENGINE_LAST_BREAKER_SLOT_OFF, // not in deployed struct\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n acctOwnerOff: V12_1_ACCT_OWNER_OFF,\r\n\r\n // InsuranceFund on deployed program is just {balance: U128} = 16 bytes.\r\n // No isolated_balance or insurance_isolation_bps fields.\r\n hasInsuranceIsolation: !isSbf,\r\n engineInsuranceIsolatedOff: isSbf ? -1 : 48,\r\n engineInsuranceIsolationBpsOff: isSbf ? -1 : 64,\r\n };\r\n}\r\n\r\n/**\r\n * V12_1 with entry_price re-added (SBF only, accountSize=288).\r\n * Same engine layout as V12_1 SBF, but account offsets shift +8 after entry_price.\r\n */\r\nfunction buildLayoutV12_1EP(maxAccounts: number): SlabLayout {\r\n const engineOff = V12_1_SBF_ENGINE_OFF; // 616\r\n const bitmapOff = V12_1_SBF_BITMAP_OFF; // 584\r\n const accountSize = V12_1_EP_SBF_ACCOUNT_SIZE; // 288\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 1,\r\n headerLen: 72,\r\n configOffset: 72,\r\n configLen: 544,\r\n reservedOff: 80, // V1_RESERVED_OFF\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: 32, // V12_1_ENGINE_PARAMS_OFF_SBF\r\n paramsSize: 184, // V12_1_PARAMS_SIZE_SBF\r\n // Engine offsets identical to V12_1 SBF\r\n engineCurrentSlotOff: V12_1_SBF_OFF_CURRENT_SLOT,\r\n engineFundingIndexOff: -1,\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: V12_1_SBF_OFF_FUNDING_RATE,\r\n engineMarkPriceOff: V12_1_SBF_OFF_MARK_PRICE_E6,\r\n engineLastCrankSlotOff: V12_1_SBF_OFF_LAST_CRANK_SLOT,\r\n engineMaxCrankStalenessOff: V12_1_SBF_OFF_MAX_CRANK_STALENESS,\r\n engineTotalOiOff: V12_1_SBF_OFF_TOTAL_OI,\r\n engineLongOiOff: V12_1_SBF_OFF_LONG_OI,\r\n engineShortOiOff: V12_1_SBF_OFF_SHORT_OI,\r\n engineCTotOff: V12_1_SBF_OFF_C_TOT,\r\n enginePnlPosTotOff: V12_1_SBF_OFF_PNL_POS_TOT,\r\n engineLiqCursorOff: V12_1_SBF_OFF_LIQ_CURSOR,\r\n engineGcCursorOff: V12_1_SBF_OFF_GC_CURSOR,\r\n engineLastSweepStartOff: V12_1_SBF_OFF_LAST_SWEEP_START,\r\n engineLastSweepCompleteOff: V12_1_SBF_OFF_LAST_SWEEP_COMPLETE,\r\n engineCrankCursorOff: V12_1_SBF_OFF_CRANK_CURSOR,\r\n engineSweepStartIdxOff: V12_1_SBF_OFF_SWEEP_START_IDX,\r\n engineLifetimeLiquidationsOff: V12_1_SBF_OFF_LIFETIME_LIQUIDATIONS,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap: 18,\r\n // Account offsets — shifted +8 from V12_1 due to entry_price insertion\r\n acctOwnerOff: V12_1_EP_ACCT_OWNER_OFF, // 216 (was 208)\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_15 slabs (percolator v12.15 engine+prog sync).\r\n * ENGINE_OFF=624, ACCOUNT_SIZE=4400, BITMAP_OFF=862 (relative to engineOff).\r\n * Account layout: new reserve cohort arrays, entry_price re-added at offset 120,\r\n * warmupStartedAtSlot/warmupSlopePerStep/lastFeeSlot removed.\r\n *\r\n * @param maxAccounts - Number of account slots (256, 1024, 2048, or 4096)\r\n */\r\nfunction buildLayoutV12_15(maxAccounts: number, dataLen?: number): SlabLayout {\r\n // SBF has i128 align=8 (not 16), so ENGINE_OFF=616 (not 624) and params=184 (not 192).\r\n const isSbf = dataLen === 237512;\r\n const accountSize = isSbf ? V12_15_ACCOUNT_SIZE_SMALL : V12_15_ACCOUNT_SIZE;\r\n const engineOff = isSbf ? V12_15_ENGINE_OFF_SBF : V12_15_ENGINE_OFF;\r\n const bitmapOff = V12_15_ENGINE_BITMAP_OFF;\r\n // SBF small has different bitmap/accounts offsets due to u128 align=8\r\n const effectiveBitmapOff = isSbf ? 648 : bitmapOff; // SBF bitmap at engine+648 (verified on-chain)\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = effectiveBitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n configLen: 552, // SBF CONFIG_LEN for v12.15\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_15_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : V12_15_PARAMS_SIZE, // SBF=184 (no trailing pad), native=192\r\n engineCurrentSlotOff: isSbf ? 216 : V12_15_ENGINE_CURRENT_SLOT_OFF, // SBF=216, native=224\r\n engineFundingIndexOff: -1, // not present in v12.15 engine struct\r\n engineLastFundingSlotOff: -1, // not present in v12.15 engine struct\r\n engineFundingRateBpsOff: isSbf ? 224 : V12_15_ENGINE_FUNDING_RATE_E9_OFF, // SBF=224, native=240\r\n engineMarkPriceOff: -1, // not present in v12.15\r\n engineLastCrankSlotOff: -1, // not yet mapped\r\n engineMaxCrankStalenessOff: -1, // not yet mapped\r\n engineTotalOiOff: -1, // not present in v12.15 engine\r\n engineLongOiOff: -1, // not present in v12.15 engine\r\n engineShortOiOff: -1, // not present in v12.15 engine\r\n engineCTotOff: isSbf ? 320 : V12_15_ENGINE_C_TOT_OFF, // SBF=320 (verified on-chain), native=344\r\n enginePnlPosTotOff: isSbf ? 336 : V12_15_ENGINE_PNL_POS_TOT_OFF, // SBF=336 (verified), native=368\r\n engineLiqCursorOff: -1, // not yet mapped\r\n engineGcCursorOff: -1, // not yet mapped\r\n engineLastSweepStartOff: -1, // not yet mapped\r\n engineLastSweepCompleteOff: -1, // not yet mapped\r\n engineCrankCursorOff: -1, // not yet mapped\r\n engineSweepStartIdxOff: -1, // not yet mapped\r\n engineLifetimeLiquidationsOff: -1, // not yet mapped\r\n engineLifetimeForceClosesOff: -1, // not present in v12.15\r\n engineNetLpPosOff: -1, // not present in v12.15\r\n engineLpSumAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsOff: -1, // not present in v12.15\r\n engineLpMaxAbsSweepOff: -1, // not present in v12.15\r\n engineEmergencyOiModeOff: -1, // not present in v12.15\r\n engineEmergencyStartSlotOff: -1, // not present in v12.15\r\n engineLastBreakerSlotOff: -1, // not present in v12.15\r\n engineBitmapOff: effectiveBitmapOff, // SBF=640, native=862\r\n postBitmap,\r\n acctOwnerOff: V12_15_ACCT_OWNER_OFF, // 192\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n };\r\n}\r\n\r\n/**\r\n * Build a SlabLayout for V12_17 slabs (two-bucket warmup, per-side funding).\r\n * Account: 368 bytes (native) / 352 bytes (SBF). No cohort arrays, no account_id, no entry_price.\r\n * Engine: per-side cumulative funding (f_long_num/f_short_num), no stored funding_rate_e9.\r\n * postBitmap=4 (num_used_accounts: u16 + free_head: u16).\r\n * RISK_BUF_LEN=160 appended after engine.\r\n */\r\nfunction buildLayoutV12_17(maxAccounts: number, dataLen: number): SlabLayout {\r\n // Detect SBF vs native from account size and engine offset.\r\n // SBF: ACCOUNT_SIZE=352, ENGINE_OFF=504. Native: ACCOUNT_SIZE=368, ENGINE_OFF=512.\r\n const isSbf = (() => {\r\n // Compute expected native size for this tier\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const preAccNative = V12_17_ENGINE_BITMAP_OFF + bitmapBytes + 4 + maxAccounts * 2;\r\n const accountsOffNative = Math.ceil(preAccNative / 16) * 16;\r\n const nativeSize = V12_17_ENGINE_OFF + accountsOffNative + maxAccounts * V12_17_ACCOUNT_SIZE + V12_17_RISK_BUF_LEN + maxAccounts * V12_17_GEN_TABLE_ENTRY;\r\n return dataLen !== nativeSize;\r\n })();\r\n\r\n const engineOff = isSbf ? V12_17_ENGINE_OFF_SBF : V12_17_ENGINE_OFF;\r\n const accountSize = isSbf ? V12_17_ACCOUNT_SIZE_SBF : V12_17_ACCOUNT_SIZE;\r\n const bitmapOff = isSbf ? V12_17_ENGINE_BITMAP_OFF_SBF : V12_17_ENGINE_BITMAP_OFF;\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const bitmapBytes = bitmapWords * 8;\r\n const postBitmap = 4;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;\r\n const acctAlign = isSbf ? 8 : 16;\r\n const accountsOffRel = Math.ceil(preAccountsLen / acctAlign) * acctAlign;\r\n\r\n return {\r\n version: 2,\r\n headerLen: V0_HEADER_LEN, // 72\r\n configOffset: V0_HEADER_LEN, // 72\r\n // configLen = 512 (SBF-aligned MarketConfig size after Phase A/B/E).\r\n // Verified field-by-field against percolator-prog/src/percolator.rs MarketConfig struct.\r\n // Missing 80 bytes from prior value 432: max_pnl_cap, last_audit_pause_slot,\r\n // oi_cap_multiplier_bps, dispute_window_slots, dispute_bond_amount,\r\n // lp_collateral_enabled, lp_collateral_ltv_bps, _new_fields_pad, pending_admin.\r\n configLen: 512,\r\n reservedOff: V1_RESERVED_OFF, // 80\r\n engineOff,\r\n accountSize,\r\n maxAccounts,\r\n bitmapWords,\r\n accountsOff: engineOff + accountsOffRel,\r\n\r\n engineInsuranceOff: 16,\r\n engineParamsOff: V12_17_ENGINE_PARAMS_OFF, // 32\r\n paramsSize: isSbf ? 184 : 192,\r\n engineCurrentSlotOff: isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF,\r\n engineFundingIndexOff: -1, // replaced by per-side f_long_num/f_short_num\r\n engineLastFundingSlotOff: -1,\r\n engineFundingRateBpsOff: -1, // no stored funding rate in v12.17\r\n engineMarkPriceOff: -1, // v12.17 computes mark from state; no stored field\r\n engineLastCrankSlotOff: isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF,\r\n engineMaxCrankStalenessOff: -1,\r\n engineTotalOiOff: -1, // parseEngine sums long + short when total offset is -1\r\n engineLongOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF,\r\n engineShortOiOff: isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF,\r\n engineCTotOff: isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF,\r\n enginePnlPosTotOff: isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF,\r\n engineLiqCursorOff: -1, // removed in v12.17\r\n engineGcCursorOff: isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF,\r\n engineLastSweepStartOff: -1,\r\n engineLastSweepCompleteOff: -1,\r\n engineCrankCursorOff: -1,\r\n engineSweepStartIdxOff: -1,\r\n engineLifetimeLiquidationsOff: -1,\r\n engineLifetimeForceClosesOff: -1,\r\n engineNetLpPosOff: -1,\r\n engineLpSumAbsOff: -1,\r\n engineLpMaxAbsOff: -1,\r\n engineLpMaxAbsSweepOff: -1,\r\n engineEmergencyOiModeOff: -1,\r\n engineEmergencyStartSlotOff: -1,\r\n engineLastBreakerSlotOff: -1,\r\n engineBitmapOff: bitmapOff,\r\n postBitmap,\r\n acctOwnerOff: isSbf ? 192 : V12_17_ACCT_OWNER_OFF, // SBF=192, native=200\r\n\r\n hasInsuranceIsolation: false,\r\n engineInsuranceIsolatedOff: -1,\r\n engineInsuranceIsolationBpsOff: -1,\r\n\r\n // v12.17 dropped the engine.mark_price field (see engineMarkPriceOff above).\r\n // The EWMA-smoothed mark that the matcher actually quotes against lives in\r\n // MarketConfig.mark_ewma_e6 at offset 304 within the config struct.\r\n // Layout is identical on SBF and native. configOffset is V0_HEADER_LEN = 72,\r\n // so absolute offset in the slab is 72 + 304 = 376.\r\n configMarkEwmaOff: V0_HEADER_LEN + 304,\r\n };\r\n}\r\n\r\n/**\r\n * Detect the slab layout version from the raw account data length.\r\n * Returns the full SlabLayout descriptor, or null if the size is unrecognised.\r\n * Checks V12_15, V12_1_EP, V12_1, V_SETDEXPOOL, V1M2, V_ADL, V1M, V0, V1D, V1D-legacy, V1, and V1-legacy sizes.\r\n *\r\n * When `data` is provided and the size matches V1D, the version field at offset 8 is read\r\n * to disambiguate V2 slabs (which produce identical sizes to V1D with postBitmap=2).\r\n * V2 slabs have version===2 at offset 8 (u32 LE).\r\n *\r\n * @param dataLen - The slab account data length in bytes\r\n * @param data - Optional raw slab data for version-field disambiguation\r\n */\r\n/**\r\n * Assert that a built SlabLayout is internally consistent.\r\n * Throws if accountsOff > dataLen or if any required bitmap region extends past the data.\r\n * Used by layout builders to catch offset arithmetic bugs early.\r\n *\r\n * @param layout - Layout descriptor to validate.\r\n * @param dataLen - Actual byte length of the slab data buffer.\r\n * @returns The validated layout (identity function for chaining).\r\n */\r\nfunction validateLayout(layout: SlabLayout, dataLen: number): SlabLayout {\r\n if (layout.accountsOff > dataLen) {\r\n throw new Error(\r\n `validateLayout: accountsOff (${layout.accountsOff}) exceeds data length (${dataLen}) ` +\r\n `for engineOff=${layout.engineOff} accountSize=${layout.accountSize} maxAccounts=${layout.maxAccounts}`\r\n );\r\n }\r\n const bitmapEnd = layout.engineOff + layout.engineBitmapOff + layout.bitmapWords * 8;\r\n if (bitmapEnd > dataLen) {\r\n throw new Error(\r\n `validateLayout: bitmap region end (${bitmapEnd}) exceeds data length (${dataLen})`\r\n );\r\n }\r\n return layout;\r\n}\r\n\r\nexport function detectSlabLayout(dataLen: number, data?: Uint8Array): SlabLayout | null {\r\n // Check V12_19 sizes first. Mainnet program ESa89R5... was upgraded to\r\n // v12.19 (--features small) on 2026-04-28; any slab created post-upgrade\r\n // is v12.19. Some sizes (94168) collide with V12_17 SBF small; the\r\n // deployed program only emits v12.19 going forward, so this priority\r\n // is correct for live mainnet reads.\r\n const v1219n = V12_19_SIZES.get(dataLen);\r\n if (v1219n !== undefined) return validateLayout(buildLayoutV12_19(v1219n, dataLen), dataLen);\r\n\r\n // Check V12_17 sizes (two-bucket warmup, per-side funding).\r\n // Unique account sizes (368 native / 352 SBF) + RISK_BUF — no collision with V12_15 (4400-byte accounts).\r\n const v1217n = V12_17_SIZES.get(dataLen);\r\n if (v1217n !== undefined) return validateLayout(buildLayoutV12_17(v1217n, dataLen), dataLen);\r\n\r\n // Check V12_15 sizes (v12.15 engine+prog sync, ACCOUNT_SIZE=4400).\r\n // Vastly larger account size — no collision with any earlier layout possible.\r\n const v1215n = V12_15_SIZES.get(dataLen);\r\n if (v1215n !== undefined) return validateLayout(buildLayoutV12_15(v1215n, dataLen), dataLen);\r\n\r\n // Check V12_1_EP sizes (entry_price re-added, ACCOUNT_SIZE=288 on SBF).\r\n // Must be checked before V12_1 (280-byte accounts) to avoid misdetection.\r\n const v121epn = V12_1_EP_SIZES.get(dataLen);\r\n if (v121epn !== undefined) return validateLayout(buildLayoutV12_1EP(v121epn), dataLen);\r\n\r\n // Check V12_1 sizes (percolator-core v12.1, ACCOUNT_SIZE=320/280, no entry_price).\r\n const v121n = V12_1_SIZES.get(dataLen);\r\n if (v121n !== undefined) return validateLayout(buildLayoutV12_1(v121n, dataLen), dataLen);\r\n\r\n // Check V_SETDEXPOOL sizes (PERC-SetDexPool, ENGINE_OFF=648, CONFIG_LEN=544).\r\n // These are the pre-v12.1 newest slabs — largest ENGINE_OFF so no size collision with V_ADL (624).\r\n const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);\r\n if (vsdpn !== undefined) return validateLayout(buildLayoutVSetDexPool(vsdpn), dataLen);\r\n\r\n // Check V1M2 sizes. After fixing bitmapOff to 1008 for both V1M2 and V_ADL,\r\n // their sizes no longer collide (engineOff differs: 616 vs 624), so size-based detection\r\n // works directly — no data-probe disambiguation required.\r\n // V1M2 medium (1024 accts): computeSlabSize(616, 1008, 312, 1024, 18) = 323312\r\n // V_ADL medium (1024 accts): computeSlabSize(624, 1008, 312, 1024, 18) = 323320\r\n const v1m2n = V1M2_SIZES.get(dataLen);\r\n if (v1m2n !== undefined) return validateLayout(buildLayoutV1M2(v1m2n), dataLen);\r\n\r\n // Check V_ADL sizes (PERC-8270/8271, ENGINE_OFF=624, BITMAP_OFF=1008, ACCOUNT_SIZE=312).\r\n const vadln = V_ADL_SIZES.get(dataLen);\r\n if (vadln !== undefined) return validateLayout(buildLayoutVADL(vadln), dataLen);\r\n\r\n // Check V1M sizes (mainnet-deployed V1 program, ESa89R5).\r\n // Must be checked before V1_LEGACY because V1M sizes are unique and don't overlap.\r\n const v1mn = V1M_SIZES.get(dataLen);\r\n if (v1mn !== undefined) return validateLayout(buildLayoutV1M(v1mn), dataLen);\r\n\r\n // Check V0 sizes (deployed devnet V0 program)\r\n const v0n = V0_SIZES.get(dataLen);\r\n if (v0n !== undefined) return validateLayout(buildLayout(0, v0n), dataLen);\r\n\r\n // Check V1D sizes (actually deployed V1 program — ENGINE_OFF=424, correct struct layout).\r\n // V2 slabs produce identical sizes (postBitmap=18 for V2 == postBitmap=2 for V1D).\r\n // When data is available, peek at the version field to disambiguate.\r\n const v1dn = V1D_SIZES.get(dataLen);\r\n if (v1dn !== undefined) {\r\n if (data && data.length >= 12) {\r\n const version = readU32LE(data, 8);\r\n if (version === 2) return validateLayout(buildLayoutV2(v1dn), dataLen);\r\n }\r\n return validateLayout(buildLayoutV1D(v1dn, 2), dataLen);\r\n }\r\n\r\n // Check V1D legacy sizes (postBitmap=18 on-chain slabs created before GH#1234 fix).\r\n // e.g. slab 6ZytbpV4 (TEST/USD, top active market) = 65104 bytes, uses postBitmap=18.\r\n // PR #1236 broke these by only registering the postBitmap=2 size; GH#1237 restores support.\r\n const v1dln = V1D_SIZES_LEGACY.get(dataLen);\r\n if (v1dln !== undefined) return validateLayout(buildLayoutV1D(v1dln, 18), dataLen);\r\n\r\n // Check V1 sizes (future V1 program — ENGINE_OFF=600, PERC-1094 corrected)\r\n const v1n = V1_SIZES.get(dataLen);\r\n if (v1n !== undefined) return validateLayout(buildLayout(1, v1n), dataLen);\r\n\r\n // Check legacy V1 sizes (pre-PERC-1094 SDK used ENGINE_OFF=640; orphaned on devnet)\r\n const v1ln = V1_SIZES_LEGACY.get(dataLen);\r\n // PERC-1095 follow-up: must pass V1_ENGINE_OFF_LEGACY (640) so the returned SlabLayout\r\n // has .engineOff=640 — without the override buildLayout would use V1_ENGINE_OFF=600,\r\n // causing all engine reads on legacy slabs to land at the wrong byte offset.\r\n if (v1ln !== undefined) return validateLayout(buildLayout(1, v1ln, V1_ENGINE_OFF_LEGACY), dataLen);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Legacy detectLayout for backward compat.\r\n * Returns { bitmapWords, accountsOff, maxAccounts } or null.\r\n *\r\n * GH#1238: previously recomputed accountsOff with hardcoded postBitmap=18, which gave a value\r\n * 16 bytes too large for V1D slabs (which use postBitmap=2). Now delegates directly to the\r\n * SlabLayout descriptor so each variant uses its own correct accountsOff.\r\n */\r\nexport function detectLayout(dataLen: number) {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return null;\r\n return { bitmapWords: layout.bitmapWords, accountsOff: layout.accountsOff, maxAccounts: layout.maxAccounts };\r\n}\r\n\r\n// =============================================================================\r\n// RiskParams Layout (field offsets within params, same for V0 and V1 basic fields)\r\n// =============================================================================\r\nconst PARAMS_WARMUP_PERIOD_OFF = 0;\r\nconst PARAMS_MAINTENANCE_MARGIN_OFF = 8;\r\nconst PARAMS_INITIAL_MARGIN_OFF = 16;\r\nconst PARAMS_TRADING_FEE_OFF = 24;\r\nconst PARAMS_MAX_ACCOUNTS_OFF = 32;\r\nconst PARAMS_NEW_ACCOUNT_FEE_OFF = 40;\r\n// V1-only extended params (offset 56+) — legacy offsets (V0/V1/V1D layouts with\r\n// riskReductionThreshold and liquidationBufferBps fields).\r\nconst PARAMS_RISK_THRESHOLD_OFF = 56;\r\nconst PARAMS_MAINTENANCE_FEE_OFF = 72;\r\nconst PARAMS_MAX_CRANK_STALENESS_OFF = 88;\r\nconst PARAMS_LIQUIDATION_FEE_BPS_OFF = 96;\r\nconst PARAMS_LIQUIDATION_FEE_CAP_OFF = 104;\r\nconst PARAMS_LIQUIDATION_BUFFER_OFF = 120;\r\nconst PARAMS_MIN_LIQUIDATION_OFF = 128;\r\n\r\n// V12_1 SBF params offsets — deployed struct has NO riskReductionThreshold or\r\n// liquidationBufferBps. Instead: maintenance_fee_per_slot follows new_account_fee\r\n// directly, and min_initial_deposit/min_nonzero_mm_req/min_nonzero_im_req/insurance_floor\r\n// are appended at the end. Verified via cargo build-sbf offset_of! assertions.\r\nconst V12_1_PARAMS_MAINT_FEE_OFF = 56; // U128\r\nconst V12_1_PARAMS_MAX_CRANK_OFF = 72; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_BPS_OFF = 80; // u64\r\nconst V12_1_PARAMS_LIQ_FEE_CAP_OFF = 88; // U128\r\nconst V12_1_PARAMS_MIN_LIQ_OFF = 104; // U128\r\nconst V12_1_PARAMS_MIN_INITIAL_DEP_OFF = 120; // U128\r\nconst V12_1_PARAMS_MIN_NZ_MM_OFF = 136; // u128\r\nconst V12_1_PARAMS_MIN_NZ_IM_OFF = 152; // u128\r\nconst V12_1_PARAMS_INS_FLOOR_OFF = 168; // U128\r\n\r\n// V12_19 SBF engine RiskParams offsets. The wrapper still accepts a wider\r\n// InitMarket wire payload for policy fields such as new_account_fee and\r\n// insurance_floor, but those fields are not stored inside engine RiskParams.\r\nconst V12_19_PARAMS_MAINTENANCE_MARGIN_OFF = 0;\r\nconst V12_19_PARAMS_INITIAL_MARGIN_OFF = 8;\r\nconst V12_19_PARAMS_TRADING_FEE_OFF = 16;\r\nconst V12_19_PARAMS_MAX_ACCOUNTS_OFF = 24;\r\nconst V12_19_PARAMS_LIQ_FEE_BPS_OFF = 32;\r\nconst V12_19_PARAMS_LIQ_FEE_CAP_OFF = 40;\r\nconst V12_19_PARAMS_MIN_LIQ_OFF = 56;\r\nconst V12_19_PARAMS_MIN_NZ_MM_OFF = 72;\r\nconst V12_19_PARAMS_MIN_NZ_IM_OFF = 88;\r\nconst V12_19_PARAMS_H_MIN_OFF = 104;\r\nconst V12_19_PARAMS_H_MAX_OFF = 112;\r\nconst V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF = 120;\r\nconst V12_19_PARAMS_MAX_ACCRUAL_DT_OFF = 128;\r\n\r\n// =============================================================================\r\n// Account Layout (240/248 bytes)\r\n// The first 240 bytes are identical in V0 and V1.\r\n// V1 adds last_partial_liquidation_slot (u64, 8 bytes) at offset 240.\r\n// =============================================================================\r\nconst ACCT_ACCOUNT_ID_OFF = 0;\r\nconst ACCT_CAPITAL_OFF = 8;\r\nconst ACCT_KIND_OFF = 24;\r\nconst ACCT_PNL_OFF = 32;\r\nconst ACCT_RESERVED_PNL_OFF = 48;\r\nconst ACCT_WARMUP_STARTED_OFF = 56;\r\nconst ACCT_WARMUP_SLOPE_OFF = 64;\r\nconst ACCT_POSITION_SIZE_OFF = 80;\r\nconst ACCT_ENTRY_PRICE_OFF = 96;\r\nconst ACCT_FUNDING_INDEX_OFF = 104;\r\nconst ACCT_MATCHER_PROGRAM_OFF = 120;\r\nconst ACCT_MATCHER_CONTEXT_OFF = 152;\r\nconst ACCT_OWNER_OFF = 184;\r\nconst ACCT_FEE_CREDITS_OFF = 216;\r\nconst ACCT_LAST_FEE_SLOT_OFF = 232;\r\n\r\n// =============================================================================\r\n// Interfaces\r\n// =============================================================================\r\n\r\nexport interface SlabHeader {\r\n magic: bigint;\r\n version: number;\r\n bump: number;\r\n flags: number;\r\n resolved: boolean;\r\n paused: boolean;\r\n admin: PublicKey;\r\n nonce: bigint;\r\n lastThrUpdateSlot: bigint;\r\n}\r\n\r\nexport interface MarketConfig {\r\n collateralMint: PublicKey;\r\n vaultPubkey: PublicKey;\r\n indexFeedId: PublicKey;\r\n maxStalenessSlots: bigint;\r\n confFilterBps: number;\r\n vaultAuthorityBump: number;\r\n invert: number;\r\n unitScale: number;\r\n fundingHorizonSlots: bigint;\r\n fundingKBps: bigint;\r\n fundingInvScaleNotionalE6: bigint;\r\n fundingMaxPremiumBps: bigint;\r\n fundingMaxBpsPerSlot: bigint;\r\n threshFloor: bigint;\r\n threshRiskBps: bigint;\r\n threshUpdateIntervalSlots: bigint;\r\n threshStepBps: bigint;\r\n threshAlphaBps: bigint;\r\n threshMin: bigint;\r\n threshMax: bigint;\r\n threshMinStep: bigint;\r\n oracleAuthority: PublicKey;\r\n authorityPriceE6: bigint;\r\n authorityTimestamp: bigint;\r\n oraclePriceCapE2bps: bigint;\r\n lastEffectivePriceE6: bigint;\r\n oiCapMultiplierBps: bigint;\r\n maxPnlCap: bigint;\r\n adaptiveFundingEnabled: boolean;\r\n adaptiveScaleBps: number;\r\n adaptiveMaxFundingBps: bigint;\r\n marketCreatedSlot: bigint;\r\n oiRampSlots: bigint;\r\n /**\r\n * @stub Always 0n — not yet read from the on-chain MarketConfig struct.\r\n * Do not use for market-resolution logic until a parser is wired.\r\n */\r\n resolvedSlot: bigint;\r\n insuranceIsolationBps: number;\r\n /** PERC-622: Oracle phase (0=Nascent, 1=Growing, 2=Mature) */\r\n oraclePhase: number;\r\n /** PERC-622: Cumulative trade volume in e6 format */\r\n cumulativeVolumeE6: bigint;\r\n /** PERC-622: Slots elapsed from market creation to Phase 2 entry (u24) */\r\n phase2DeltaSlots: number;\r\n /**\r\n * PERC-SetDexPool: Admin-pinned DEX pool pubkey for HYPERP markets.\r\n * Null when reading old slabs (pre-SetDexPool configLen < 528) or when\r\n * SetDexPool has never been called (all-zero pubkey).\r\n * Non-null means the program will reject any UpdateHyperpMark that passes\r\n * a different pool account.\r\n */\r\n dexPool: PublicKey | null;\r\n}\r\n\r\nexport interface InsuranceFund {\r\n balance: bigint;\r\n feeRevenue: bigint;\r\n isolatedBalance: bigint;\r\n isolationBps: number;\r\n}\r\n\r\nexport interface RiskParams {\r\n /**\r\n * @deprecated Split into hMin/hMax in v12.15 RiskParams. On V12_15 slabs this field returns\r\n * hMin for backwards compatibility. On pre-v12.15 slabs hMin/hMax both mirror this value.\r\n */\r\n warmupPeriodSlots: bigint;\r\n maintenanceMarginBps: bigint;\r\n initialMarginBps: bigint;\r\n tradingFeeBps: bigint;\r\n maxAccounts: bigint;\r\n newAccountFee: bigint;\r\n riskReductionThreshold: bigint;\r\n maintenanceFeePerSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n liquidationFeeBps: bigint;\r\n liquidationFeeCap: bigint;\r\n liquidationBufferBps: bigint;\r\n minLiquidationAbs: bigint;\r\n /** Minimum initial deposit to open an account (V12_1+ only) */\r\n minInitialDeposit: bigint;\r\n /** Minimum nonzero maintenance margin requirement (V12_1+ only) */\r\n minNonzeroMmReq: bigint;\r\n /** Minimum nonzero initial margin requirement (V12_1+ only) */\r\n minNonzeroImReq: bigint;\r\n /** Insurance fund floor (V12_1+ only) */\r\n insuranceFloor: bigint;\r\n /** Minimum horizon slots (v12.15+). Replaces warmupPeriodSlots. 0n on pre-v12.15 slabs. */\r\n hMin: bigint;\r\n /** Maximum horizon slots (v12.15+). 0n on pre-v12.15 slabs. */\r\n hMax: bigint;\r\n}\r\n\r\nexport interface EngineState {\r\n vault: bigint;\r\n insuranceFund: InsuranceFund;\r\n currentSlot: bigint;\r\n fundingIndexQpbE6: bigint;\r\n lastFundingSlot: bigint;\r\n /**\r\n * Funding rate per slot. On pre-v12.15 slabs: i64 in BPS units.\r\n * On v12.15+ slabs: i128 in e9 units (field renamed `funding_rate_e9` on-chain).\r\n */\r\n fundingRateBpsPerSlotLast: bigint;\r\n /**\r\n * Funding rate in e9 units (i128). v12.15+ only.\r\n * 0n on pre-v12.15 slabs.\r\n */\r\n fundingRateE9: bigint;\r\n /**\r\n * Market mode. v12.15+ only. 0 = Live, 1 = Resolved. null on pre-v12.15 slabs.\r\n */\r\n marketMode: 0 | 1 | null;\r\n lastCrankSlot: bigint;\r\n maxCrankStalenessSlots: bigint;\r\n totalOpenInterest: bigint;\r\n longOi: bigint;\r\n shortOi: bigint;\r\n cTot: bigint;\r\n pnlPosTot: bigint;\r\n /**\r\n * Matured (settled) positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs.\r\n */\r\n pnlMaturedPosTot: bigint;\r\n liqCursor: number;\r\n gcCursor: number;\r\n lastSweepStartSlot: bigint;\r\n lastSweepCompleteSlot: bigint;\r\n crankCursor: number;\r\n sweepStartIdx: number;\r\n lifetimeLiquidations: bigint;\r\n lifetimeForceCloses: bigint;\r\n netLpPos: bigint;\r\n lpSumAbs: bigint;\r\n lpMaxAbs: bigint;\r\n lpMaxAbsSweep: bigint;\r\n emergencyOiMode: boolean;\r\n emergencyStartSlot: bigint;\r\n lastBreakerSlot: bigint;\r\n numUsedAccounts: number;\r\n nextAccountId: bigint;\r\n markPriceE6: bigint;\r\n /** last_oracle_price (u64, e6). V12_15+ only. 0n on pre-v12.15. */\r\n oraclePriceE6: bigint;\r\n\r\n // ---- V12_17 engine fields ----\r\n /** Cumulative funding numerator for long side (i128). 0n on pre-v12.17. */\r\n fLongNum: bigint;\r\n /** Cumulative funding numerator for short side (i128). 0n on pre-v12.17. */\r\n fShortNum: bigint;\r\n /** Count of accounts with negative PnL. 0n on pre-v12.17. */\r\n negPnlAccountCount: bigint;\r\n /** Last funding-sample price (u64 e6). 0n on pre-v12.17. */\r\n fundPxLast: bigint;\r\n /** Matured positive PnL total (u128). v12.15+ only. 0n on pre-v12.15 slabs. */\r\n resolvedKLongTerminalDelta: bigint;\r\n /** Terminal K delta for short side (i128). 0n on pre-v12.17. */\r\n resolvedKShortTerminalDelta: bigint;\r\n /** Live oracle price used during resolution (u64 e6). 0n on pre-v12.17. */\r\n resolvedLivePrice: bigint;\r\n}\r\n\r\nexport enum AccountKind {\r\n User = 0,\r\n LP = 1,\r\n}\r\n\r\n/** Parsed reserve cohort (64 bytes on-chain). Raw bytes; structure is program-internal. */\r\nexport type ReserveCohortBytes = Uint8Array;\r\n\r\nexport interface Account {\r\n kind: AccountKind;\r\n accountId: bigint;\r\n capital: bigint;\r\n pnl: bigint;\r\n reservedPnl: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupStartedAtSlot: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n warmupSlopePerStep: bigint;\r\n positionSize: bigint;\r\n /** Entry price in e6 units. Present in V12_15 (offset 120) and V_ADL/V12_1_EP. -1 signals absent. */\r\n entryPrice: bigint;\r\n fundingIndex: bigint;\r\n matcherProgram: PublicKey;\r\n matcherContext: PublicKey;\r\n owner: PublicKey;\r\n feeCredits: bigint;\r\n /** @deprecated Removed in v12.15. Always 0n on V12_15 slabs. */\r\n lastFeeSlot: bigint;\r\n /** Total fees earned over account lifetime (u128). Present from v12.15. 0n on older layouts. */\r\n feesEarnedTotal: bigint;\r\n /**\r\n * Reserve cohorts array (v12.15+). Up to 62 cohorts of 64 bytes each.\r\n * `null` on pre-v12.15 slabs. Parse the raw bytes according to the on-chain ReserveCohort struct.\r\n */\r\n exactReserveCohorts: ReserveCohortBytes[] | null;\r\n /** Number of active reserve cohorts (0-62). null on pre-v12.15 slabs. */\r\n exactCohortCount: number | null;\r\n /** Overflow (oldest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowOlder: ReserveCohortBytes | null;\r\n /** True if overflowOlder contains valid data. null on pre-v12.15 slabs. */\r\n overflowOlderPresent: boolean | null;\r\n /** Overflow (newest) cohort raw bytes. null on pre-v12.15 slabs or when not present. */\r\n overflowNewest: ReserveCohortBytes | null;\r\n /** True if overflowNewest contains valid data. null on pre-v12.15 slabs. */\r\n overflowNewestPresent: boolean | null;\r\n\r\n // ---- V12_17 fields (two-bucket warmup, per-side funding) ----\r\n /** Per-account cumulative funding snapshot (i128). 0n on pre-v12.17 slabs. */\r\n fSnap: bigint;\r\n /** ADL A-basis snapshot (u128). 0n on pre-v12.17 slabs. */\r\n adlABasis: bigint;\r\n /** ADL K-coefficient snapshot (i128). 0n on pre-v12.17 slabs. */\r\n adlKSnap: bigint;\r\n /** ADL epoch snapshot (u64). 0n on pre-v12.17 slabs. */\r\n adlEpochSnap: bigint;\r\n\r\n // Scheduled reserve bucket (older, matures linearly)\r\n /** True if the scheduled warmup bucket is active. null on pre-v12.17. */\r\n schedPresent: boolean | null;\r\n /** Remaining unreleased quantity in scheduled bucket. null on pre-v12.17. */\r\n schedRemainingQ: bigint | null;\r\n /** Anchor quantity for scheduled bucket. null on pre-v12.17. */\r\n schedAnchorQ: bigint | null;\r\n /** Start slot for scheduled bucket. null on pre-v12.17. */\r\n schedStartSlot: bigint | null;\r\n /** Warmup horizon for scheduled bucket. null on pre-v12.17. */\r\n schedHorizon: bigint | null;\r\n /** Release quantity for scheduled bucket. null on pre-v12.17. */\r\n schedReleaseQ: bigint | null;\r\n\r\n // Pending reserve bucket (newest, does not mature while pending)\r\n /** True if the pending warmup bucket is active. null on pre-v12.17. */\r\n pendingPresent: boolean | null;\r\n /** Remaining unreleased quantity in pending bucket. null on pre-v12.17. */\r\n pendingRemainingQ: bigint | null;\r\n /** Warmup horizon for pending bucket. null on pre-v12.17. */\r\n pendingHorizon: bigint | null;\r\n /** Creation slot for pending bucket. null on pre-v12.17. */\r\n pendingCreatedSlot: bigint | null;\r\n}\r\n\r\n// =============================================================================\r\n// Fetch\r\n// =============================================================================\r\n\r\nexport async function fetchSlab(\r\n connection: Connection,\r\n slabPubkey: PublicKey,\r\n expectedOwner?: PublicKey\r\n): Promise {\r\n const info = await connection.getAccountInfo(slabPubkey);\r\n if (!info) {\r\n throw new Error(`Slab account not found: ${slabPubkey.toBase58()}`);\r\n }\r\n if (expectedOwner && !info.owner.equals(expectedOwner)) {\r\n throw new Error(\r\n `fetchSlab: account ${slabPubkey.toBase58()} is owned by ${info.owner.toBase58()} but expected ${expectedOwner.toBase58()}`\r\n );\r\n }\r\n return new Uint8Array(info.data);\r\n}\r\n\r\n// =============================================================================\r\n// PERC-302: Market Maturity OI Ramp\r\n// =============================================================================\r\n\r\nexport const RAMP_START_BPS = 1000n;\r\nexport const DEFAULT_OI_RAMP_SLOTS = 432_000n;\r\n\r\nexport function computeEffectiveOiCapBps(config: MarketConfig, currentSlot: bigint): bigint {\r\n const target = config.oiCapMultiplierBps;\r\n if (target === 0n) return 0n;\r\n if (config.oiRampSlots === 0n) return target;\r\n if (target <= RAMP_START_BPS) return target;\r\n const elapsed = currentSlot > config.marketCreatedSlot\r\n ? currentSlot - config.marketCreatedSlot\r\n : 0n;\r\n if (elapsed >= config.oiRampSlots) return target;\r\n const range = target - RAMP_START_BPS;\r\n const rampAdd = (range * elapsed) / config.oiRampSlots;\r\n const result = RAMP_START_BPS + rampAdd;\r\n return result < target ? result : target;\r\n}\r\n\r\n// =============================================================================\r\n// Header helpers\r\n// =============================================================================\r\n\r\nexport function readNonce(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readNonce: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 8) throw new Error(\"Slab data too short for nonce\");\r\n return readU64LE(data, roff);\r\n}\r\n\r\nexport function readLastThrUpdateSlot(data: Uint8Array): bigint {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`readLastThrUpdateSlot: unrecognized slab data length ${data.length}`);\r\n }\r\n const roff = layout.reservedOff;\r\n if (data.length < roff + 16) throw new Error(\"Slab data too short for lastThrUpdateSlot\");\r\n return readU64LE(data, roff + 8);\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Parse slab header (first 72 bytes — layout-independent).\r\n */\r\nexport function parseHeader(data: Uint8Array): SlabHeader {\r\n if (data.length < V0_HEADER_LEN) {\r\n throw new Error(`Slab data too short for header: ${data.length} < ${V0_HEADER_LEN}`);\r\n }\r\n\r\n const magic = readU64LE(data, 0);\r\n if (magic !== MAGIC) {\r\n throw new Error(`Invalid slab magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);\r\n }\r\n\r\n const version = readU32LE(data, 8);\r\n const bump = readU8(data, 12);\r\n const flags = readU8(data, 13);\r\n const admin = new PublicKey(data.subarray(16, 48));\r\n\r\n // Reserved field location depends on layout\r\n const layout = detectSlabLayout(data.length, data);\r\n const roff = layout ? layout.reservedOff : V0_RESERVED_OFF;\r\n const nonce = readU64LE(data, roff);\r\n const lastThrUpdateSlot = readU64LE(data, roff + 8);\r\n\r\n return {\r\n magic,\r\n version,\r\n bump,\r\n flags,\r\n resolved: (flags & FLAG_RESOLVED) !== 0,\r\n paused: (flags & 0x02) !== 0,\r\n admin,\r\n nonce,\r\n lastThrUpdateSlot,\r\n };\r\n}\r\n\r\n/**\r\n * Parse market config. Layout-version aware.\r\n * For V0 slabs, fields beyond the basic config are read if present in the data,\r\n * otherwise defaults are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice for discovery; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\n/**\r\n * V12_17 MarketConfig parser. Struct definition: percolator-prog/src/percolator.rs:2194.\r\n * SBF layout (u128 align=8, total size 512 bytes):\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_bps_per_slot i64\r\n * 144 oracle_authority [32]\r\n * 176 authority_price_e6 u64\r\n * 184 authority_timestamp i64\r\n * 192 oracle_price_cap_e2bps u64\r\n * 200 last_effective_price_e6 u64\r\n * 208 max_insurance_floor u128\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 insurance_withdraw_max_bps u16 (+ 6 pad)\r\n * 240 insurance_withdraw_cooldown_slots u64\r\n * 248 _iw_padding2 [u64;2]\r\n * 264 last_hyperp_index_slot u64\r\n * 272 last_mark_push_slot u128\r\n * 288 last_insurance_withdraw_slot u64 (+ 8 pad)\r\n * 304 mark_ewma_e6 u64\r\n * 312 mark_ewma_last_slot u64\r\n * 320 mark_ewma_halflife_slots u64 (+ 8 pad)\r\n * 336 permissionless_resolve_stale_slots u64\r\n * 344 last_good_oracle_slot u64\r\n * 352 maintenance_fee_per_slot u128\r\n * 368 last_fee_charge_slot u64 (+ 8 pad)\r\n * 384 mark_min_fee u64\r\n * 392 force_close_delay_slots u64\r\n * 400 dex_pool [32]\r\n * 432 max_pnl_cap u64\r\n * 440 last_audit_pause_slot u64\r\n * 448 oi_cap_multiplier_bps u64\r\n * 456 dispute_window_slots u64\r\n * 464 dispute_bond_amount u64\r\n * 472 lp_collateral_enabled u8\r\n * 473 _pad u8\r\n * 474 lp_collateral_ltv_bps u16 (+ 4 pad)\r\n * 480 pending_admin [32]\r\n * 512 end\r\n */\r\nfunction parseConfigV12_17(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_17_BYTES = 512;\r\n if (data.length < configOff + MIN_V12_17_BYTES) {\r\n throw new Error(`Slab data too short for V12_17 config: ${data.length} < ${configOff + MIN_V12_17_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 192);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 200);\r\n // max_insurance_floor, min_oracle_price_cap, mark_ewma, dispute, etc. — not\r\n // currently surfaced by the MarketConfig type; read them when/if callers\r\n // need them. Only dex_pool is consumed downstream.\r\n\r\n const dexPoolBytes = data.subarray(b + 400, b + 432);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n, // removed in v12.17\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n, // removed in v12.17\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 448),\r\n maxPnlCap: readU64LE(data, b + 432),\r\n adaptiveFundingEnabled: false, // removed in v12.17\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * V12_19 MarketConfig parser. SBF layout (480 bytes total, u128 align=8).\r\n * Probe-confirmed against /Users/khubair/percolator-prog (cargo build-sbf\r\n * --features small) on 2026-04-28.\r\n *\r\n * 0 collateral_mint [32]\r\n * 32 vault_pubkey [32]\r\n * 64 index_feed_id [32]\r\n * 96 max_staleness_secs u64\r\n * 104 conf_filter_bps u16\r\n * 106 vault_authority_bump u8\r\n * 107 invert u8\r\n * 108 unit_scale u32\r\n * 112 funding_horizon_slots u64\r\n * 120 funding_k_bps u64\r\n * 128 funding_max_premium_bps i64\r\n * 136 funding_max_e9_per_slot i64\r\n * 144 hyperp_authority [32] ← was oracle_authority in v12.17, renamed\r\n * 176 hyperp_mark_e6 u64 ← v12.19 only\r\n * 184 last_oracle_publish_time i64\r\n * 192 last_effective_price_e6 u64 ← shifted from v12.17 (was at 200)\r\n * 200 insurance_withdraw_max_bps u16\r\n * 202 tvl_insurance_cap_mult u16 ← v12.19 only\r\n * 204 _iw_padding [u8;4]\r\n * 208 insurance_withdraw_cooldown_slots u64\r\n * 216 oracle_price_cap_e2bps u64 ← shifted from v12.17 (was at 192)\r\n * 224 min_oracle_price_cap_e2bps u64\r\n * 232 last_hyperp_index_slot u64\r\n * 240 last_mark_push_slot u128\r\n * 256 last_insurance_withdraw_slot u64\r\n * 264 _pad u64\r\n * 272 mark_ewma_e6 u64\r\n * 280 mark_ewma_last_slot u64\r\n * 288 mark_ewma_halflife_slots u64\r\n * 296 init_restart_slot u64\r\n * 304 permissionless_resolve_stale_slots u64\r\n * 312 last_good_oracle_slot u64\r\n * 320 maintenance_fee_per_slot u128\r\n * 336 fee_sweep_cursor_word u64\r\n * 344 fee_sweep_cursor_bit u64\r\n * 352 mark_min_fee u64\r\n * 360 force_close_delay_slots u64\r\n * 368 dex_pool [32] ← shifted from v12.17 (was at 400)\r\n * 400 max_pnl_cap u64 ← shifted from v12.17 (was at 432)\r\n * 408 last_audit_pause_slot u64\r\n * 416 oi_cap_multiplier_bps u64\r\n * 424 dispute_window_slots u64\r\n * 432 dispute_bond_amount u64\r\n * 440 lp_collateral_enabled u8\r\n * 441 _pad u8\r\n * 442 lp_collateral_ltv_bps u16\r\n * 444 _pad [u8;4]\r\n * 448 pending_admin [32]\r\n * 480 end\r\n */\r\nfunction parseConfigV12_19(data: Uint8Array, configOff: number): MarketConfig {\r\n const MIN_V12_19_BYTES = 480;\r\n if (data.length < configOff + MIN_V12_19_BYTES) {\r\n throw new Error(`Slab data too short for V12_19 config: ${data.length} < ${configOff + MIN_V12_19_BYTES}`);\r\n }\r\n\r\n const b = configOff;\r\n const collateralMint = new PublicKey(data.subarray(b + 0, b + 32));\r\n const vaultPubkey = new PublicKey(data.subarray(b + 32, b + 64));\r\n const indexFeedId = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maxStalenessSlots = readU64LE(data, b + 96);\r\n const confFilterBps = readU16LE(data, b + 104);\r\n const vaultAuthorityBump = readU8(data, b + 106);\r\n const invert = readU8(data, b + 107);\r\n const unitScale = readU32LE(data, b + 108);\r\n const fundingHorizonSlots = readU64LE(data, b + 112);\r\n const fundingKBps = readU64LE(data, b + 120);\r\n const fundingMaxPremiumBps = readI64LE(data, b + 128);\r\n const fundingMaxBpsPerSlot = readI64LE(data, b + 136);\r\n const oracleAuthority = new PublicKey(data.subarray(b + 144, b + 176));\r\n const authorityPriceE6 = readU64LE(data, b + 176);\r\n const authorityTimestamp = readI64LE(data, b + 184);\r\n const lastEffectivePriceE6 = readU64LE(data, b + 192);\r\n const oraclePriceCapE2bps = readU64LE(data, b + 216);\r\n\r\n const dexPoolBytes = data.subarray(b + 368, b + 400);\r\n const dexPool = dexPoolBytes.some(x => x !== 0) ? new PublicKey(dexPoolBytes) : null;\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6: 0n,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor: 0n,\r\n threshRiskBps: 0n,\r\n threshUpdateIntervalSlots: 0n,\r\n threshStepBps: 0n,\r\n threshAlphaBps: 0n,\r\n threshMin: 0n,\r\n threshMax: 0n,\r\n threshMinStep: 0n,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps: readU64LE(data, b + 416),\r\n maxPnlCap: readU64LE(data, b + 400),\r\n adaptiveFundingEnabled: false,\r\n adaptiveScaleBps: 0,\r\n adaptiveMaxFundingBps: 0n,\r\n marketCreatedSlot: 0n,\r\n oiRampSlots: 0n,\r\n resolvedSlot: 0n,\r\n insuranceIsolationBps: 0,\r\n oraclePhase: 0,\r\n cumulativeVolumeE6: 0n,\r\n phase2DeltaSlots: 0,\r\n dexPool,\r\n };\r\n}\r\n\r\nexport function parseConfig(data: Uint8Array, layoutHint?: SlabLayout | null): MarketConfig {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseConfig: invalid slab magic');\r\n }\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const configOff = layout ? layout.configOffset : V0_HEADER_LEN;\r\n const configLen = layout ? layout.configLen : V0_CONFIG_LEN;\r\n\r\n // V12_19 MarketConfig (480 bytes, hyperp/dex_pool reordered vs v12.17).\r\n // Detect by accountSize=360 (probe-confirmed v12.19 SBF Account size).\r\n const isV12_19 = layout && layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_19) {\r\n return parseConfigV12_19(data, configOff);\r\n }\r\n\r\n // V12_17 MarketConfig has a completely different layout — no funding_inv_scale,\r\n // no thresh_* fields. Parse it via its own field-ordered reader. The legacy\r\n // sequential code below covers pre-v12.17 layouts.\r\n const isV12_17 = layout && (layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF);\r\n if (isV12_17) {\r\n return parseConfigV12_17(data, configOff);\r\n }\r\n\r\n // Mandatory config fields (collateralMint..maxPnlCap) consume 376 bytes.\r\n // V1 extended fields are optional and guarded by their own `remaining` checks.\r\n const MIN_CONFIG_BYTES = 376;\r\n const minLen = configOff + Math.min(configLen, MIN_CONFIG_BYTES);\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for config: ${data.length} < ${minLen}`);\r\n }\r\n\r\n let off = configOff;\r\n\r\n const collateralMint = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const vaultPubkey = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const indexFeedId = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const maxStalenessSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const confFilterBps = readU16LE(data, off);\r\n off += 2;\r\n\r\n const vaultAuthorityBump = readU8(data, off);\r\n off += 1;\r\n\r\n const invert = readU8(data, off);\r\n off += 1;\r\n\r\n const unitScale = readU32LE(data, off);\r\n off += 4;\r\n\r\n // Funding rate parameters\r\n const fundingHorizonSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingKBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const fundingInvScaleNotionalE6 = readU128LE(data, off);\r\n off += 16;\r\n\r\n const fundingMaxPremiumBps = readI64LE(data, off);\r\n off += 8;\r\n\r\n const fundingMaxBpsPerSlot = readI64LE(data, off);\r\n off += 8;\r\n\r\n // NOTE: Extended funding fields (fundingPremiumWeightBps, fundingSettlementIntervalSlots,\r\n // fundingPremiumDampeningE6, fundingPremiumMaxBpsPerSlot) were removed in V12_1 upstream\r\n // rebase. They do NOT exist in the on-chain MarketConfig struct. Reading them here shifted\r\n // all subsequent fields by 32 bytes, causing oracle_authority to read garbage.\r\n\r\n // Threshold parameters\r\n const threshFloor = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshRiskBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshUpdateIntervalSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshStepBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshAlphaBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const threshMin = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMax = readU128LE(data, off);\r\n off += 16;\r\n\r\n const threshMinStep = readU128LE(data, off);\r\n off += 16;\r\n\r\n // Oracle authority fields\r\n const oracleAuthority = new PublicKey(data.subarray(off, off + 32));\r\n off += 32;\r\n\r\n const authorityPriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n const authorityTimestamp = readI64LE(data, off);\r\n off += 8;\r\n\r\n // Oracle price circuit breaker\r\n const oraclePriceCapE2bps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const lastEffectivePriceE6 = readU64LE(data, off);\r\n off += 8;\r\n\r\n // OI cap\r\n const oiCapMultiplierBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n const maxPnlCap = readU64LE(data, off);\r\n off += 8;\r\n\r\n // Check if we have enough data for V1-only fields\r\n const remaining = configOff + configLen - off;\r\n\r\n let adaptiveFundingEnabled = false;\r\n let adaptiveScaleBps = 0;\r\n let adaptiveMaxFundingBps = 0n;\r\n let marketCreatedSlot = 0n;\r\n let oiRampSlots = 0n;\r\n let resolvedSlot = 0n;\r\n let insuranceIsolationBps = 0;\r\n let oraclePhase = 0;\r\n let cumulativeVolumeE6 = 0n;\r\n let phase2DeltaSlots = 0;\r\n\r\n if (remaining >= 40) {\r\n // V1 extended fields — on-chain order (percolator.rs:3617-3639):\r\n // market_created_slot(u64), oi_ramp_slots(u64),\r\n // adaptive_funding_enabled(u8), _pad(u8), adaptive_scale_bps(u16),\r\n // _pad2(u32), adaptive_max_funding_bps(u64),\r\n // insurance_isolation_bps(u16), _insurance_isolation_padding([u8;14])\r\n marketCreatedSlot = readU64LE(data, off);\r\n off += 8;\r\n\r\n oiRampSlots = readU64LE(data, off);\r\n off += 8;\r\n\r\n adaptiveFundingEnabled = readU8(data, off) !== 0;\r\n off += 1;\r\n off += 1; // _adaptive_pad\r\n adaptiveScaleBps = readU16LE(data, off);\r\n off += 2;\r\n off += 4; // _adaptive_pad2\r\n adaptiveMaxFundingBps = readU64LE(data, off);\r\n off += 8;\r\n\r\n if (remaining >= 42) {\r\n insuranceIsolationBps = readU16LE(data, off);\r\n // PERC-622: Read oracle phase fields from _insurance_isolation_padding\r\n // padding starts at off + 2 (after u16 insuranceIsolationBps)\r\n // [0..2] = mark_oracle_weight (PERC-118), [2] = oracle_phase, [3..11] = cumulative_volume, [11..14] = phase2_delta\r\n if (remaining >= 56) { // 42 + 14 bytes padding\r\n const padOff = off + 2;\r\n oraclePhase = Math.min(readU8(data, padOff + 2), 2);\r\n cumulativeVolumeE6 = readU64LE(data, padOff + 3);\r\n // phase2_delta_slots is u24 LE (3 bytes)\r\n phase2DeltaSlots = data[padOff + 11] | (data[padOff + 12] << 8) | (data[padOff + 13] << 16);\r\n }\r\n }\r\n }\r\n\r\n // PERC-SetDexPool: read dex_pool at BPF offset 496 within config.\r\n // Only present in V_SETDEXPOOL slabs (configLen >= 528).\r\n // All-zero pubkey means SetDexPool was never called.\r\n let dexPool: PublicKey | null = null;\r\n const DEX_POOL_REL_OFF = 512; // SBF offset of dex_pool within MarketConfig (CONFIG_LEN=544, dex_pool at end = 544-32=512)\r\n if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {\r\n const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);\r\n // Return null if all-zero (SetDexPool never called)\r\n if (dexPoolBytes.some(b => b !== 0)) {\r\n dexPool = new PublicKey(dexPoolBytes);\r\n }\r\n }\r\n\r\n return {\r\n collateralMint,\r\n vaultPubkey,\r\n indexFeedId,\r\n maxStalenessSlots,\r\n confFilterBps,\r\n vaultAuthorityBump,\r\n invert,\r\n unitScale,\r\n fundingHorizonSlots,\r\n fundingKBps,\r\n fundingInvScaleNotionalE6,\r\n fundingMaxPremiumBps,\r\n fundingMaxBpsPerSlot,\r\n threshFloor,\r\n threshRiskBps,\r\n threshUpdateIntervalSlots,\r\n threshStepBps,\r\n threshAlphaBps,\r\n threshMin,\r\n threshMax,\r\n threshMinStep,\r\n oracleAuthority,\r\n authorityPriceE6,\r\n authorityTimestamp,\r\n oraclePriceCapE2bps,\r\n lastEffectivePriceE6,\r\n oiCapMultiplierBps,\r\n maxPnlCap,\r\n adaptiveFundingEnabled,\r\n adaptiveScaleBps,\r\n adaptiveMaxFundingBps,\r\n marketCreatedSlot,\r\n oiRampSlots,\r\n resolvedSlot,\r\n insuranceIsolationBps,\r\n oraclePhase,\r\n cumulativeVolumeE6,\r\n phase2DeltaSlots,\r\n dexPool,\r\n };\r\n}\r\n\r\n/**\r\n * Parse RiskParams from engine data. Layout-version aware.\r\n * For V0 slabs, extended params (risk_threshold, maintenance_fee, etc.) are\r\n * not present on-chain, so defaults (0) are returned.\r\n *\r\n * @param data - Slab data (may be a partial slice; pass layoutHint in that case)\r\n * @param layoutHint - Pre-detected layout to use; if omitted, detected from data.length.\r\n */\r\nexport function parseParams(data: Uint8Array, layoutHint?: SlabLayout | null): RiskParams {\r\n const layout = layoutHint !== undefined ? layoutHint : detectSlabLayout(data.length, data);\r\n const engineOff = layout ? layout.engineOff : V0_ENGINE_OFF;\r\n const paramsOff = layout ? layout.engineParamsOff : V0_ENGINE_PARAMS_OFF;\r\n const paramsSize = layout ? layout.paramsSize : V0_PARAMS_SIZE;\r\n const base = engineOff + paramsOff;\r\n\r\n // Validate we have enough data for the fields we'll actually read.\r\n // V0 basic params need 56 bytes; V1 extended params need 144 bytes.\r\n const MIN_PARAMS_BYTES = paramsSize >= 144 ? 144 : 56;\r\n if (data.length < base + MIN_PARAMS_BYTES) {\r\n throw new Error(`Slab data too short for RiskParams: ${data.length} < ${base + MIN_PARAMS_BYTES}`);\r\n }\r\n\r\n // Detect V12_15 layout: paramsSize=192. In v12.15, warmup_period_slots is replaced by\r\n // h_min(u64@160) + h_max(u64@168). max_accounts moved to offset 24 (from 32).\r\n const isV12_15Params = paramsSize === V12_15_PARAMS_SIZE || paramsSize === 184; // 192=native, 184=SBF\r\n const isV12_19Params = layout !== null && layout !== undefined &&\r\n layout.engineOff === V12_19_ENGINE_OFF_SBF &&\r\n paramsSize === V12_19_SBF_ENGINE_PARAMS_SIZE;\r\n\r\n // Detect V12_1 SBF layout — deployed struct has different field order from legacy layouts.\r\n // V12_1 SBF: no riskReductionThreshold/liquidationBufferBps; adds minInitialDeposit/\r\n // minNonzeroMmReq/minNonzeroImReq/insuranceFloor at the end.\r\n const isV12_1Sbf = !isV12_15Params && layout !== null && layout !== undefined &&\r\n (layout.engineOff === V12_1_SBF_ENGINE_OFF) && paramsSize === 184;\r\n\r\n // Basic params present in all layouts (offsets 0-55 are identical)\r\n const result: RiskParams = {\r\n warmupPeriodSlots: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF) // backwards compat: return hMin\r\n : readU64LE(data, base + PARAMS_WARMUP_PERIOD_OFF),\r\n maintenanceMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAINTENANCE_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 0) // v12.15: mm_bps is first field (offset 0)\r\n : readU64LE(data, base + PARAMS_MAINTENANCE_MARGIN_OFF),\r\n initialMarginBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_INITIAL_MARGIN_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 8)\r\n : readU64LE(data, base + PARAMS_INITIAL_MARGIN_OFF),\r\n tradingFeeBps: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_TRADING_FEE_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + 16)\r\n : readU64LE(data, base + PARAMS_TRADING_FEE_OFF),\r\n maxAccounts: isV12_19Params\r\n ? readU64LE(data, base + V12_19_PARAMS_MAX_ACCOUNTS_OFF)\r\n : isV12_15Params\r\n ? readU64LE(data, base + V12_15_PARAMS_MAX_ACCOUNTS_OFF) // offset 24 in v12.15\r\n : readU64LE(data, base + PARAMS_MAX_ACCOUNTS_OFF),\r\n newAccountFee: isV12_19Params\r\n ? 1n // v12.19 wrapper hardcodes a one-base-unit anti-spam fee at InitUser/InitLP.\r\n : isV12_15Params\r\n ? readU128LE(data, base + 32) // offset 32 in v12.15\r\n : readU128LE(data, base + PARAMS_NEW_ACCOUNT_FEE_OFF),\r\n // Extended params: defaults; overwritten below if layout supports them\r\n riskReductionThreshold: 0n,\r\n maintenanceFeePerSlot: 0n,\r\n maxCrankStalenessSlots: 0n,\r\n liquidationFeeBps: 0n,\r\n liquidationFeeCap: 0n,\r\n liquidationBufferBps: 0n,\r\n minLiquidationAbs: 0n,\r\n minInitialDeposit: 0n,\r\n minNonzeroMmReq: 0n,\r\n minNonzeroImReq: 0n,\r\n insuranceFloor: 0n,\r\n hMin: 0n,\r\n hMax: 0n,\r\n };\r\n\r\n if (isV12_19Params) {\r\n // V12_19 engine RiskParams no longer stores wrapper policy fields such as\r\n // new_account_fee, min_initial_deposit, insurance_floor, or maintenance fee.\r\n result.hMin = readU64LE(data, base + V12_19_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_19_PARAMS_H_MAX_OFF);\r\n result.riskReductionThreshold = 0n;\r\n result.maintenanceFeePerSlot = 0n;\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_19_PARAMS_MAX_ACCRUAL_DT_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_19_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_19_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + V12_19_PARAMS_RESOLVE_PRICE_DEVIATION_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_19_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = 0n;\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_19_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = 0n;\r\n } else if (isV12_15Params) {\r\n // V12_15 RiskParams: read hMin/hMax, insurance_floor occupies offset 144.\r\n result.hMin = readU64LE(data, base + V12_15_PARAMS_H_MIN_OFF);\r\n result.hMax = readU64LE(data, base + V12_15_PARAMS_H_MAX_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_15_PARAMS_INSURANCE_FLOOR_OFF);\r\n // v12.15 RiskParams: no riskReductionThreshold, no maintenanceFeePerSlot.\r\n // All offsets shift -8 from legacy (warmupPeriodSlots removed from start).\r\n result.riskReductionThreshold = 0n; // removed in v12.15\r\n result.maintenanceFeePerSlot = 0n; // removed in v12.15\r\n // v12.15 RiskParams offsets (same on native and SBF — no i128 fields in RiskParams)\r\n result.maxCrankStalenessSlots = readU64LE(data, base + 48);\r\n result.liquidationFeeBps = readU64LE(data, base + 56);\r\n result.liquidationFeeCap = readU128LE(data, base + 64);\r\n result.liquidationBufferBps = 0n; // removed (wire slot reused as resolve_price_deviation_bps)\r\n result.minLiquidationAbs = readU128LE(data, base + 80);\r\n result.minInitialDeposit = readU128LE(data, base + 96);\r\n result.minNonzeroMmReq = readU128LE(data, base + 112);\r\n result.minNonzeroImReq = readU128LE(data, base + 128);\r\n } else if (isV12_1Sbf) {\r\n // V12_1 SBF deployed struct — no riskReductionThreshold/liquidationBufferBps\r\n result.maintenanceFeePerSlot = readU128LE(data, base + V12_1_PARAMS_MAINT_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + V12_1_PARAMS_MAX_CRANK_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + V12_1_PARAMS_LIQ_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + V12_1_PARAMS_LIQ_FEE_CAP_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + V12_1_PARAMS_MIN_LIQ_OFF);\r\n result.minInitialDeposit = readU128LE(data, base + V12_1_PARAMS_MIN_INITIAL_DEP_OFF);\r\n result.minNonzeroMmReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_MM_OFF);\r\n result.minNonzeroImReq = readU128LE(data, base + V12_1_PARAMS_MIN_NZ_IM_OFF);\r\n result.insuranceFloor = readU128LE(data, base + V12_1_PARAMS_INS_FLOOR_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n } else if (paramsSize >= 144) {\r\n // Legacy V0/V1/V1D layouts with riskReductionThreshold + liquidationBufferBps\r\n result.riskReductionThreshold = readU128LE(data, base + PARAMS_RISK_THRESHOLD_OFF);\r\n result.maintenanceFeePerSlot = readU128LE(data, base + PARAMS_MAINTENANCE_FEE_OFF);\r\n result.maxCrankStalenessSlots = readU64LE(data, base + PARAMS_MAX_CRANK_STALENESS_OFF);\r\n result.liquidationFeeBps = readU64LE(data, base + PARAMS_LIQUIDATION_FEE_BPS_OFF);\r\n result.liquidationFeeCap = readU128LE(data, base + PARAMS_LIQUIDATION_FEE_CAP_OFF);\r\n result.liquidationBufferBps = readU64LE(data, base + PARAMS_LIQUIDATION_BUFFER_OFF);\r\n result.minLiquidationAbs = readU128LE(data, base + PARAMS_MIN_LIQUIDATION_OFF);\r\n // hMin/hMax: backfill from warmupPeriodSlots for pre-v12.15 callers\r\n result.hMin = result.warmupPeriodSlots;\r\n result.hMax = result.warmupPeriodSlots;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse RiskEngine state (excluding accounts array). Layout-version aware.\r\n */\r\nexport function parseEngine(data: Uint8Array): EngineState {\r\n if (data.length >= 8 && readU64LE(data, 0) !== MAGIC) {\r\n throw new Error('parseEngine: invalid slab magic');\r\n }\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n throw new Error(`Unrecognized slab data length: ${data.length}. Cannot determine layout version.`);\r\n }\r\n if (data.length < layout.accountsOff) {\r\n throw new Error(`parseEngine: data too short for accountsOff (${data.length} < ${layout.accountsOff})`);\r\n }\r\n\r\n const base = layout.engineOff;\r\n\r\n // Detect layout versions\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL) && (layout.engineOff === V12_15_ENGINE_OFF || layout.engineOff === V12_15_ENGINE_OFF_SBF);\r\n\r\n // V12_17: completely new engine layout — per-side funding, no stored funding_rate_e9.\r\n // V12_19 SBF: probe-confirmed engineOff=616, ACCOUNT_SIZE=360, internal offsets\r\n // shifted from V12_17 SBF. Detect via accountSize=360 (V12_19) vs 352 (V12_17 SBF).\r\n const isV12_19 = layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n if (isV12_17 || isV12_19) {\r\n const isSbf = layout.engineOff === V12_17_ENGINE_OFF_SBF || isV12_19;\r\n\r\n const currentSlotOff = isV12_19 ? V12_19_SBF_ENGINE_CURRENT_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_CURRENT_SLOT_OFF : V12_17_ENGINE_CURRENT_SLOT_OFF;\r\n const marketModeOff = isV12_19 ? V12_19_SBF_ENGINE_MARKET_MODE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_MARKET_MODE_OFF : V12_17_ENGINE_MARKET_MODE_OFF;\r\n const cTotOff = isV12_19 ? V12_19_SBF_ENGINE_C_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_C_TOT_OFF : V12_17_ENGINE_C_TOT_OFF;\r\n const pnlPosTotOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_POS_TOT_OFF : V12_17_ENGINE_PNL_POS_TOT_OFF;\r\n const pnlMaturedOff = isV12_19 ? V12_19_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_PNL_MATURED_POS_TOT_OFF : V12_17_ENGINE_PNL_MATURED_POS_TOT_OFF;\r\n const negPnlOff = isV12_19 ? V12_19_SBF_ENGINE_NEG_PNL_COUNT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_NEG_PNL_COUNT_OFF : V12_17_ENGINE_NEG_PNL_COUNT_OFF;\r\n const oraclePriceOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_ORACLE_PRICE_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_ORACLE_PRICE_OFF : V12_17_ENGINE_LAST_ORACLE_PRICE_OFF;\r\n const fundPxLastOff = isV12_19 ? V12_19_SBF_ENGINE_FUND_PX_LAST_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_FUND_PX_LAST_OFF : V12_17_ENGINE_FUND_PX_LAST_OFF;\r\n const fLongNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_LONG_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_LONG_NUM_OFF : V12_17_ENGINE_F_LONG_NUM_OFF;\r\n const fShortNumOff = isV12_19 ? V12_19_SBF_ENGINE_F_SHORT_NUM_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_F_SHORT_NUM_OFF : V12_17_ENGINE_F_SHORT_NUM_OFF;\r\n // resolved_k offsets: native 304/320, SBF 288/304\r\n // V12_19 renamed resolved_k_long/short to *_terminal_delta but kept same offsets.\r\n const resolvedKLongOff = isV12_19 ? 288\r\n : isSbf ? 288 : V12_17_ENGINE_RESOLVED_K_LONG_OFF;\r\n const resolvedKShortOff = isV12_19 ? 304\r\n : isSbf ? 304 : V12_17_ENGINE_RESOLVED_K_SHORT_OFF;\r\n const resolvedLivePriceOff = isV12_19 ? V12_19_SBF_ENGINE_RESOLVED_LIVE_PRICE_OFF\r\n : isSbf ? 320 : V12_17_ENGINE_RESOLVED_LIVE_PRICE_OFF;\r\n // V12_19 doesn't have last_crank_slot or gc_cursor; use last_market_slot and rr_cursor.\r\n const lastCrankSlotOff = isV12_19 ? V12_19_SBF_ENGINE_LAST_MARKET_SLOT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_LAST_CRANK_SLOT_OFF : V12_17_ENGINE_LAST_CRANK_SLOT_OFF;\r\n const gcCursorOff = isV12_19 ? V12_19_SBF_ENGINE_RR_CURSOR_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_GC_CURSOR_OFF : V12_17_ENGINE_GC_CURSOR_OFF;\r\n const oiEffLongOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_LONG_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_LONG_OFF : V12_17_ENGINE_OI_EFF_LONG_OFF;\r\n const oiEffShortOff = isV12_19 ? V12_19_SBF_ENGINE_OI_EFF_SHORT_OFF\r\n : isSbf ? V12_17_SBF_ENGINE_OI_EFF_SHORT_OFF : V12_17_ENGINE_OI_EFF_SHORT_OFF;\r\n\r\n const longOi = readU128LE(data, base + oiEffLongOff);\r\n const shortOi = readU128LE(data, base + oiEffShortOff);\r\n\r\n // numUsedAccounts: at bitmap + bitmapBytes (postBitmap=4: num_used_accounts is first u16)\r\n const bitmapEnd = layout.engineBitmapOff + layout.bitmapWords * 8;\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: 0n,\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + currentSlotOff),\r\n fundingIndexQpbE6: 0n, // replaced by per-side funding\r\n lastFundingSlot: 0n,\r\n fundingRateBpsPerSlotLast: 0n, // no stored funding rate in v12.17\r\n fundingRateE9: 0n, // no stored funding rate in v12.17\r\n marketMode: readU8(data, base + marketModeOff) === 1 ? 1 : 0,\r\n lastCrankSlot: readU64LE(data, base + lastCrankSlotOff),\r\n maxCrankStalenessSlots: 0n,\r\n totalOpenInterest: longOi + shortOi,\r\n longOi,\r\n shortOi,\r\n cTot: readU128LE(data, base + cTotOff),\r\n pnlPosTot: readU128LE(data, base + pnlPosTotOff),\r\n pnlMaturedPosTot: readU128LE(data, base + pnlMaturedOff),\r\n liqCursor: 0,\r\n gcCursor: readU16LE(data, base + gcCursorOff),\r\n lastSweepStartSlot: 0n,\r\n lastSweepCompleteSlot: 0n,\r\n crankCursor: 0,\r\n sweepStartIdx: 0,\r\n lifetimeLiquidations: 0n,\r\n lifetimeForceCloses: 0n,\r\n netLpPos: 0n,\r\n lpSumAbs: 0n,\r\n lpMaxAbs: 0n,\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n,\r\n oraclePriceE6: readU64LE(data, base + oraclePriceOff),\r\n numUsedAccounts: readU16LE(data, base + bitmapEnd),\r\n nextAccountId: 0n, // removed in v12.17 (replaced by mat_counter in header)\r\n\r\n // V12_17 fields\r\n fLongNum: readI128LE(data, base + fLongNumOff),\r\n fShortNum: readI128LE(data, base + fShortNumOff),\r\n negPnlAccountCount: readU64LE(data, base + negPnlOff),\r\n fundPxLast: readU64LE(data, base + fundPxLastOff),\r\n resolvedKLongTerminalDelta: readI128LE(data, base + resolvedKLongOff),\r\n resolvedKShortTerminalDelta: readI128LE(data, base + resolvedKShortOff),\r\n resolvedLivePrice: readU64LE(data, base + resolvedLivePriceOff),\r\n };\r\n }\r\n\r\n // For v12.15: funding_rate_e9 is i128 at layout.engineFundingRateBpsOff (224 SBF, 240 native).\r\n // For pre-v12.15: i64 at engineFundingRateBpsOff.\r\n const fundingRateBpsPerSlotLast = isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : readI64LE(data, base + layout.engineFundingRateBpsOff);\r\n\r\n return {\r\n vault: readU128LE(data, base),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + layout.engineInsuranceOff),\r\n // feeRevenue: only exists in percolator-core (80-byte InsuranceFund), not deployed (16-byte)\r\n feeRevenue: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceOff + 16)\r\n : 0n,\r\n isolatedBalance: layout.hasInsuranceIsolation\r\n ? readU128LE(data, base + layout.engineInsuranceIsolatedOff)\r\n : 0n,\r\n isolationBps: layout.hasInsuranceIsolation\r\n ? readU16LE(data, base + layout.engineInsuranceIsolationBpsOff)\r\n : 0,\r\n },\r\n currentSlot: readU64LE(data, base + layout.engineCurrentSlotOff),\r\n fundingIndexQpbE6: layout.engineFundingIndexOff >= 0\r\n ? ((layout.engineLastFundingSlotOff >= 0 && layout.engineLastFundingSlotOff - layout.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + layout.engineFundingIndexOff))\r\n : readI128LE(data, base + layout.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: layout.engineLastFundingSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastFundingSlotOff) : 0n,\r\n fundingRateBpsPerSlotLast,\r\n fundingRateE9: isV12_15\r\n ? readI128LE(data, base + layout.engineFundingRateBpsOff)\r\n : 0n,\r\n marketMode: isV12_15\r\n ? (readU8(data, base + layout.engineFundingRateBpsOff + 16) === 1 ? 1 : 0)\r\n : null,\r\n lastCrankSlot: layout.engineLastCrankSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastCrankSlotOff) : 0n,\r\n maxCrankStalenessSlots: layout.engineMaxCrankStalenessOff >= 0\r\n ? readU64LE(data, base + layout.engineMaxCrankStalenessOff) : 0n,\r\n totalOpenInterest: layout.engineTotalOiOff >= 0\r\n ? readU128LE(data, base + layout.engineTotalOiOff) : 0n,\r\n longOi: layout.engineLongOiOff >= 0\r\n ? readU128LE(data, base + layout.engineLongOiOff) : 0n,\r\n shortOi: layout.engineShortOiOff >= 0\r\n ? readU128LE(data, base + layout.engineShortOiOff) : 0n,\r\n cTot: readU128LE(data, base + layout.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + layout.enginePnlPosTotOff),\r\n pnlMaturedPosTot: isV12_15\r\n ? readU128LE(data, base + V12_15_ENGINE_PNL_MATURED_POS_TOT_OFF)\r\n : 0n,\r\n liqCursor: layout.engineLiqCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineLiqCursorOff) : 0,\r\n gcCursor: layout.engineGcCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineGcCursorOff) : 0,\r\n lastSweepStartSlot: layout.engineLastSweepStartOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepStartOff) : 0n,\r\n lastSweepCompleteSlot: layout.engineLastSweepCompleteOff >= 0\r\n ? readU64LE(data, base + layout.engineLastSweepCompleteOff) : 0n,\r\n crankCursor: layout.engineCrankCursorOff >= 0\r\n ? readU16LE(data, base + layout.engineCrankCursorOff) : 0,\r\n sweepStartIdx: layout.engineSweepStartIdxOff >= 0\r\n ? readU16LE(data, base + layout.engineSweepStartIdxOff) : 0,\r\n lifetimeLiquidations: layout.engineLifetimeLiquidationsOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeLiquidationsOff) : 0n,\r\n lifetimeForceCloses: layout.engineLifetimeForceClosesOff >= 0\r\n ? readU64LE(data, base + layout.engineLifetimeForceClosesOff) : 0n,\r\n netLpPos: layout.engineNetLpPosOff >= 0\r\n ? readI128LE(data, base + layout.engineNetLpPosOff) : 0n,\r\n lpSumAbs: layout.engineLpSumAbsOff >= 0\r\n ? readU128LE(data, base + layout.engineLpSumAbsOff) : 0n,\r\n lpMaxAbs: layout.engineLpMaxAbsOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsOff) : 0n,\r\n lpMaxAbsSweep: layout.engineLpMaxAbsSweepOff >= 0 ? readU128LE(data, base + layout.engineLpMaxAbsSweepOff) : 0n,\r\n emergencyOiMode: layout.engineEmergencyOiModeOff >= 0\r\n ? data[base + layout.engineEmergencyOiModeOff] !== 0\r\n : false,\r\n emergencyStartSlot: layout.engineEmergencyStartSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineEmergencyStartSlotOff) : 0n,\r\n lastBreakerSlot: layout.engineLastBreakerSlotOff >= 0\r\n ? readU64LE(data, base + layout.engineLastBreakerSlotOff) : 0n,\r\n markPriceE6: layout.engineMarkPriceOff >= 0\r\n ? readU64LE(data, base + layout.engineMarkPriceOff) : 0n,\r\n // V12_15: last_oracle_price at engine+608 (SBF) / engine+... (native).\r\n // Located at bitmapOff - 40 on SBF (648-40=608, verified on-chain).\r\n oraclePriceE6: isV12_15\r\n ? readU64LE(data, base + layout.engineBitmapOff - 40)\r\n : 0n,\r\n numUsedAccounts: (() => {\r\n if (layout.postBitmap < 18) return 0;\r\n const bw = layout.bitmapWords;\r\n return readU16LE(data, base + layout.engineBitmapOff + bw * 8);\r\n })(),\r\n nextAccountId: (() => {\r\n if (layout.postBitmap < 18) return 0n;\r\n const bw = layout.bitmapWords;\r\n const numUsedOff = layout.engineBitmapOff + bw * 8;\r\n return readU64LE(data, base + Math.ceil((numUsedOff + 2) / 8) * 8);\r\n })(),\r\n\r\n // V12_17 fields (not present in pre-v12.17)\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n };\r\n}\r\n\r\n/**\r\n * Read bitmap to get list of used account indices.\r\n */\r\n/**\r\n * Return all account indices whose bitmap bit is set (i.e. slot is in use).\r\n * Uses the layout-aware bitmap offset so V1_LEGACY slabs (bitmap at rel+672) are handled correctly.\r\n */\r\nexport function parseUsedIndices(data: Uint8Array): number[] {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n if (data.length < base + layout.bitmapWords * 8) {\r\n throw new Error(\"Slab data too short for bitmap\");\r\n }\r\n\r\n const used: number[] = [];\r\n for (let word = 0; word < layout.bitmapWords; word++) {\r\n const bits = readU64LE(data, base + word * 8);\r\n if (bits === 0n) continue;\r\n for (let bit = 0; bit < 64; bit++) {\r\n if ((bits >> BigInt(bit)) & 1n) {\r\n used.push(word * 64 + bit);\r\n }\r\n }\r\n }\r\n return used;\r\n}\r\n\r\n/**\r\n * Check if a specific account index is used.\r\n */\r\nexport function isAccountUsed(data: Uint8Array, idx: number): boolean {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) return false;\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= layout.maxAccounts) return false;\r\n const base = layout.engineOff + layout.engineBitmapOff;\r\n const word = Math.floor(idx / 64);\r\n const bit = idx % 64;\r\n const bits = readU64LE(data, base + word * 8);\r\n return ((bits >> BigInt(bit)) & 1n) !== 0n;\r\n}\r\n\r\n/**\r\n * Calculate the maximum valid account index for a given slab size.\r\n */\r\nexport function maxAccountIndex(dataLen: number): number {\r\n const layout = detectSlabLayout(dataLen);\r\n if (!layout) return 0;\r\n const accountsEnd = dataLen - layout.accountsOff;\r\n if (accountsEnd <= 0) return 0;\r\n return Math.floor(accountsEnd / layout.accountSize);\r\n}\r\n\r\n/**\r\n * Parse a single account by index.\r\n */\r\nexport function parseAccount(data: Uint8Array, idx: number): Account {\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) throw new Error(`Unrecognized slab data length: ${data.length}`);\r\n\r\n const maxIdx = maxAccountIndex(data.length);\r\n if (!Number.isInteger(idx) || idx < 0 || idx >= maxIdx) {\r\n throw new Error(`Account index out of range: ${idx} (max: ${maxIdx - 1})`);\r\n }\r\n\r\n const base = layout.accountsOff + idx * layout.accountSize;\r\n if (data.length < base + layout.accountSize) {\r\n throw new Error(\"Slab data too short for account\");\r\n }\r\n\r\n // Select layout-dependent account field offsets.\r\n // V12_15 (account_size=4400): completely new layout, reserve cohorts, warmup/lastFeeSlot removed.\r\n // V12_1 (account_size=320/280): new fields (position_basis_q, adl_a_basis, adl_k_snap, adl_epoch_snap)\r\n // shift matcher/owner/fee offsets +16 from V_ADL, and move legacy fields to end.\r\n // V_ADL (account_size=312): reserved_pnl grew u64→u128 (PERC-8267), shifting from pre-ADL offsets.\r\n // Pre-ADL (account_size<312): original offsets.\r\n // V12_1: engineOff=648 + bitmapOff(rel)=368. Detect by engineOff (most reliable).\r\n // Account is 320 on aarch64, 280 on SBF — accountSize alone is ambiguous.\r\n // V12_1_EP: entry_price re-added, accountSize=288 on SBF. All offsets after entry_price shift +8.\r\n // V12_19 SBF Account is structurally identical to V12_17 SBF (same field offsets,\r\n // same SBF alignment correction d1=8/d2=16). Only difference: 8 bytes of trailing\r\n // padding (V12_17 SBF=352, V12_19 SBF=360). Routing V12_19 to the V12_17 fast path\r\n // here is correct — pending_created_slot at +352 in both versions. Probe-confirmed 2026-04-28.\r\n const isV12_17 = layout.accountSize === V12_17_ACCOUNT_SIZE\r\n || layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const isV12_15 = !isV12_17 && (layout.accountSize === V12_15_ACCOUNT_SIZE || layout.accountSize === V12_15_ACCOUNT_SIZE_SMALL);\r\n const isV12_1EP = !isV12_17 && !isV12_15 && layout.accountSize === V12_1_EP_SBF_ACCOUNT_SIZE && layout.engineOff === V12_1_SBF_ENGINE_OFF;\r\n const isV12_1 = !isV12_17 && !isV12_15 && !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);\r\n const isAdl = !isV12_17 && !isV12_15 && (layout.accountSize >= 312 || isV12_1 || isV12_1EP);\r\n\r\n if (isV12_17) {\r\n // V12_17 fast path: two-bucket warmup, per-side funding, no account_id/entry_price/cohorts.\r\n //\r\n // SBF vs native alignment delta:\r\n // After `kind: u8`, native i128 (align=16) inserts 15 bytes pad vs SBF (align=8) 7 bytes → d1=8.\r\n // After `pending_present: u8`, the same happens again: native pads 15 vs SBF 7 → d2=16.\r\n // The first gap (after sched_present) does NOT add extra delta because sched_present lands at\r\n // native offset 248 where (249 % 16 = 9) needs only 7 bytes — same as SBF. But pending_present\r\n // lands at native 320 where (321 % 16 = 1) needs 15 bytes vs SBF's 7.\r\n const isSbf = layout.accountSize === V12_17_ACCOUNT_SIZE_SBF\r\n || layout.accountSize === V12_19_ACCOUNT_SIZE_SBF;\r\n const d1 = isSbf ? 8 : 0; // fields after kind through pending_present\r\n const d2 = isSbf ? 16 : 0; // fields after pending_present (pending_remaining_q onward)\r\n\r\n const kindByte = readU8(data, base + V12_17_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: 0n, // removed in v12.17\r\n capital: readU128LE(data, base + V12_17_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_17_ACCT_PNL_OFF - d1),\r\n reservedPnl: readU128LE(data, base + V12_17_ACCT_RESERVED_PNL_OFF - d1),\r\n warmupStartedAtSlot: 0n, // removed\r\n warmupSlopePerStep: 0n, // removed\r\n positionSize: readI128LE(data, base + V12_17_ACCT_POSITION_BASIS_Q_OFF - d1),\r\n entryPrice: 0n, // removed — compute off-chain from position_basis_q / effective_pos_q\r\n fundingIndex: 0n, // replaced by per-side f_long_num/f_short_num + per-account f_snap\r\n matcherProgram: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1, base + V12_17_ACCT_MATCHER_PROGRAM_OFF - d1 + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1, base + V12_17_ACCT_MATCHER_CONTEXT_OFF - d1 + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_17_ACCT_OWNER_OFF - d1, base + V12_17_ACCT_OWNER_OFF - d1 + 32)),\r\n feeCredits: readI128LE(data, base + V12_17_ACCT_FEE_CREDITS_OFF - d1),\r\n lastFeeSlot: 0n, // removed\r\n feesEarnedTotal: 0n, // removed in v12.17\r\n exactReserveCohorts: null, // replaced by two-bucket warmup\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // V12_17 fields\r\n fSnap: readI128LE(data, base + V12_17_ACCT_F_SNAP_OFF - d1),\r\n adlABasis: readU128LE(data, base + V12_17_ACCT_ADL_A_BASIS_OFF - d1),\r\n adlKSnap: readI128LE(data, base + V12_17_ACCT_ADL_K_SNAP_OFF - d1),\r\n adlEpochSnap: readU64LE(data, base + V12_17_ACCT_ADL_EPOCH_SNAP_OFF - d1),\r\n schedPresent: readU8(data, base + V12_17_ACCT_SCHED_PRESENT_OFF - d1) !== 0,\r\n schedRemainingQ: readU128LE(data, base + V12_17_ACCT_SCHED_REMAINING_Q_OFF - d1),\r\n schedAnchorQ: readU128LE(data, base + V12_17_ACCT_SCHED_ANCHOR_Q_OFF - d1),\r\n schedStartSlot: readU64LE(data, base + V12_17_ACCT_SCHED_START_SLOT_OFF - d1),\r\n schedHorizon: readU64LE(data, base + V12_17_ACCT_SCHED_HORIZON_OFF - d1),\r\n schedReleaseQ: readU128LE(data, base + V12_17_ACCT_SCHED_RELEASE_Q_OFF - d1),\r\n pendingPresent: readU8(data, base + V12_17_ACCT_PENDING_PRESENT_OFF - d1) !== 0,\r\n pendingRemainingQ: readU128LE(data, base + V12_17_ACCT_PENDING_REMAINING_Q_OFF - d2),\r\n pendingHorizon: readU64LE(data, base + V12_17_ACCT_PENDING_HORIZON_OFF - d2),\r\n pendingCreatedSlot: readU64LE(data, base + V12_17_ACCT_PENDING_CREATED_SLOT_OFF - d2),\r\n };\r\n }\r\n\r\n if (isV12_15) {\r\n // V12_15 fast path: fixed offsets, all fields explicit.\r\n const kindByte = readU8(data, base + V12_15_ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n // Parse the 62 reserve cohorts\r\n const cohortCount = readU8(data, base + V12_15_ACCT_EXACT_COHORT_COUNT_OFF);\r\n const exactReserveCohorts: ReserveCohortBytes[] = [];\r\n for (let i = 0; i < 62; i++) {\r\n const cohortOff = base + V12_15_ACCT_EXACT_RESERVE_COHORTS_OFF + i * 64;\r\n exactReserveCohorts.push(data.slice(cohortOff, cohortOff + 64));\r\n }\r\n\r\n const overflowOlderPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_OLDER_PRESENT_OFF) !== 0;\r\n const overflowNewestPresent = readU8(data, base + V12_15_ACCT_OVERFLOW_NEWEST_PRESENT_OFF) !== 0;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + V12_15_ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + V12_15_ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + V12_15_ACCT_PNL_OFF),\r\n reservedPnl: readU128LE(data, base + V12_15_ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: 0n, // removed in v12.15\r\n warmupSlopePerStep: 0n, // removed in v12.15\r\n positionSize: readI128LE(data, base + V12_15_ACCT_POSITION_BASIS_Q_OFF),\r\n entryPrice: readU64LE(data, base + V12_15_ACCT_ENTRY_PRICE_OFF),\r\n fundingIndex: 0n, // not present in v12.15 account struct\r\n matcherProgram: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_PROGRAM_OFF, base + V12_15_ACCT_MATCHER_PROGRAM_OFF + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + V12_15_ACCT_MATCHER_CONTEXT_OFF, base + V12_15_ACCT_MATCHER_CONTEXT_OFF + 32)),\r\n owner: new PublicKey(data.subarray(base + V12_15_ACCT_OWNER_OFF, base + V12_15_ACCT_OWNER_OFF + 32)),\r\n feeCredits: readI128LE(data, base + V12_15_ACCT_FEE_CREDITS_OFF),\r\n lastFeeSlot: 0n, // removed in v12.15\r\n feesEarnedTotal: readU128LE(data, base + V12_15_ACCT_FEES_EARNED_TOTAL_OFF),\r\n exactReserveCohorts,\r\n exactCohortCount: cohortCount,\r\n overflowOlder: data.slice(base + V12_15_ACCT_OVERFLOW_OLDER_OFF, base + V12_15_ACCT_OVERFLOW_OLDER_OFF + 64),\r\n overflowOlderPresent,\r\n overflowNewest: data.slice(base + V12_15_ACCT_OVERFLOW_NEWEST_OFF, base + V12_15_ACCT_OVERFLOW_NEWEST_OFF + 64),\r\n overflowNewestPresent,\r\n\r\n // v12.17 fields (not present in v12.15)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n }\r\n\r\n // Pre-v12.15 path\r\n const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;\r\n const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;\r\n const positionSizeOff = (isV12_1 || isV12_1EP) ? V12_1_ACCT_POSITION_SIZE_OFF : (isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF);\r\n 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));\r\n const fundingIndexOff = (isV12_1 || isV12_1EP) ? -1 : (isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF);\r\n 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));\r\n 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));\r\n 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));\r\n 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));\r\n\r\n const kindByte = readU8(data, base + ACCT_KIND_OFF);\r\n const kind = kindByte === 1 ? AccountKind.LP : AccountKind.User;\r\n\r\n return {\r\n kind,\r\n accountId: readU64LE(data, base + ACCT_ACCOUNT_ID_OFF),\r\n capital: readU128LE(data, base + ACCT_CAPITAL_OFF),\r\n pnl: readI128LE(data, base + ACCT_PNL_OFF),\r\n reservedPnl: isAdl ? readU128LE(data, base + ACCT_RESERVED_PNL_OFF) : readU64LE(data, base + ACCT_RESERVED_PNL_OFF),\r\n warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),\r\n warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),\r\n positionSize: readI128LE(data, base + positionSizeOff),\r\n entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,\r\n // V12_1/V12_1_EP: funding_index not present in SBF layout\r\n fundingIndex: (isV12_1 || isV12_1EP) ? (fundingIndexOff >= 0 ? BigInt(readI64LE(data, base + fundingIndexOff)) : 0n) : readI128LE(data, base + fundingIndexOff),\r\n matcherProgram: new PublicKey(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),\r\n matcherContext: new PublicKey(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),\r\n owner: new PublicKey(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),\r\n feeCredits: readI128LE(data, base + feeCreditsOff),\r\n lastFeeSlot: readU64LE(data, base + lastFeeSlotOff),\r\n feesEarnedTotal: 0n, // not present in pre-v12.15 layouts\r\n exactReserveCohorts: null, // not present in pre-v12.15 layouts\r\n exactCohortCount: null,\r\n overflowOlder: null,\r\n overflowOlderPresent: null,\r\n overflowNewest: null,\r\n overflowNewestPresent: null,\r\n\r\n // v12.17 fields (not present in pre-v12.17)\r\n fSnap: 0n, adlABasis: 0n, adlKSnap: 0n, adlEpochSnap: 0n,\r\n schedPresent: null, schedRemainingQ: null, schedAnchorQ: null,\r\n schedStartSlot: null, schedHorizon: null, schedReleaseQ: null,\r\n pendingPresent: null, pendingRemainingQ: null, pendingHorizon: null, pendingCreatedSlot: null,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// v17 (WrapperConfigV16) — 496-byte config block in the market group account\r\n//\r\n// Protocol-fee program change (feat/protocol-fee-taker-only, wrapper HEAD\r\n// 626fb617): WrapperConfigV16 grew 432 -> 496 bytes (three new tail fields,\r\n// see WrapperConfigV17 below) and the account VERSION bumped 16 -> 17. This\r\n// is a full account-layout break — every v16-version market account is\r\n// abandoned; only VERSION=17 accounts carry the 496-byte config block.\r\n// =============================================================================\r\n\r\n/**\r\n * v17 account magic (\"PERCV16\\0\" as little-endian u64).\r\n * Stored at bytes [0..8] of every v17 percolator-owned account.\r\n * bytes[0..8] = [0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]\r\n */\r\nexport const V17_MAGIC = 0x5045_5243_5631_3600n;\r\n\r\n/**\r\n * v17 account version (u16 at offset 8).\r\n *\r\n * Bumped 16 -> 17 by the protocol-fee program change (WrapperConfigV16\r\n * 432 -> 496 bytes; percolator-prog@626fb617, `v16_program.rs:51`\r\n * `pub const VERSION: u16 = 17`). Fails closed on any pre-protocol-fee\r\n * (VERSION=16) account — those must be re-seeded, not read with this parser.\r\n */\r\nexport const V17_EXPECTED_VERSION = 17;\r\n\r\n/**\r\n * v17 account-kind byte (offset 10 of the 16-byte header).\r\n *\r\n * The program's `check_header()` discriminates EVERY v17 percolator-owned\r\n * account SOLELY by this byte (percolator-prog `v16_program.rs` KIND_*):\r\n * 1 = MARKET, 2 = PORTFOLIO, 3 = BACKING_DOMAIN_LEDGER, 4 = INSURANCE_LEDGER,\r\n * 5 = LP_VAULT_REGISTRY, 6 = LP_REDEMPTION, 7 = NFT_REGISTRY.\r\n * Only KIND_MARKET (1) carries the WrapperConfigV16 block parsed during market\r\n * discovery — every other kind shares the same magic+version and would falsely\r\n * pass the looser {@link isV17Account} check (#264).\r\n */\r\nexport const V17_KIND_MARKET = 1;\r\n\r\n/** Byte offset of the v17 account-kind discriminator within the header. */\r\nexport const V17_KIND_OFF = 10;\r\n\r\n/**\r\n * v17 wrapper config block length (WrapperConfigV16 = 576 bytes).\r\n *\r\n * Growth history, each stage purely additive at the tail with all earlier\r\n * offsets UNCHANGED:\r\n * 432 -> 496 protocol-fee program change: `protocol_fee_authority` [32]\r\n * @432, `protocol_fee_accrued_atoms` u128 @464,\r\n * `protocol_fee_withdrawn_atoms` u128 @480.\r\n * 496 -> 576 fee-collection split (percolator-prog\r\n * feat/protocol-fee-taker-only@2b3a6a65): four u128 counters\r\n * @496/512/528/544, three u16 shares @560/562/564, then\r\n * `_padding_split` [u8;10] @566.\r\n *\r\n * ⚠ FIELD ORDER IN THE 496->576 BLOCK IS LOAD-BEARING. The struct derives\r\n * `bytemuck::Pod`, which forbids IMPLICIT padding. 496 is a multiple of 16, so\r\n * it is u128-aligned; placing the u16 shares first would push the u128s to\r\n * offset 502 and force the compiler to insert implicit padding, failing the\r\n * Pod derive. Counters therefore come first, then the shares, then EXPLICIT\r\n * padding out to the 16-byte alignment boundary.\r\n *\r\n * Verified against `percolator-prog/src/v16_program.rs` — `WRAPPER_CONFIG_LEN:\r\n * usize = 576` at line 58, struct `WrapperConfigV16` at line 1057, with a\r\n * compile-time `assert!(size_of::() == WRAPPER_CONFIG_LEN)`\r\n * at line 1159.\r\n *\r\n * ⚠ NOT YET DEPLOYED. The devnet wrapper DhSkE7uTb8HBUYYWF1xkxMYBGtLYJEoDq1tfBD7SnHcj\r\n * still carries the 496-byte layout. Reading a market created by that build\r\n * with this decoder will throw \"data too short\"; a 576-byte read against a\r\n * 496-byte account is a length error, not a silent misparse.\r\n */\r\nexport const V17_WRAPPER_CONFIG_LEN = 576;\r\n\r\n/**\r\n * Byte offset of `creator_fee_claimable_atoms` (u64 LE) RELATIVE TO THE START\r\n * OF THE WrapperConfigV16 BLOCK. Absolute offset in a market-group account is\r\n * `V17_HEADER_LEN + V17_CREATOR_FEE_CLAIMABLE_OFF` = 16 + 568 = 584.\r\n *\r\n * ADDITIVE AND IN-PLACE: the field was carved out of the existing 10-byte\r\n * `_padding_split` tail at the only 8-aligned slot inside it, so\r\n * {@link V17_WRAPPER_CONFIG_LEN} stays 576, {@link V17_MARKET_GROUP_OFF} stays\r\n * 592, and NO pre-existing offset moves. Growing the config instead would have\r\n * shifted every asset-profile offset and bricked the already-deployed 576-byte\r\n * markets — a repeat of the 496→576 incident. If you ever find yourself\r\n * changing V17_WRAPPER_CONFIG_LEN because of this field, something is wrong.\r\n *\r\n * Source of truth: percolator-prog `src/v16_program.rs` struct\r\n * `WrapperConfigV16` (`creator_fee_claimable_atoms: u64` after\r\n * `_padding_split: [u8; 2]`), guarded on the Rust side by\r\n * `const _: () = assert!(size_of::() == WRAPPER_CONFIG_LEN)`.\r\n */\r\nexport const V17_CREATOR_FEE_CLAIMABLE_OFF = 568;\r\n\r\n/** v17 AssetOracleProfileV16 length (400 bytes). */\r\nexport const V17_ASSET_ORACLE_PROFILE_LEN = 400;\r\n\r\n/** v17 header length (16 bytes: magic[8] + version[2] + kind[1] + pad[1] + reserved[4]). */\r\nexport const V17_HEADER_LEN = 16;\r\n\r\n/**\r\n * v17 market group config offset = HEADER_LEN + WRAPPER_CONFIG_LEN = 592\r\n * (was 512 pre-fee-split when WRAPPER_CONFIG_LEN was 496, and 448 before the\r\n * protocol-fee change when it was 432). DERIVED, never hardcoded — every\r\n * downstream offset in this file chains off it.\r\n */\r\nexport const V17_MARKET_GROUP_OFF = V17_HEADER_LEN + V17_WRAPPER_CONFIG_LEN; // 592\r\n\r\n/**\r\n * v17 MarketGroupV16HeaderAccount size (758 bytes) and per-asset slot stride (1797 bytes),\r\n * verified against percolator-prog `cargo run --example dump_layout`.\r\n */\r\nexport const V17_MARKET_GROUP_LEN = 758;\r\nexport const V17_MARKET_ASSET_SLOT_LEN = 1797;\r\n\r\n/**\r\n * Exact byte length of a v17 market (slab) account for a given asset-slot capacity, matching the\r\n * program's state::market_account_len_for_capacity. v17 markets are DYNAMICALLY sized — the wrapper's\r\n * InitMarket validates that (len - V17_MARKET_GROUP_OFF - V17_MARKET_GROUP_LEN) is an exact multiple of\r\n * V17_MARKET_ASSET_SLOT_LEN, so a v12 SLAB_TIERS byte count (e.g. 992_568) makes InitMarket REVERT.\r\n * Size the account with this for maxPortfolioAssets (cap-1 = 3003, cap-14 = 26_364).\r\n */\r\nexport function v17MarketAccountLen(maxPortfolioAssets: number): number {\r\n if (!Number.isInteger(maxPortfolioAssets) || maxPortfolioAssets < 1) {\r\n throw new Error(`v17MarketAccountLen: maxPortfolioAssets must be a positive integer, got ${maxPortfolioAssets}`);\r\n }\r\n return V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN + maxPortfolioAssets * V17_MARKET_ASSET_SLOT_LEN;\r\n}\r\n\r\n/**\r\n * v17 portfolio account total length = HEADER_LEN(16) + PortfolioAccountV16Account(9227) +\r\n * PORTFOLIO_MATCHER_CONFIG_LEN(104) = 9347. Single source of truth for the System.createAccount\r\n * size/rent: the program's InitPortfolio reallocs UP to this and adds no lamports, so an undersized\r\n * createAccount (e.g. 2048) leaves the account below rent-exempt → InitPortfolio fails with\r\n * InsufficientFundsForRent. (Matches the keeper's getProgramAccounts dataSize filter.)\r\n */\r\nexport const V17_PORTFOLIO_ACCOUNT_LEN = 9347;\r\n\r\n/**\r\n * Parsed WrapperConfigV16 — the 496-byte v17 market config block.\r\n *\r\n * Field offsets follow SBF alignment (u128 align=8, not 16).\r\n * Full offset table (verified against v17 wrapper source v16_program.rs,\r\n * protocol-fee branch feat/protocol-fee-taker-only@626fb617):\r\n * 0 marketauth [32]\r\n * 32 collateral_mint [32]\r\n * 64 secondary_collateral_mint [32]\r\n * 96 maintenance_fee_per_slot u128\r\n * 112 permissionless_market_init_fee u128\r\n * 128 trade_fee_base_bps u64\r\n * 136 permissionless_resolve_stale_slots u64\r\n * 144 force_close_delay_slots u64\r\n * 152 last_good_oracle_slot u64\r\n * 160 insurance_withdraw_deposit_remaining u128\r\n * 176 insurance_withdraw_max_bps u16\r\n * 178 liquidation_cranker_fee_share_bps u16\r\n * 180 maintenance_cranker_fee_share_bps u16\r\n * 182 backing_trade_fee_bps_long u16\r\n * 184 unit_scale u32\r\n * 188 conf_filter_bps u16\r\n * 190 backing_trade_fee_bps_short u16\r\n * 192 insurance_withdraw_deposits_only u8\r\n * 193 oracle_mode u8\r\n * 194 oracle_leg_count u8\r\n * 195 oracle_leg_flags u8\r\n * 196 invert u8\r\n * 197 _padding0 u8\r\n * 198 free_market_slot_count u16\r\n * 200 insurance_withdraw_cooldown_slots u64\r\n * 208 last_insurance_withdraw_slot u64\r\n * 216 max_staleness_secs u64\r\n * 224 hybrid_soft_stale_slots u64\r\n * 232 mark_ewma_e6 u64\r\n * 240 mark_ewma_last_slot u64\r\n * 248 mark_ewma_halflife_slots u64\r\n * 256 mark_min_fee u64\r\n * 264 oracle_target_price_e6 u64\r\n * 272 oracle_target_publish_time i64\r\n * 280 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 376 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 400 oracle_leg_publish_times [i64;3] (24B)\r\n * 424 backing_trade_fee_policy_count u16\r\n * 426 backing_trade_fee_insurance_share_bps_long u16\r\n * 428 backing_trade_fee_insurance_share_bps_short u16\r\n * 430 fee_redirect_to_market_0_bps u16\r\n * --- protocol-fee program change (additive tail, offsets 0..431 unchanged) ---\r\n * 432 protocol_fee_authority [32]\r\n * 464 protocol_fee_accrued_atoms u128\r\n * 480 protocol_fee_withdrawn_atoms u128\r\n * --- fee-collection split (additive tail, offsets 0..495 unchanged) ---\r\n * --- ORDER IS LOAD-BEARING: u128 counters MUST precede the u16 shares ---\r\n * 496 lp_fee_accrued_atoms u128\r\n * 512 lp_fee_withdrawn_atoms u128\r\n * 528 insurance_reserve_accrued_atoms u128\r\n * 544 insurance_reserve_withdrawn_atoms u128\r\n * 560 creator_share_bps u16\r\n * 562 lp_share_bps u16\r\n * 564 insurance_share_bps u16\r\n * 566 _padding_split [u8;2] (was [u8;10] pre-creator-fee-claim)\r\n * --- creator fee claim (2026-07-23) — IN-PLACE, consumes the pad tail ---\r\n * 568 creator_fee_claimable_atoms u64 (NEW; WRAPPER_CONFIG_LEN still 576)\r\n * Total: 576\r\n */\r\nexport interface WrapperConfigV17 {\r\n marketauth: PublicKey;\r\n collateralMint: PublicKey;\r\n secondaryCollateralMint: PublicKey;\r\n maintenanceFeePerSlot: bigint;\r\n permissionlessMarketInitFee: bigint;\r\n tradeFeeBps: bigint;\r\n permissionlessResolveStaleSlots: bigint;\r\n forceCloseDelaySlots: bigint;\r\n lastGoodOracleSlot: bigint;\r\n insuranceWithdrawDepositRemaining: bigint;\r\n insuranceWithdrawMaxBps: number;\r\n liquidationCrankerFeeShareBps: number;\r\n maintenanceCrankerFeeShareBps: number;\r\n backingTradeFeeBpsLong: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsShort: number;\r\n insuranceWithdrawDepositsOnly: number;\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n freeMarketSlotCount: number;\r\n insuranceWithdrawCooldownSlots: bigint;\r\n lastInsuranceWithdrawSlot: bigint;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n backingTradeFeePolicyCount: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n feeRedirectToMarket0Bps: number;\r\n /**\r\n * Destination pubkey for the protocol's accrued fee share. Set to a\r\n * hardcoded program-level constant at InitMarket; rotatable only via\r\n * SetProtocolFeeAuthority (tag 85, upgrade-authority-gated). NOT settable\r\n * by marketauth/insurance_authority/any creator-facing gate.\r\n */\r\n protocolFeeAuthority: PublicKey;\r\n /**\r\n * Cumulative atoms ever accrued to the protocol's claim (monotonic). Never\r\n * itself credited into any domain's insurance budget — tracks an\r\n * unbudgeted slice of header.insurance no insurance_operator can reach.\r\n */\r\n protocolFeeAccruedAtoms: bigint;\r\n /**\r\n * Cumulative atoms ever paid out via WithdrawProtocolFee (tag 84).\r\n * Monotonic, always <= protocolFeeAccruedAtoms. Claim capacity =\r\n * protocolFeeAccruedAtoms - protocolFeeWithdrawnAtoms.\r\n */\r\n protocolFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the LP vault's claim (monotonic). Claimed via\r\n * LpVaultCrankFees (tag 78), which reclassifies them into LP backing\r\n * principal.\r\n *\r\n * ⚠ LP yield is JUNIOR at-risk backing capital, not a senior earnings claim:\r\n * it can be impaired by backing losses between crank and redemption.\r\n *\r\n * ⚠ Tag 78 is Live-only, so LP fees accrued on a market that later Resolves\r\n * can never be cranked. Outstanding = accrued - withdrawn.\r\n */\r\n lpFeeAccruedAtoms: bigint;\r\n /** Cumulative atoms already credited to the LP vault. <= lpFeeAccruedAtoms. */\r\n lpFeeWithdrawnAtoms: bigint;\r\n /**\r\n * Cumulative atoms accrued to the insurance/staker leg (monotonic). Claimed\r\n * via WithdrawInsuranceReserveToStake (tag 87), which transfers them to the\r\n * bound stake pool's vault.\r\n *\r\n * ⚠ Tag 87 is Live-only and ResolveMarket is one-way, so any\r\n * accrued-but-unwithdrawn amount is PERMANENTLY FORFEITED once the market\r\n * resolves — WithdrawInsuranceAsset cannot recover it, because this leg is\r\n * unbudgeted by construction. Keepers should crank before resolution.\r\n */\r\n insuranceReserveAccruedAtoms: bigint;\r\n /** Cumulative atoms already pushed to the stake vault. <= insuranceReserveAccruedAtoms. */\r\n insuranceReserveWithdrawnAtoms: bigint;\r\n /**\r\n * Creator's share of T in bps. Default 1600, ceiling MAX_CREATOR_SHARE_BPS\r\n * (3600). Lands in insurance_domain_budget; claimed via\r\n * WithdrawInsuranceAsset (tag 57).\r\n */\r\n creatorShareBps: number;\r\n /** LP vault's share of T in bps. Default 4800, floor MIN_LP_SHARE_BPS (3200). */\r\n lpShareBps: number;\r\n /**\r\n * Insurance/staker share of T in bps. Default 1600, floor\r\n * MIN_INSURANCE_SHARE_BPS (1200). Also absorbs all sub-atom rounding, since\r\n * split_trade_fee computes this leg as the remainder.\r\n */\r\n insuranceShareBps: number;\r\n /**\r\n * Creator's UNCLAIMED trade-fee revenue, in collateral atoms (u64 at\r\n * {@link V17_CREATOR_FEE_CLAIMABLE_OFF} = 568).\r\n *\r\n * This is the honest claimable balance a creator-claim UI should display.\r\n * Before the creator-fee-claim change the creator leg was credited into the\r\n * asset's insurance DOMAIN BUDGET — the loss backstop — so \"creator earned X\"\r\n * had no on-chain representation at all and a claim button was really a\r\n * backstop withdrawal. The leg now lands here instead and leaves the backstop\r\n * alone.\r\n *\r\n * ⚠ NOT MONOTONIC and NOT an accrued/withdrawn pair. Unlike the protocol / LP\r\n * / insurance legs above, this is a single live balance: trades add to it and\r\n * WithdrawCreatorFee (tag 90) is the only thing that subtracts from it. It\r\n * therefore CANNOT be used to derive lifetime creator revenue — only what is\r\n * claimable right now. (Forced by the 10-byte pad budget; see\r\n * V17_CREATOR_FEE_CLAIMABLE_OFF.)\r\n *\r\n * ⚠ Markets created by a pre-upgrade build read `0n` here: bytes 568..576\r\n * were explicit padding, so the value is well-defined rather than garbage,\r\n * and the counter simply accrues fresh after an in-place upgrade.\r\n */\r\n creatorFeeClaimableAtoms: bigint;\r\n}\r\n\r\n/**\r\n * Parse a v17 WrapperConfigV16 block from raw account data.\r\n *\r\n * The config block starts at offset `configOff` (default: V17_HEADER_LEN = 16).\r\n *\r\n * IMPORTANT: v17 uses a completely different account structure from v12.x slabs.\r\n * This function reads the 496-byte wrapper config block directly. It does NOT\r\n * validate the account header magic or version — callers must do that separately.\r\n *\r\n * @param data Raw bytes of the market group account.\r\n * @param configOff Byte offset where the WrapperConfigV16 block starts (default 16).\r\n * @returns Parsed WrapperConfigV17 object.\r\n *\r\n * @example\r\n * ```ts\r\n * const accountInfo = await connection.getAccountInfo(marketGroupPubkey);\r\n * if (!accountInfo) throw new Error(\"account not found\");\r\n * const magic = readU64FromBytes(accountInfo.data, 0);\r\n * if (magic !== V17_MAGIC) throw new Error(\"not a v17 account\");\r\n * const config = parseWrapperConfigV17(accountInfo.data);\r\n * console.log(config.collateralMint.toBase58());\r\n * ```\r\n */\r\nexport function parseWrapperConfigV17(data: Uint8Array, configOff: number = V17_HEADER_LEN): WrapperConfigV17 {\r\n const MIN_LEN = configOff + V17_WRAPPER_CONFIG_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseWrapperConfigV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = configOff;\r\n\r\n // Offsets from the WrapperConfigV16 offset table above\r\n const marketauth = new PublicKey(data.subarray(b + 0, b + 32));\r\n const collateralMint = new PublicKey(data.subarray(b + 32, b + 64));\r\n const secondaryCollateralMint = new PublicKey(data.subarray(b + 64, b + 96));\r\n const maintenanceFeePerSlot = readU128LE(data, b + 96);\r\n const permissionlessMarketInitFee = readU128LE(data, b + 112);\r\n const tradeFeeBps = readU64LE(data, b + 128);\r\n const permissionlessResolveStaleSlots = readU64LE(data, b + 136);\r\n const forceCloseDelaySlots = readU64LE(data, b + 144);\r\n const lastGoodOracleSlot = readU64LE(data, b + 152);\r\n const insuranceWithdrawDepositRemaining = readU128LE(data, b + 160);\r\n const insuranceWithdrawMaxBps = readU16LE(data, b + 176);\r\n const liquidationCrankerFeeShareBps = readU16LE(data, b + 178);\r\n const maintenanceCrankerFeeShareBps = readU16LE(data, b + 180);\r\n const backingTradeFeeBpsLong = readU16LE(data, b + 182);\r\n const unitScale = readU32LE(data, b + 184);\r\n const confFilterBps = readU16LE(data, b + 188);\r\n const backingTradeFeeBpsShort = readU16LE(data, b + 190);\r\n const insuranceWithdrawDepositsOnly = readU8(data, b + 192);\r\n const oracleMode = readU8(data, b + 193);\r\n const oracleLegCount = readU8(data, b + 194);\r\n const oracleLegFlags = readU8(data, b + 195);\r\n const invert = readU8(data, b + 196);\r\n // _padding0 at b+197\r\n const freeMarketSlotCount = readU16LE(data, b + 198);\r\n const insuranceWithdrawCooldownSlots = readU64LE(data, b + 200);\r\n const lastInsuranceWithdrawSlot = readU64LE(data, b + 208);\r\n const maxStalenessSecs = readU64LE(data, b + 216);\r\n const hybridSoftStaleSlots = readU64LE(data, b + 224);\r\n const markEwmaE6 = readU64LE(data, b + 232);\r\n const markEwmaLastSlot = readU64LE(data, b + 240);\r\n const markEwmaHalflifeSlots = readU64LE(data, b + 248);\r\n const markMinFee = readU64LE(data, b + 256);\r\n const oracleTargetPriceE6 = readU64LE(data, b + 264);\r\n const oracleTargetPublishTime = readI64LE(data, b + 272); // i64 in WrapperConfigV16 (matches parseAssetOracleProfileV17)\r\n\r\n // oracle_leg_feeds: [[u8;32];3] at b+280, 96 bytes total\r\n const ORACLE_LEG_CAP = 3;\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 280 + i * 32, b + 280 + (i + 1) * 32)));\r\n }\r\n\r\n // oracle_leg_prices_e6: [u64;3] at b+376\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 376 + i * 8));\r\n }\r\n\r\n // oracle_leg_publish_times: [i64;3] at b+400\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 400 + i * 8));\r\n }\r\n\r\n // Tail policy fields at b+424\r\n const backingTradeFeePolicyCount = readU16LE(data, b + 424);\r\n const backingTradeFeeInsuranceShareBpsLong = readU16LE(data, b + 426);\r\n const backingTradeFeeInsuranceShareBpsShort = readU16LE(data, b + 428);\r\n const feeRedirectToMarket0Bps = readU16LE(data, b + 430);\r\n\r\n // Protocol-fee program change (additive tail at b+432, WRAPPER_CONFIG_LEN 432 -> 496).\r\n const protocolFeeAuthority = new PublicKey(data.subarray(b + 432, b + 464));\r\n const protocolFeeAccruedAtoms = readU128LE(data, b + 464);\r\n const protocolFeeWithdrawnAtoms = readU128LE(data, b + 480);\r\n\r\n // Fee-collection split (additive tail at b+496, WRAPPER_CONFIG_LEN 496 -> 576).\r\n // ORDER IS LOAD-BEARING: the four u128 counters precede the three u16 shares\r\n // because bytemuck::Pod forbids implicit padding — see V17_WRAPPER_CONFIG_LEN.\r\n const lpFeeAccruedAtoms = readU128LE(data, b + 496);\r\n const lpFeeWithdrawnAtoms = readU128LE(data, b + 512);\r\n const insuranceReserveAccruedAtoms = readU128LE(data, b + 528);\r\n const insuranceReserveWithdrawnAtoms = readU128LE(data, b + 544);\r\n const creatorShareBps = readU16LE(data, b + 560);\r\n const lpShareBps = readU16LE(data, b + 562);\r\n const insuranceShareBps = readU16LE(data, b + 564);\r\n // _padding_split [u8;2] at b+566 .. b+568 — explicit, not read.\r\n\r\n // Creator fee claim (2026-07-23): carved out of the old 10-byte pad IN PLACE.\r\n // WRAPPER_CONFIG_LEN is STILL 576 — nothing above this line moved.\r\n const creatorFeeClaimableAtoms = readU64LE(data, b + V17_CREATOR_FEE_CLAIMABLE_OFF);\r\n\r\n return {\r\n marketauth,\r\n collateralMint,\r\n secondaryCollateralMint,\r\n maintenanceFeePerSlot,\r\n permissionlessMarketInitFee,\r\n tradeFeeBps,\r\n permissionlessResolveStaleSlots,\r\n forceCloseDelaySlots,\r\n lastGoodOracleSlot,\r\n insuranceWithdrawDepositRemaining,\r\n insuranceWithdrawMaxBps,\r\n liquidationCrankerFeeShareBps,\r\n maintenanceCrankerFeeShareBps,\r\n backingTradeFeeBpsLong,\r\n unitScale,\r\n confFilterBps,\r\n backingTradeFeeBpsShort,\r\n insuranceWithdrawDepositsOnly,\r\n oracleMode,\r\n oracleLegCount,\r\n oracleLegFlags,\r\n invert,\r\n freeMarketSlotCount,\r\n insuranceWithdrawCooldownSlots,\r\n lastInsuranceWithdrawSlot,\r\n maxStalenessSecs,\r\n hybridSoftStaleSlots,\r\n markEwmaE6,\r\n markEwmaLastSlot,\r\n markEwmaHalflifeSlots,\r\n markMinFee,\r\n oracleTargetPriceE6,\r\n oracleTargetPublishTime,\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n backingTradeFeePolicyCount,\r\n backingTradeFeeInsuranceShareBpsLong,\r\n backingTradeFeeInsuranceShareBpsShort,\r\n feeRedirectToMarket0Bps,\r\n protocolFeeAuthority,\r\n protocolFeeAccruedAtoms,\r\n protocolFeeWithdrawnAtoms,\r\n lpFeeAccruedAtoms,\r\n lpFeeWithdrawnAtoms,\r\n insuranceReserveAccruedAtoms,\r\n insuranceReserveWithdrawnAtoms,\r\n creatorShareBps,\r\n lpShareBps,\r\n insuranceShareBps,\r\n creatorFeeClaimableAtoms,\r\n };\r\n}\r\n\r\n/**\r\n * Parsed AssetOracleProfileV16 — the 400-byte per-asset profile in a v17 asset slot.\r\n *\r\n * Field offsets (SBF alignment, verified against v16_program.rs AssetOracleProfileV16):\r\n * 0 oracle_mode u8\r\n * 1 oracle_leg_count u8\r\n * 2 oracle_leg_flags u8\r\n * 3 invert u8\r\n * 4 unit_scale u32\r\n * 8 conf_filter_bps u16\r\n * 10 backing_trade_fee_bps_long u16\r\n * 12 backing_trade_fee_bps_short u16\r\n * 14 backing_trade_fee_insurance_share_bps_long u16\r\n * 16 backing_trade_fee_insurance_share_bps_short u16\r\n * 18 _padding0 [u8;6]\r\n * 24 insurance_authority [32]\r\n * 56 insurance_operator [32]\r\n * 88 backing_bucket_authority [32]\r\n * 120 oracle_authority [32]\r\n * 152 max_staleness_secs u64\r\n * 160 hybrid_soft_stale_slots u64\r\n * 168 mark_ewma_e6 u64\r\n * 176 mark_ewma_last_slot u64\r\n * 184 mark_ewma_halflife_slots u64\r\n * 192 mark_min_fee u64\r\n * 200 oracle_target_price_e6 u64\r\n * 208 oracle_target_publish_time i64\r\n * 216 last_good_oracle_slot u64\r\n * 224 oracle_leg_feeds [[u8;32];3] (96B)\r\n * 320 oracle_leg_prices_e6 [u64;3] (24B)\r\n * 344 oracle_leg_publish_times [i64;3] (24B)\r\n * 368 asset_admin [32] ← v17 NEW\r\n * Total: 400\r\n */\r\nexport interface AssetOracleProfileV17 {\r\n oracleMode: number;\r\n oracleLegCount: number;\r\n oracleLegFlags: number;\r\n invert: number;\r\n unitScale: number;\r\n confFilterBps: number;\r\n backingTradeFeeBpsLong: number;\r\n backingTradeFeeBpsShort: number;\r\n backingTradeFeeInsuranceShareBpsLong: number;\r\n backingTradeFeeInsuranceShareBpsShort: number;\r\n insuranceAuthority: PublicKey;\r\n insuranceOperator: PublicKey;\r\n backingBucketAuthority: PublicKey;\r\n oracleAuthority: PublicKey;\r\n maxStalenessSecs: bigint;\r\n hybridSoftStaleSlots: bigint;\r\n markEwmaE6: bigint;\r\n markEwmaLastSlot: bigint;\r\n markEwmaHalflifeSlots: bigint;\r\n markMinFee: bigint;\r\n oracleTargetPriceE6: bigint;\r\n oracleTargetPublishTime: bigint;\r\n lastGoodOracleSlot: bigint;\r\n oracleLegFeeds: PublicKey[];\r\n oracleLegPricesE6: bigint[];\r\n oracleLegPublishTimes: bigint[];\r\n /** v17 NEW: asset_admin pubkey at offset 368. */\r\n assetAdmin: PublicKey;\r\n}\r\n\r\n/**\r\n * Parse a v17 AssetOracleProfileV16 block from raw account data.\r\n *\r\n * @param data Raw bytes containing the profile block.\r\n * @param profileOff Byte offset where the AssetOracleProfileV16 starts.\r\n * @returns Parsed AssetOracleProfileV17 object.\r\n */\r\nexport function parseAssetOracleProfileV17(data: Uint8Array, profileOff: number): AssetOracleProfileV17 {\r\n const MIN_LEN = profileOff + V17_ASSET_ORACLE_PROFILE_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseAssetOracleProfileV17: data too short — need ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n\r\n const b = profileOff;\r\n const ORACLE_LEG_CAP = 3;\r\n\r\n const oracleLegFeeds: PublicKey[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegFeeds.push(new PublicKey(data.subarray(b + 224 + i * 32, b + 224 + (i + 1) * 32)));\r\n }\r\n\r\n const oracleLegPricesE6: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPricesE6.push(readU64LE(data, b + 320 + i * 8));\r\n }\r\n\r\n const oracleLegPublishTimes: bigint[] = [];\r\n for (let i = 0; i < ORACLE_LEG_CAP; i++) {\r\n oracleLegPublishTimes.push(readI64LE(data, b + 344 + i * 8));\r\n }\r\n\r\n return {\r\n oracleMode: readU8(data, b + 0),\r\n oracleLegCount: readU8(data, b + 1),\r\n oracleLegFlags: readU8(data, b + 2),\r\n invert: readU8(data, b + 3),\r\n unitScale: readU32LE(data, b + 4),\r\n confFilterBps: readU16LE(data, b + 8),\r\n backingTradeFeeBpsLong: readU16LE(data, b + 10),\r\n backingTradeFeeBpsShort: readU16LE(data, b + 12),\r\n backingTradeFeeInsuranceShareBpsLong: readU16LE(data, b + 14),\r\n backingTradeFeeInsuranceShareBpsShort: readU16LE(data, b + 16),\r\n insuranceAuthority: new PublicKey(data.subarray(b + 24, b + 56)),\r\n insuranceOperator: new PublicKey(data.subarray(b + 56, b + 88)),\r\n backingBucketAuthority: new PublicKey(data.subarray(b + 88, b + 120)),\r\n oracleAuthority: new PublicKey(data.subarray(b + 120, b + 152)),\r\n maxStalenessSecs: readU64LE(data, b + 152),\r\n hybridSoftStaleSlots: readU64LE(data, b + 160),\r\n markEwmaE6: readU64LE(data, b + 168),\r\n markEwmaLastSlot: readU64LE(data, b + 176),\r\n markEwmaHalflifeSlots: readU64LE(data, b + 184),\r\n markMinFee: readU64LE(data, b + 192),\r\n oracleTargetPriceE6: readU64LE(data, b + 200),\r\n oracleTargetPublishTime: readI64LE(data, b + 208),\r\n lastGoodOracleSlot: readU64LE(data, b + 216),\r\n oracleLegFeeds,\r\n oracleLegPricesE6,\r\n oracleLegPublishTimes,\r\n assetAdmin: new PublicKey(data.subarray(b + 368, b + 400)),\r\n };\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer contains a v17 percolator account.\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if magic == V17_MAGIC and version == V17_EXPECTED_VERSION.\r\n */\r\nexport function isV17Account(data: Uint8Array): boolean {\r\n if (data.length < 10) return false;\r\n const magic = readU64LE(data, 0);\r\n const version = readU16LE(data, 8);\r\n return magic === V17_MAGIC && version === V17_EXPECTED_VERSION;\r\n}\r\n\r\n/**\r\n * Check if a raw account buffer is a v17 percolator MARKET account.\r\n *\r\n * Stricter than {@link isV17Account}: requires both that the account is a valid\r\n * v17 account (magic + version) AND that the kind byte at offset 10 is\r\n * {@link V17_KIND_MARKET}. Portfolio / ledger / registry accounts share the same\r\n * magic+version and so pass `isV17Account`, but they are NOT markets and do not\r\n * carry a WrapperConfigV16 block — market discovery must gate on this (#264).\r\n *\r\n * @param data Raw account bytes.\r\n * @returns true if the account is a v17 account whose kind == KIND_MARKET (1).\r\n */\r\nexport function isV17MarketAccount(data: Uint8Array): boolean {\r\n if (data.length < V17_KIND_OFF + 1) return false;\r\n if (!isV17Account(data)) return false;\r\n return data[V17_KIND_OFF] === V17_KIND_MARKET;\r\n}\r\n\r\n// =============================================================================\r\n// V17 OI parser\r\n// =============================================================================\r\n\r\n/**\r\n * Relative offset of insurance within MarketGroupV16HeaderAccount:\r\n * market_group_id[32] + V16ConfigAccount[249] + asset_slot_capacity(V16PodU32)[4] + vault(V16PodU128)[16] = 301\r\n */\r\nconst V17_HEADER_INSURANCE_OFF = 301;\r\n\r\n/**\r\n * Wrapper T size preceding EngineAssetSlotV16Account in each Market slot.\r\n * Wrapper T = 512 bytes (AssetOracleProfileV16Account=400 + 112 more).\r\n */\r\nconst V17_ASSET_SLOT_WRAPPER_SIZE = 512;\r\n\r\n/**\r\n * Offsets of oi_eff_long_q and oi_eff_short_q within AssetStateV16Account\r\n * (the first sub-struct of EngineAssetSlotV16Account, at slot offset = wrapper size):\r\n * market_id[8] + retired_slot[8] + lifecycle[1] + raw_oracle_target_price[8]\r\n * + effective_price[8] + fund_px_last[8] + slot_last[8] = 49 bytes header\r\n * then 14 × u128 fields before oi_eff_long_q → 49 + 14×16 = 273\r\n * oi_eff_short_q follows at 273 + 16 = 289\r\n */\r\nconst V17_ASSET_STATE_OI_LONG_REL = 273;\r\nconst V17_ASSET_STATE_OI_SHORT_REL = 289;\r\n\r\n/**\r\n * Aggregated open-interest parsed from a v17 market group account.\r\n *\r\n * The v17 engine stores OI per-asset (per Market slot) as oi_eff_long_q and\r\n * oi_eff_short_q in AssetStateV16Account. This parser sums across all capacity\r\n * slots in the account and also returns per-asset breakdown.\r\n *\r\n * All quantities are in token micro-units (raw, not scaled by decimals).\r\n */\r\nexport interface V17MarketGroupOI {\r\n /** Group-level insurance reserve (u128, micro-units) */\r\n insuranceBalance: bigint;\r\n /** Sum of oi_eff_long_q across all asset slots */\r\n totalLongOiQ: bigint;\r\n /** Sum of oi_eff_short_q across all asset slots */\r\n totalShortOiQ: bigint;\r\n /** Per-slot breakdown (only slots where at least one side is non-zero) */\r\n assets: Array<{\r\n assetIndex: number;\r\n oiEffLongQ: bigint;\r\n oiEffShortQ: bigint;\r\n }>;\r\n}\r\n\r\n/**\r\n * Parse open-interest fields from a v17 market group account.\r\n *\r\n * Reads the group-level insurance balance from MarketGroupV16HeaderAccount and\r\n * iterates every asset-slot capacity to accumulate oi_eff_long_q / oi_eff_short_q\r\n * from AssetStateV16Account (the first sub-struct of EngineAssetSlotV16Account\r\n * which follows the 512-byte wrapper T at the start of each slot).\r\n *\r\n * Relative offsets verified with `offset_of!` against the engine's own `#[repr(C)]`\r\n * structs (`percolator/src/v16.rs`): `MarketGroupV16HeaderAccount::insurance` @ 301,\r\n * `AssetStateV16Account::oi_eff_long_q` @ 273, `oi_eff_short_q` @ 289. Every\r\n * `V16Pod*` field is an align-1 `[u8; N]` and the structs derive `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are exact byte offsets.\r\n *\r\n * The absolute offsets below follow from the CURRENT wrapper layout —\r\n * WRAPPER_CONFIG_LEN = 576 and V17_MARKET_GROUP_OFF = 16 + 576 = 592\r\n * (`v16_program.rs` HEADER_LEN/WRAPPER_CONFIG_LEN, with a compile-time\r\n * `assert!(size_of::() == WRAPPER_CONFIG_LEN)`):\r\n * - slots base: V17_MARKET_GROUP_OFF(592) + V17_MARKET_GROUP_LEN(758) = 1350\r\n * - insurance: 592 + 301 = 893\r\n * - oi_eff_long_q(i): 1350 + i×1797 + 512 + 273 = 2135 + i×1797\r\n * - oi_eff_short_q(i): 1350 + i×1797 + 512 + 289 = 2151 + i×1797\r\n *\r\n * (This block previously quoted 432/496 and 448/512 from a pre-fee-split layout,\r\n * giving insurance @ 813. The CODE was always correct — it composes the named\r\n * constants — but the stated numbers were stale. Verified against the first real\r\n * v17 market on the new devnet deployment.)\r\n *\r\n * @param data Raw bytes of the v17 market group account.\r\n * @returns Parsed V17MarketGroupOI — zero OI when no active positions exist.\r\n * @throws Error if the buffer is not a valid v17 market account or is too short.\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketGroupPk);\r\n * if (!isV17MarketAccount(new Uint8Array(info.data))) throw new Error(\"not v17\");\r\n * const oi = parseMarketGroupV17OI(new Uint8Array(info.data));\r\n * console.log(`long OI: ${oi.totalLongOiQ}, short OI: ${oi.totalShortOiQ}`);\r\n * ```\r\n */\r\nexport function parseMarketGroupV17OI(data: Uint8Array): V17MarketGroupOI {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseMarketGroupV17OI: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseMarketGroupV17OI: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n // Read insurance u128 from MarketGroupV16HeaderAccount at absolute offset 813.\r\n const insuranceOff = V17_MARKET_GROUP_OFF + V17_HEADER_INSURANCE_OFF;\r\n const insuranceBalance = readU128LE(data, insuranceOff);\r\n\r\n // Iterate asset slots. Slots start immediately after MarketGroupV16HeaderAccount.\r\n const slotsBase = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN; // 1350 post-fee-split\r\n const numSlots = Math.floor(\r\n (data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN,\r\n );\r\n\r\n let totalLongOiQ = 0n;\r\n let totalShortOiQ = 0n;\r\n const assets: V17MarketGroupOI[\"assets\"] = [];\r\n\r\n for (let i = 0; i < numSlots; i++) {\r\n const slotBase = slotsBase + i * V17_MARKET_ASSET_SLOT_LEN;\r\n // EngineAssetSlotV16Account starts at slotBase + wrapper-T size (512).\r\n // AssetStateV16Account is the first field of EngineAssetSlotV16Account (offset 0).\r\n const longOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_LONG_REL;\r\n const shortOff =\r\n slotBase + V17_ASSET_SLOT_WRAPPER_SIZE + V17_ASSET_STATE_OI_SHORT_REL;\r\n\r\n // Guard against a truncated buffer (should not happen on well-formed accounts).\r\n if (shortOff + 16 > data.length) break;\r\n\r\n const oiEffLongQ = readU128LE(data, longOff);\r\n const oiEffShortQ = readU128LE(data, shortOff);\r\n\r\n totalLongOiQ += oiEffLongQ;\r\n totalShortOiQ += oiEffShortQ;\r\n\r\n if (oiEffLongQ !== 0n || oiEffShortQ !== 0n) {\r\n assets.push({ assetIndex: i, oiEffLongQ, oiEffShortQ });\r\n }\r\n }\r\n\r\n return { insuranceBalance, totalLongOiQ, totalShortOiQ, assets };\r\n}\r\n\r\n// =============================================================================\r\n// V17 account decoders (DESYNC fixes — new standalone account types)\r\n// =============================================================================\r\n\r\n/** Header length for all v17 standalone accounts (magic:u64 + version:u16 + kind:u8 + reserved:5 = 16). */\r\nconst V17_ACCOUNT_HEADER_LEN = 16;\r\nconst V17_KIND_PORTFOLIO = 2;\r\nconst V17_KIND_LP_VAULT_REGISTRY = 5;\r\nconst V17_KIND_LP_REDEMPTION = 6;\r\n\r\nfunction assertV17StandaloneHeader(\r\n data: Uint8Array,\r\n parserName: string,\r\n expectedKind: number,\r\n): void {\r\n if (data.length < V17_ACCOUNT_HEADER_LEN) {\r\n throw new Error(`${parserName}: data too short (${data.length} < ${V17_ACCOUNT_HEADER_LEN})`);\r\n }\r\n const magic = readU64LE(data, 0);\r\n if (magic !== V17_MAGIC) {\r\n throw new Error(`${parserName}: invalid v17 magic`);\r\n }\r\n const version = readU16LE(data, 8);\r\n if (version !== V17_EXPECTED_VERSION) {\r\n throw new Error(`${parserName}: invalid v17 version (${version} !== ${V17_EXPECTED_VERSION})`);\r\n }\r\n const kind = readU8(data, 10);\r\n if (kind !== expectedKind) {\r\n throw new Error(`${parserName}: invalid v17 account kind (${kind} !== ${expectedKind})`);\r\n }\r\n}\r\n\r\n// PortfolioAccountV16Account field layout (relative to HEADER_LEN=16).\r\n// ProvenanceHeaderV16Account: market_group_id[32]+portfolio_account_id[32]+owner[32]+version[2]+layout_discriminator[2] = 100 bytes.\r\nconst PF_PROVENANCE_OFF = V17_ACCOUNT_HEADER_LEN; // 16\r\nconst PF_PROVENANCE_MARKET_GROUP_OFF = PF_PROVENANCE_OFF; // 16..48\r\nconst PF_PROVENANCE_ACCOUNT_ID_OFF = PF_PROVENANCE_OFF + 32; // 48..80\r\nconst PF_PROVENANCE_OWNER_OFF = PF_PROVENANCE_OFF + 64; // 80..112\r\nconst PF_PROVENANCE_VERSION_OFF = PF_PROVENANCE_OFF + 96; // 112..114\r\nconst PF_PROVENANCE_DISC_OFF = PF_PROVENANCE_OFF + 98; // 114..116\r\nconst PF_BODY_OFF = PF_PROVENANCE_OFF + 100; // 116 — after provenance header\r\nconst PF_OWNER_OFF = PF_BODY_OFF; // [u8;32]\r\nconst PF_CAPITAL_OFF = PF_BODY_OFF + 32; // V16PodU128\r\nconst PF_PNL_OFF = PF_BODY_OFF + 48; // V16PodI128\r\nconst PF_RESERVED_PNL_OFF = PF_BODY_OFF + 64; // V16PodU128\r\nconst PF_RESIDUAL_LOSS_OFF = PF_BODY_OFF + 80; // V16PodU128\r\nconst PF_RESIDUAL_PRINCIPAL_OFF = PF_BODY_OFF + 96; // V16PodU128\r\nconst PF_RESIDUAL_RECEIVED_OFF = PF_BODY_OFF + 112; // V16PodU128\r\nconst PF_FEE_CREDITS_OFF = PF_BODY_OFF + 128; // V16PodI128\r\nconst PF_CANCEL_ESCROW_OFF = PF_BODY_OFF + 144; // V16PodU128\r\nconst PF_LAST_FEE_SLOT_OFF = PF_BODY_OFF + 160; // V16PodU64\r\nconst PF_ACTIVE_BITMAP_OFF = PF_BODY_OFF + 168; // [V16PodU64; 1]\r\n// PortfolioLegV16Account (144 bytes each):\r\n// active(1)+asset_index(4)+market_id(8)+side(1)+basis_pos_q(16)+a_basis(16)+k_snap(16)+\r\n// f_snap(16)+epoch_snap(8)+loss_weight(16)+b_snap(16)+b_rem(16)+b_epoch_snap(8)+b_stale(1)+stale(1) = 144\r\nconst PF_LEG_SIZE = 144;\r\nconst PF_LEGS_OFF = PF_BODY_OFF + 176; // [PortfolioLegV16Account; 16]\r\nconst PF_LEGS_COUNT = 16;\r\n// PortfolioSourceDomainV16Account (196 bytes each):\r\n// domain(4)+market_id(8)+13×u128(16 each)=208? Let me recount:\r\n// domain(4)+source_claim_market_id(8)+source_claim_bound_num(16)+source_claim_liened_num(16)+\r\n// source_claim_counterparty_liened_num(16)+source_claim_insurance_liened_num(16)+\r\n// source_lien_effective_reserved(16)+source_lien_counterparty_backing_num(16)+\r\n// source_lien_insurance_backing_num(16)+source_lien_fee_last_slot(8)+\r\n// source_claim_impaired_num(16)+source_lien_impaired_effective_reserved(16)+\r\n// source_lien_capital_at_risk_fee_revenue(16)+source_lien_impaired_capital_at_risk_fee_revenue(16)\r\n// = 4+8+16+16+16+16+16+16+16+8+16+16+16+16 = 196 bytes\r\nconst PF_SOURCE_DOMAIN_SIZE = 196;\r\nconst PF_SOURCE_DOMAINS_OFF = PF_LEGS_OFF + PF_LEGS_COUNT * PF_LEG_SIZE; // 176+2304=2480 (rel to header)\r\nconst PF_SOURCE_DOMAINS_CAP = 32; // PORTFOLIO_SOURCE_DOMAIN_CAP = 2 * V16_MAX_PORTFOLIO_ASSETS_N = 32\r\n// HealthCertV16Account (121 bytes):\r\nconst PF_HEALTH_CERT_OFF = PF_SOURCE_DOMAINS_OFF + PF_SOURCE_DOMAINS_CAP * PF_SOURCE_DOMAIN_SIZE;\r\n// stale_state(1)+b_stale_state(1)+rebalance_lock(1)+liquidation_lock(1) = 4 bytes after HealthCert\r\n// CloseProgressLedgerV16Account (188 bytes):\r\n// active(1)+finalized(1)+canceled(1)+close_id(8)+asset_index(4)+market_id(8)+domain_side(1)+\r\n// gross_loss(16)+drift_ref_slot(8)+max_close_slot(8)+support(16)+junior(16)+insurance(16)+\r\n// b_loss(16)+explicit(16)+adl(16)+drift_consumed(16)+residual_remaining(16) = 188\r\n// ResolvedPayoutReceiptV16Account (66 bytes):\r\n// prior_bound(16)+live_released(16)+terminal(16)+paid(16)+present(1)+finalized(1) = 66\r\n\r\n// PortfolioMatcherConfigV16 (104 bytes): matcher_program(32)+matcher_context(32)+\r\n// matcher_delegate(32)+enabled(8). This is a separate trailing region after\r\n// PortfolioAccountV16Account, not part of it (see v16_program.rs PORTFOLIO_MATCHER_CONFIG_OFF\r\n// = HEADER_LEN + PORTFOLIO_STATE_LEN). Computed from the END of the account\r\n// (V17_PORTFOLIO_ACCOUNT_LEN - 104) rather than chaining through HealthCert/locks/\r\n// CloseProgress/ResolvedPayoutReceipt above — none of those intermediate regions are\r\n// actually decoded by parsePortfolioV17, and the CloseProgressLedgerV16Account size\r\n// noted above (188) does not even match its own field breakdown (sums to 184; see\r\n// percolator-keeper's crank.ts comment, which independently confirms 184 and computes\r\n// the same anchor-from-the-end offset).\r\nconst PF_MATCHER_CONFIG_LEN = 104;\r\nconst PF_MATCHER_PROGRAM_OFF = V17_PORTFOLIO_ACCOUNT_LEN - PF_MATCHER_CONFIG_LEN; // 9243\r\nconst PF_MATCHER_CONTEXT_OFF = PF_MATCHER_PROGRAM_OFF + 32; // 9275\r\nconst PF_MATCHER_DELEGATE_OFF = PF_MATCHER_CONTEXT_OFF + 32; // 9307\r\nconst PF_MATCHER_ENABLED_OFF = PF_MATCHER_DELEGATE_OFF + 32; // 9339\r\n\r\n/** Per-leg decoded data returned by parsePortfolioV17. */\r\nexport interface PortfolioLegV17 {\r\n active: boolean;\r\n assetIndex: number;\r\n marketId: bigint;\r\n /** 0 = long, 1 = short */\r\n side: number;\r\n basisPosQ: bigint;\r\n aBasis: bigint;\r\n kSnap: bigint;\r\n fSnap: bigint;\r\n epochSnap: bigint;\r\n lossWeight: bigint;\r\n bSnap: bigint;\r\n bRem: bigint;\r\n bEpochSnap: bigint;\r\n bStale: boolean;\r\n stale: boolean;\r\n}\r\n\r\n/** Per source-domain slot returned by parsePortfolioV17. */\r\nexport interface PortfolioSourceDomainV17 {\r\n domain: number;\r\n sourceClaimMarketId: bigint;\r\n sourceClaimBoundNum: bigint;\r\n sourceClaimLienedNum: bigint;\r\n sourceClaimCounterpartyLienedNum: bigint;\r\n sourceClaimInsuranceLienedNum: bigint;\r\n sourceLienEffectiveReserved: bigint;\r\n sourceLienCounterpartyBackingNum: bigint;\r\n sourceLienInsuranceBackingNum: bigint;\r\n sourceLienFeeLastSlot: bigint;\r\n sourceClaimImpairedNum: bigint;\r\n sourceLienImpairedEffectiveReserved: bigint;\r\n sourceLienCapitalAtRiskFeeRevenue: bigint;\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: bigint;\r\n}\r\n\r\n/** Decoded v17 PortfolioAccountV16Account. */\r\nexport interface PortfolioV17 {\r\n /** Market group this portfolio belongs to. */\r\n marketGroupId: PublicKey;\r\n /** Portfolio account identity pubkey (immutable PDA). */\r\n portfolioAccountId: PublicKey;\r\n /** Owner wallet pubkey from the provenance header. */\r\n provenanceOwner: PublicKey;\r\n /** Portfolio owner (matches provenanceOwner for valid accounts). */\r\n owner: PublicKey;\r\n /** Collateral capital in atoms (u128). */\r\n capital: bigint;\r\n /** Unrealised P&L in atoms (i128). */\r\n pnl: bigint;\r\n /** Capital reserved for pending payout (u128). */\r\n reservedPnl: bigint;\r\n /** Genesis farming: cumulative crystallized loss atoms (u128). */\r\n residualCrystallizedLossAtomsTotal: bigint;\r\n /** Genesis farming: cumulative spent principal atoms (u128). */\r\n residualSpentPrincipalAtomsTotal: bigint;\r\n /** Genesis farming: cumulative received atoms (u128). */\r\n residualReceivedAtomsTotal: bigint;\r\n /** Fee credits (i128, can be negative). */\r\n feeCredits: bigint;\r\n /** Cancel-deposit escrow holding (u128). */\r\n cancelDepositEscrow: bigint;\r\n /** Slot when fees were last accrued. */\r\n lastFeeSlot: bigint;\r\n /** Bitmap of active leg slots (one u64 word for 16-asset portfolios). */\r\n activeBitmap: bigint;\r\n /** All 16 position leg slots (active or empty). */\r\n legs: PortfolioLegV17[];\r\n /** Up to 32 source-domain entries (sparse; unoccupied slots have domain=0 and all-zero fields). */\r\n sourceDomains: PortfolioSourceDomainV17[];\r\n /** External matcher program this portfolio routes trades through (PublicKey.default if unset). */\r\n matcherProgram: PublicKey;\r\n /** Matcher context account for matcherProgram (PublicKey.default if unset). */\r\n matcherContext: PublicKey;\r\n /** PDA the wrapper signs CPI calls to matcherProgram with (PublicKey.default if unset). */\r\n matcherDelegate: PublicKey;\r\n /** Whether the external matcher is enabled for this portfolio (SetMatcherConfig). */\r\n matcherEnabled: boolean;\r\n}\r\n\r\n/**\r\n * Parse a v17 PortfolioAccountV16Account from raw account data.\r\n * Total account size: HEADER_LEN(16) + sizeof(PortfolioAccountV16Account).\r\n *\r\n * @param data - Raw account bytes from `connection.getAccountInfo`.\r\n * @returns Decoded portfolio state.\r\n * @throws If data is too short or magic does not match.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(portfolioPubkey);\r\n * const portfolio = parsePortfolioV17(new Uint8Array(info!.data));\r\n * console.log('capital:', portfolio.capital);\r\n * ```\r\n */\r\nexport function parsePortfolioV17(data: Uint8Array): PortfolioV17 {\r\n // Minimum size check: header(16) + provenance(100) + owner/capital/pnl/reserved_pnl.\r\n const MIN_PORTFOLIO_BYTES = PF_RESERVED_PNL_OFF + 16;\r\n if (data.length < MIN_PORTFOLIO_BYTES) {\r\n throw new Error(`parsePortfolioV17: data too short (${data.length} < ${MIN_PORTFOLIO_BYTES})`);\r\n }\r\n assertV17StandaloneHeader(data, \"parsePortfolioV17\", V17_KIND_PORTFOLIO);\r\n\r\n // Provenance header\r\n const marketGroupId = new PublicKey(data.subarray(PF_PROVENANCE_MARKET_GROUP_OFF, PF_PROVENANCE_MARKET_GROUP_OFF + 32));\r\n const portfolioAccountId = new PublicKey(data.subarray(PF_PROVENANCE_ACCOUNT_ID_OFF, PF_PROVENANCE_ACCOUNT_ID_OFF + 32));\r\n const provenanceOwner = new PublicKey(data.subarray(PF_PROVENANCE_OWNER_OFF, PF_PROVENANCE_OWNER_OFF + 32));\r\n\r\n // Body fields\r\n const owner = new PublicKey(data.subarray(PF_OWNER_OFF, PF_OWNER_OFF + 32));\r\n const capital = readU128LE(data, PF_CAPITAL_OFF);\r\n const pnl = readI128LE(data, PF_PNL_OFF);\r\n const reservedPnl = readU128LE(data, PF_RESERVED_PNL_OFF);\r\n\r\n const residualCrystallizedLossAtomsTotal = data.length >= PF_RESIDUAL_LOSS_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_LOSS_OFF) : 0n;\r\n const residualSpentPrincipalAtomsTotal = data.length >= PF_RESIDUAL_PRINCIPAL_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_PRINCIPAL_OFF) : 0n;\r\n const residualReceivedAtomsTotal = data.length >= PF_RESIDUAL_RECEIVED_OFF + 16\r\n ? readU128LE(data, PF_RESIDUAL_RECEIVED_OFF) : 0n;\r\n const feeCredits = data.length >= PF_FEE_CREDITS_OFF + 16\r\n ? readI128LE(data, PF_FEE_CREDITS_OFF) : 0n;\r\n const cancelDepositEscrow = data.length >= PF_CANCEL_ESCROW_OFF + 16\r\n ? readU128LE(data, PF_CANCEL_ESCROW_OFF) : 0n;\r\n const lastFeeSlot = data.length >= PF_LAST_FEE_SLOT_OFF + 8\r\n ? readU64LE(data, PF_LAST_FEE_SLOT_OFF) : 0n;\r\n const activeBitmap = data.length >= PF_ACTIVE_BITMAP_OFF + 8\r\n ? readU64LE(data, PF_ACTIVE_BITMAP_OFF) : 0n;\r\n\r\n // Legs\r\n const legs: PortfolioLegV17[] = [];\r\n for (let i = 0; i < PF_LEGS_COUNT; i++) {\r\n const b = PF_LEGS_OFF + i * PF_LEG_SIZE;\r\n if (data.length < b + PF_LEG_SIZE) break;\r\n legs.push({\r\n active: data[b] !== 0,\r\n assetIndex: readU32LE(data, b + 1),\r\n marketId: readU64LE(data, b + 5),\r\n side: data[b + 13],\r\n basisPosQ: readI128LE(data, b + 14),\r\n aBasis: readU128LE(data, b + 30),\r\n kSnap: readI128LE(data, b + 46),\r\n fSnap: readI128LE(data, b + 62),\r\n epochSnap: readU64LE(data, b + 78),\r\n lossWeight: readU128LE(data, b + 86),\r\n bSnap: readU128LE(data, b + 102),\r\n bRem: readU128LE(data, b + 118),\r\n bEpochSnap: readU64LE(data, b + 134),\r\n bStale: data[b + 142] !== 0,\r\n stale: data[b + 143] !== 0,\r\n });\r\n }\r\n\r\n // Source domains\r\n const sourceDomains: PortfolioSourceDomainV17[] = [];\r\n for (let i = 0; i < PF_SOURCE_DOMAINS_CAP; i++) {\r\n const b = PF_SOURCE_DOMAINS_OFF + i * PF_SOURCE_DOMAIN_SIZE;\r\n if (data.length < b + PF_SOURCE_DOMAIN_SIZE) break;\r\n sourceDomains.push({\r\n domain: readU32LE(data, b + 0),\r\n sourceClaimMarketId: readU64LE(data, b + 4),\r\n sourceClaimBoundNum: readU128LE(data, b + 12),\r\n sourceClaimLienedNum: readU128LE(data, b + 28),\r\n sourceClaimCounterpartyLienedNum: readU128LE(data, b + 44),\r\n sourceClaimInsuranceLienedNum: readU128LE(data, b + 60),\r\n sourceLienEffectiveReserved: readU128LE(data, b + 76),\r\n sourceLienCounterpartyBackingNum: readU128LE(data, b + 92),\r\n sourceLienInsuranceBackingNum: readU128LE(data, b + 108),\r\n sourceLienFeeLastSlot: readU64LE(data, b + 124),\r\n sourceClaimImpairedNum: readU128LE(data, b + 132),\r\n sourceLienImpairedEffectiveReserved: readU128LE(data, b + 148),\r\n sourceLienCapitalAtRiskFeeRevenue: readU128LE(data, b + 164),\r\n sourceLienImpairedCapitalAtRiskFeeRevenue: readU128LE(data, b + 180),\r\n });\r\n }\r\n\r\n const matcherProgram = data.length >= PF_MATCHER_PROGRAM_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_PROGRAM_OFF, PF_MATCHER_PROGRAM_OFF + 32))\r\n : PublicKey.default;\r\n const matcherContext = data.length >= PF_MATCHER_CONTEXT_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_CONTEXT_OFF, PF_MATCHER_CONTEXT_OFF + 32))\r\n : PublicKey.default;\r\n const matcherDelegate = data.length >= PF_MATCHER_DELEGATE_OFF + 32\r\n ? new PublicKey(data.subarray(PF_MATCHER_DELEGATE_OFF, PF_MATCHER_DELEGATE_OFF + 32))\r\n : PublicKey.default;\r\n // `enabled` is a u64 the wrapper only ever writes as 0 or 1, and\r\n // read_portfolio_matcher_config (v16_program.rs:1482) returns InvalidAccountData\r\n // for anything > 1. Mirror that instead of coercing any nonzero to true, so a\r\n // corrupt trailer surfaces here rather than being reported as \"matcher enabled\"\r\n // for an account the program itself would refuse to operate on.\r\n let matcherEnabled = false;\r\n if (data.length >= PF_MATCHER_ENABLED_OFF + 8) {\r\n const rawEnabled = readU64LE(data, PF_MATCHER_ENABLED_OFF);\r\n if (rawEnabled > 1n) {\r\n throw new Error(\r\n `parsePortfolioV17: matcher config 'enabled' is ${rawEnabled}, expected 0 or 1`,\r\n );\r\n }\r\n matcherEnabled = rawEnabled === 1n;\r\n }\r\n\r\n return {\r\n marketGroupId,\r\n portfolioAccountId,\r\n provenanceOwner,\r\n owner,\r\n capital,\r\n pnl,\r\n reservedPnl,\r\n residualCrystallizedLossAtomsTotal,\r\n residualSpentPrincipalAtomsTotal,\r\n residualReceivedAtomsTotal,\r\n feeCredits,\r\n cancelDepositEscrow,\r\n lastFeeSlot,\r\n activeBitmap,\r\n legs,\r\n sourceDomains,\r\n matcherProgram,\r\n matcherContext,\r\n matcherDelegate,\r\n matcherEnabled,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpVaultRegistryV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpVaultRegistryV16(160) = 176 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:2927):\r\n// market_group[32]+lp_mint[32]+total_lp_shares_outstanding(u128)+insurance_fee_snapshot(u128)+\r\n// fee_distribution_total(u128)+epoch(u64)+redemption_cooldown_slots(u64)+fee_share_bps(u16)+\r\n// oi_reservation_threshold_bps(u16)+domain(u16)+paused(u8)+version(u8)+bump(u8)+mint_bump(u8)+\r\n// _padding[6]+_reserved[16] = 160 bytes.\r\nconst LP_VAULT_REGISTRY_TOTAL = 176; // HEADER_LEN(16) + sizeof(LpVaultRegistryV16)(160)\r\n\r\n/** Decoded v17 LpVaultRegistryV16 account. */\r\nexport interface LpVaultRegistryV17 {\r\n marketGroup: PublicKey;\r\n lpMint: PublicKey;\r\n totalLpSharesOutstanding: bigint;\r\n insuranceFeeSnapshotAtoms: bigint;\r\n feeDistributionTotalAtoms: bigint;\r\n epoch: bigint;\r\n redemptionCooldownSlots: bigint;\r\n feeShareBps: number;\r\n oiReservationThresholdBps: number;\r\n domain: number;\r\n paused: boolean;\r\n version: number;\r\n bump: number;\r\n mintBump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpVaultRegistryV16 account from raw bytes.\r\n * Total account size: 176 bytes (HEADER_LEN=16 + struct=160).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP vault registry state.\r\n * @throws If data is shorter than 176 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(registryPubkey);\r\n * const registry = parseLpVaultRegistry(new Uint8Array(info!.data));\r\n * console.log('totalShares:', registry.totalLpSharesOutstanding);\r\n * ```\r\n */\r\nexport function parseLpVaultRegistry(data: Uint8Array): LpVaultRegistryV17 {\r\n if (data.length < LP_VAULT_REGISTRY_TOTAL) {\r\n throw new Error(\r\n `parseLpVaultRegistry: data too short (${data.length} < ${LP_VAULT_REGISTRY_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpVaultRegistry\", V17_KIND_LP_VAULT_REGISTRY);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n marketGroup: new PublicKey(data.subarray(b + 0, b + 32)),\r\n lpMint: new PublicKey(data.subarray(b + 32, b + 64)),\r\n totalLpSharesOutstanding: readU128LE(data, b + 64),\r\n insuranceFeeSnapshotAtoms: readU128LE(data, b + 80),\r\n feeDistributionTotalAtoms: readU128LE(data, b + 96),\r\n epoch: readU64LE(data, b + 112),\r\n redemptionCooldownSlots: readU64LE(data, b + 120),\r\n feeShareBps: readU16LE(data, b + 128),\r\n oiReservationThresholdBps: readU16LE(data, b + 130),\r\n domain: readU16LE(data, b + 132),\r\n paused: data[b + 134] !== 0,\r\n version: data[b + 135],\r\n bump: data[b + 136],\r\n mintBump: data[b + 137],\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// LpRedemptionV16 decoder\r\n// =============================================================================\r\n// Account layout: HEADER_LEN(16) + LpRedemptionV16(96) = 112 bytes total.\r\n// Struct layout (probe-confirmed in ~/v17/percolator-prog/src/v16_program.rs:3023):\r\n// registry[32]+redeemer[32]+shares(u128)+request_slot(u64)+version(u8)+bump(u8)+_padding[6] = 96.\r\nconst LP_REDEMPTION_TOTAL = 112; // HEADER_LEN(16) + sizeof(LpRedemptionV16)(96)\r\n\r\n/** Decoded v17 LpRedemptionV16 account. */\r\nexport interface LpRedemptionV17 {\r\n registry: PublicKey;\r\n redeemer: PublicKey;\r\n /** LP shares requested for redemption (u128). */\r\n shares: bigint;\r\n /** Slot when RequestRedeemLpShares was called. */\r\n requestSlot: bigint;\r\n version: number;\r\n bump: number;\r\n}\r\n\r\n/**\r\n * Parse a v17 LpRedemptionV16 account from raw bytes.\r\n * Total account size: 112 bytes (HEADER_LEN=16 + struct=96).\r\n *\r\n * @param data - Raw account bytes.\r\n * @returns Decoded LP redemption request state.\r\n * @throws If data is shorter than 112 bytes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = await connection.getAccountInfo(redemptionPubkey);\r\n * const redemption = parseLpRedemption(new Uint8Array(info!.data));\r\n * console.log('shares:', redemption.shares, 'slot:', redemption.requestSlot);\r\n * ```\r\n */\r\nexport function parseLpRedemption(data: Uint8Array): LpRedemptionV17 {\r\n if (data.length < LP_REDEMPTION_TOTAL) {\r\n throw new Error(\r\n `parseLpRedemption: data too short (${data.length} < ${LP_REDEMPTION_TOTAL})`\r\n );\r\n }\r\n assertV17StandaloneHeader(data, \"parseLpRedemption\", V17_KIND_LP_REDEMPTION);\r\n const b = V17_ACCOUNT_HEADER_LEN; // skip 16-byte header\r\n return {\r\n registry: new PublicKey(data.subarray(b + 0, b + 32)),\r\n redeemer: new PublicKey(data.subarray(b + 32, b + 64)),\r\n shares: readU128LE(data, b + 64),\r\n requestSlot: readU64LE(data, b + 80),\r\n version: data[b + 88],\r\n bump: data[b + 89],\r\n };\r\n}\r\n\r\n/**\r\n * Parse all used accounts.\r\n */\r\nexport function parseAllAccounts(data: Uint8Array): { idx: number; account: Account }[] {\r\n const indices = parseUsedIndices(data);\r\n const maxIdx = maxAccountIndex(data.length);\r\n const validIndices = indices.filter(idx => idx < maxIdx);\r\n const droppedCount = indices.length - validIndices.length;\r\n if (droppedCount > 0) {\r\n console.warn(\r\n `[parseAllAccounts] bitmap claims ${indices.length} used accounts but only ${maxIdx} fit ` +\r\n `in the slab — ${droppedCount} out-of-bounds indices dropped (possible bitmap corruption)`,\r\n );\r\n }\r\n return validIndices.map(idx => ({\r\n idx,\r\n account: parseAccount(data, idx),\r\n }));\r\n}\r\n","import { PublicKey } from \"@solana/web3.js\";\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Encode a u16 as a 2-byte little-endian buffer.\r\n * Used for PDA seed segments that include a domain/index as u16 LE.\r\n */\r\nfunction u16LE(value: number): Uint8Array {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isInteger(value) ||\r\n value < 0 ||\r\n value > 0xffff\r\n ) {\r\n throw new Error(`u16LE: value must be an integer in [0, 65535], got ${value}`);\r\n }\r\n const buf = new Uint8Array(2);\r\n new DataView(buf.buffer).setUint16(0, value, /*littleEndian=*/ true);\r\n return buf;\r\n}\r\n\r\n/**\r\n * Derive vault authority PDA.\r\n * Seeds: [\"vault\", slab_key]\r\n *\r\n * Mirrors `derive_vault_authority(program_id, market_key)` in\r\n * `percolator-prog/src/v16_program.rs:17339-17341`.\r\n */\r\nexport function deriveVaultAuthority(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"vault\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Canonical market vault (F-VAULT-FRAG) — tags 84, 87, and every token path\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * SPL Associated Token Account program.\r\n *\r\n * Mirrors `ASSOCIATED_TOKEN_PROGRAM_ID` in `v16_program.rs:17400-17401`, which the\r\n * wrapper declares locally for exactly one purpose: deriving the canonical vault.\r\n */\r\nexport const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\r\n);\r\n\r\n/**\r\n * The legacy SPL Token program — the ONLY token program the v17 wrapper accepts.\r\n *\r\n * This is not a default that a Token-2022 mint can override. `verify_token_program`\r\n * (`v16_program.rs:17436-17441`) rejects any `token_program` account whose key is not\r\n * `spl_token::ID`, and `unpack_token_account` (`17443-17455`) rejects any token account\r\n * not *owned* by `spl_token::ID`. Token-2022 collateral is unusable end to end, so the\r\n * ATA's middle seed is always this program id.\r\n */\r\nexport const PERCOLATOR_VAULT_TOKEN_PROGRAM_ID = new PublicKey(\r\n \"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"\r\n);\r\n\r\n/**\r\n * Derive the CANONICAL vault token account for a market + collateral mint.\r\n *\r\n * The vault is the Associated Token Account of the market's `vault_authority` PDA:\r\n *\r\n * ```text\r\n * vault_authority = PDA([\"vault\", market], wrapperProgramId)\r\n * vault = PDA([vault_authority, SPL_TOKEN_ID, mint], ATA_PROGRAM_ID)\r\n * ```\r\n *\r\n * Mirrors `canonical_vault_address(vault_authority, mint)`\r\n * (`v16_program.rs:17404-17415`). The wrapper PINS this single address rather than\r\n * accepting any `vault_authority`-owned token account: `verify_vault_token_account`\r\n * (`17543-17563`) rejects a token account whose key is not exactly this, on top of the\r\n * mint/owner/state/delegate/close-authority checks. That pin is finding F-VAULT-FRAG —\r\n * without it an attacker could route deposits to a second `vault_authority`-owned account\r\n * and strand honest withdrawals against the canonical one.\r\n *\r\n * ⚠ The middle seed is ALWAYS the legacy SPL Token program\r\n * ({@link PERCOLATOR_VAULT_TOKEN_PROGRAM_ID}), never Token-2022 — the wrapper hard-pins\r\n * `spl_token::ID` in both `verify_token_program` and `unpack_token_account`. Deriving this\r\n * address with a detected token program would produce a key the program rejects with\r\n * `InvalidVaultAccount`, which reads as \"bad vault\" rather than \"wrong derivation\".\r\n *\r\n * Required by `WithdrawProtocolFee` (tag 84) at accounts[3] and\r\n * `WithdrawInsuranceReserveToStake` (tag 87) at accounts[4], plus every deposit/withdraw\r\n * token path.\r\n *\r\n * @param programId - The Percolator wrapper program ID (the market's owner).\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint (`WrapperConfigV16::collateral_mint`).\r\n * @returns `[vaultTokenAccount, bump]` — the ATA address and its bump.\r\n *\r\n * @example\r\n * ```ts\r\n * const cfg = parseWrapperConfigV17(marketData);\r\n * const [vaultToken] = deriveCanonicalVault(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * ```\r\n */\r\nexport function deriveCanonicalVault(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n const [vaultAuthority] = deriveVaultAuthority(programId, market);\r\n return deriveCanonicalVaultForAuthority(vaultAuthority, mint);\r\n}\r\n\r\n/**\r\n * Derive the canonical vault ATA from an already-derived `vault_authority`.\r\n *\r\n * Split out from {@link deriveCanonicalVault} so callers that already hold the authority\r\n * (e.g. because they must also pass it as an account) do not re-run the \"vault\" PDA search.\r\n * Same derivation, same program pins — see {@link deriveCanonicalVault} for the rationale.\r\n *\r\n * @param vaultAuthority - The `[\"vault\", market]` PDA under the wrapper program.\r\n * @param mint - The market's collateral mint.\r\n * @returns `[vaultTokenAccount, bump]`\r\n *\r\n * @example\r\n * ```ts\r\n * const [auth] = deriveVaultAuthority(WRAPPER_ID, marketPk);\r\n * const [vault] = deriveCanonicalVaultForAuthority(auth, mintPk);\r\n * ```\r\n */\r\nexport function deriveCanonicalVaultForAuthority(\r\n vaultAuthority: PublicKey,\r\n mint: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n vaultAuthority.toBytes(),\r\n PERCOLATOR_VAULT_TOKEN_PROGRAM_ID.toBytes(),\r\n mint.toBytes(),\r\n ],\r\n ASSOCIATED_TOKEN_PROGRAM_ID\r\n );\r\n}\r\n\r\n/** Both halves of a market's vault, as required by tags 84 and 87. */\r\nexport interface MarketVaultAccounts {\r\n /** `PDA([\"vault\", market], wrapperProgramId)` — SPL owner of the vault, and CPI signer. */\r\n vaultAuthority: PublicKey;\r\n /** Bump for `vaultAuthority`. The program re-derives it; callers never pass it. */\r\n vaultAuthorityBump: number;\r\n /** The canonical vault token account — `ATA(vaultAuthority, SPL_TOKEN, mint)`. */\r\n vaultToken: PublicKey;\r\n /** Bump for `vaultToken`. */\r\n vaultTokenBump: number;\r\n /** The token program that must be passed alongside — always legacy SPL Token. */\r\n tokenProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Derive every vault-side account a fee-withdrawal instruction needs, in one call.\r\n *\r\n * `WithdrawProtocolFee` (tag 84) and `WithdrawInsuranceReserveToStake` (tag 87) each take\r\n * the vault token account, the vault authority PDA and the token program as three separate\r\n * accounts that must agree with one another; deriving them together makes disagreement\r\n * impossible.\r\n *\r\n * Account positions:\r\n * - tag 84 (`v16_program.rs:10796-10815`): `[3] vaultToken (w)`, `[4] vaultAuthority`, `[5] tokenProgram`\r\n * - tag 87 (`v16_program.rs:11238-11258`): `[4] vaultToken (w)`, `[5] vaultAuthority`, `[6] tokenProgram`\r\n *\r\n * @param programId - The Percolator wrapper program ID.\r\n * @param market - The v17 market group (slab) public key.\r\n * @param mint - The market's collateral mint.\r\n * @returns The vault authority, the canonical vault token account, both bumps, and the token program.\r\n *\r\n * @example\r\n * ```ts\r\n * const v = deriveMarketVaultAccounts(WRAPPER_ID, marketPk, cfg.collateralMint);\r\n * const keys = [\r\n * { pubkey: cranker.publicKey, isSigner: true, isWritable: false },\r\n * { pubkey: marketPk, isSigner: false, isWritable: true },\r\n * { pubkey: destToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultToken, isSigner: false, isWritable: true },\r\n * { pubkey: v.vaultAuthority, isSigner: false, isWritable: false },\r\n * { pubkey: v.tokenProgram, isSigner: false, isWritable: false },\r\n * ];\r\n * ```\r\n */\r\nexport function deriveMarketVaultAccounts(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n mint: PublicKey\r\n): MarketVaultAccounts {\r\n const [vaultAuthority, vaultAuthorityBump] = deriveVaultAuthority(programId, market);\r\n const [vaultToken, vaultTokenBump] = deriveCanonicalVaultForAuthority(\r\n vaultAuthority,\r\n mint\r\n );\r\n return {\r\n vaultAuthority,\r\n vaultAuthorityBump,\r\n vaultToken,\r\n vaultTokenBump,\r\n tokenProgram: PERCOLATOR_VAULT_TOKEN_PROGRAM_ID,\r\n };\r\n}\r\n\r\n/**\r\n * Derive insurance LP mint PDA (a.k.a. LP vault mint PDA).\r\n * Seeds: [\"lp_vault_mint\", slab_key]\r\n * Wrapper anchor: src/percolator.rs:2543 derive_lp_vault_mint.\r\n */\r\nexport function deriveInsuranceLpMint(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault_mint\"), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\nconst LP_INDEX_U16_MAX = 0xffff;\r\n\r\n/**\r\n * Derive LP PDA for TradeCpi.\r\n * Seeds: [\"lp\", slab_key, lp_idx as u16 LE]\r\n */\r\nexport function deriveLpPda(\r\n programId: PublicKey,\r\n slab: PublicKey,\r\n lpIdx: number\r\n): [PublicKey, number] {\r\n if (\r\n typeof lpIdx !== \"number\" ||\r\n !Number.isInteger(lpIdx) ||\r\n lpIdx < 0 ||\r\n lpIdx > LP_INDEX_U16_MAX\r\n ) {\r\n throw new Error(\r\n `deriveLpPda: lpIdx must be an integer in [0, ${LP_INDEX_U16_MAX}], got ${lpIdx}`,\r\n );\r\n }\r\n const idxBuf = new Uint8Array(2);\r\n new DataView(idxBuf.buffer).setUint16(0, lpIdx, true);\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp\"), slab.toBytes(), idxBuf],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DEX Program IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/** PumpSwap AMM program ID. */\r\nexport const PUMPSWAP_PROGRAM_ID = new PublicKey(\r\n \"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA\"\r\n);\r\n\r\n/** Raydium CLMM (Concentrated Liquidity) program ID. */\r\nexport const RAYDIUM_CLMM_PROGRAM_ID = new PublicKey(\r\n \"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK\"\r\n);\r\n\r\n/** Meteora DLMM (Dynamic Liquidity Market Maker) program ID. */\r\nexport const METEORA_DLMM_PROGRAM_ID = new PublicKey(\r\n \"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth Push Oracle\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Pyth Push Oracle program on mainnet. */\r\nexport const PYTH_PUSH_ORACLE_PROGRAM_ID = new PublicKey(\r\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\r\n);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Creator Lock PDA (PERC-627)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Seed used to derive the creator lock PDA.\r\n * Matches `creator_lock::CREATOR_LOCK_SEED` in percolator-prog.\r\n */\r\nexport const CREATOR_LOCK_SEED = \"creator_lock\";\r\n\r\n/**\r\n * Derive the creator lock PDA for a given slab.\r\n * Seeds: [\"creator_lock\", slab_key]\r\n *\r\n * This PDA is required as accounts[9] in every LpVaultWithdraw instruction\r\n * since percolator-prog PR#170 (GH#1926 / PERC-8287).\r\n * Non-creator withdrawers must pass this key; if no lock exists on-chain the\r\n * enforcement is a no-op. The SDK must ALWAYS include it — passing it is mandatory.\r\n *\r\n * @param programId - The percolator program ID.\r\n * @param slab - The slab (market) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [creatorLockPda] = deriveCreatorLockPda(PROGRAM_ID, slabKey);\r\n * ```\r\n */\r\nexport function deriveCreatorLockPda(\r\n programId: PublicKey,\r\n slab: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(CREATOR_LOCK_SEED), slab.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// LP Vault PDAs (v17 — tags 74-80)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the LP Vault registry PDA.\r\n * Seeds: [\"lp_vault\", marketGroup]\r\n *\r\n * Required by: CreateLpVault (tag 74), DepositToLpVault (tag 75),\r\n * RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77),\r\n * LpVaultCrankFees (tag 78), SetLpVaultPaused (tag 79), CloseLpVault (tag 80).\r\n *\r\n * Matches `constants::LP_VAULT_REGISTRY_SEED = b\"lp_vault\"` in v16_program.rs.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpVaultRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_vault\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP redemption ticket PDA for a specific redeemer.\r\n * Seeds: [\"lp_redemption\", registry, redeemer]\r\n *\r\n * Required by: RequestRedeemLpShares (tag 76), ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_REDEMPTION_SEED = b\"lp_redemption\"` in v16_program.rs\r\n * and `derive_lp_redemption(program_id, registry, redeemer)` at line 3111.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param registry - The LP Vault registry PDA (from deriveLpVaultRegistry).\r\n * @param redeemer - The wallet public key of the redeemer.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [registryPda] = deriveLpVaultRegistry(PROGRAM_ID, marketGroupKey);\r\n * const [redemptionPda] = deriveLpRedemption(PROGRAM_ID, registryPda, walletKey);\r\n * ```\r\n */\r\nexport function deriveLpRedemption(\r\n programId: PublicKey,\r\n registry: PublicKey,\r\n redeemer: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_redemption\"),\r\n registry.toBytes(),\r\n redeemer.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP backing-domain ledger PDA.\r\n * Seeds: [\"lp_backing_ledger\", marketGroup, u16LE(domainIdx)]\r\n *\r\n * Required by: DepositToLpVault (tag 75) at accounts[7],\r\n * LpVaultCrankFees (tag 78) at accounts[3].\r\n *\r\n * Matches `constants::LP_BACKING_LEDGER_SEED = b\"lp_backing_ledger\"` and\r\n * `derive_lp_backing_ledger(program_id, market_group, domain: u16)` in v16_program.rs\r\n * (line 3127) — domain is encoded as 2-byte little-endian.\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @param domainIdx - The backing domain index as a u16 integer (0–65535).\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [ledgerPda] = deriveLpBackingLedger(PROGRAM_ID, marketGroupKey, 0);\r\n * ```\r\n */\r\nexport function deriveLpBackingLedger(\r\n programId: PublicKey,\r\n marketGroup: PublicKey,\r\n domainIdx: number\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"lp_backing_ledger\"),\r\n marketGroup.toBytes(),\r\n u16LE(domainIdx),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/**\r\n * Derive the LP escrow SPL token account PDA.\r\n * Seeds: [\"lp_escrow\", marketGroup]\r\n *\r\n * The escrow is owned by the registry PDA and holds LP tokens during the\r\n * redemption window. Required by ExecuteRedemption (tag 77).\r\n *\r\n * Matches `constants::LP_ESCROW_SEED = b\"lp_escrow\"` and\r\n * `derive_lp_escrow(program_id, market_group)` in v16_program.rs (line 3157).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [escrowPda] = deriveLpEscrow(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveLpEscrow(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"lp_escrow\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NFT Registry PDA (v17 — tag 73)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the per-market NFT program-id registry PDA.\r\n * Seeds: [\"nft_registry\", marketGroup]\r\n *\r\n * Required by: SetNftProgramId (tag 73) and the wrapper's NFT B-3 CPI path\r\n * (TransferPortfolioOwnership, tag 72).\r\n *\r\n * Matches `constants::NFT_REGISTRY_SEED = b\"nft_registry\"` and\r\n * `derive_nft_registry(program_id, market_group)` in v16_program.rs (line 3274).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param marketGroup - The market group (slab) public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [nftRegistryPda] = deriveNftRegistry(PROGRAM_ID, marketGroupKey);\r\n * ```\r\n */\r\nexport function deriveNftRegistry(\r\n programId: PublicKey,\r\n marketGroup: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [textEncoder.encode(\"nft_registry\"), marketGroup.toBytes()],\r\n programId\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Matcher Delegate PDA (v17 — TradeCpi tag 10 / BatchTradeCpi tag 67)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Derive the matcher delegate PDA.\r\n * Seeds: [\"matcher\", market, accountB, accountBOwner, matcherProg, matcherCtx]\r\n * (all six seed segments are 32-byte public keys)\r\n *\r\n * Required by TradeCpi (tag 10) at accounts[6] and BatchTradeCpi (tag 67).\r\n * The program signs CPI calls to the external matcher program using this PDA.\r\n *\r\n * Matches `derive_matcher_delegate(program_id, market_key, maker_account,\r\n * maker_owner, matcher_program, matcher_context)` in v16_program.rs (line 13642).\r\n *\r\n * @param programId - The Percolator program ID.\r\n * @param market - The market (slab) public key.\r\n * @param accountB - The maker/LP portfolio account public key.\r\n * @param accountBOwner - The owner of accountB.\r\n * @param matcherProg - The external matcher program public key.\r\n * @param matcherCtx - The matcher context account public key.\r\n * @returns [pda, bump]\r\n *\r\n * @example\r\n * ```ts\r\n * const [delegatePda] = deriveMatcherDelegate(\r\n * PROGRAM_ID,\r\n * marketKey,\r\n * accountBKey,\r\n * accountBOwnerKey,\r\n * matcherProgKey,\r\n * matcherCtxKey,\r\n * );\r\n * ```\r\n */\r\nexport function deriveMatcherDelegate(\r\n programId: PublicKey,\r\n market: PublicKey,\r\n accountB: PublicKey,\r\n accountBOwner: PublicKey,\r\n matcherProg: PublicKey,\r\n matcherCtx: PublicKey\r\n): [PublicKey, number] {\r\n return PublicKey.findProgramAddressSync(\r\n [\r\n textEncoder.encode(\"matcher\"),\r\n market.toBytes(),\r\n accountB.toBytes(),\r\n accountBOwner.toBytes(),\r\n matcherProg.toBytes(),\r\n matcherCtx.toBytes(),\r\n ],\r\n programId\r\n );\r\n}\r\n\r\n/** 32-byte feed id as 64 hex digits (optional `0x` prefix after trim). */\r\nconst PYTH_FEED_ID_HEX_LEN = 64;\r\n\r\nfunction normalizePythFeedIdHex(feedIdHex: string): string {\r\n let s = feedIdHex.trim();\r\n if (s.startsWith(\"0x\") || s.startsWith(\"0X\")) {\r\n s = s.slice(2);\r\n }\r\n return s;\r\n}\r\n\r\n/**\r\n * Derive the Pyth Push Oracle PDA for a given feed ID.\r\n * Seeds: [shard_id(u16 LE, always 0), feed_id(32 bytes)]\r\n * Program: pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\r\n */\r\nconst FEED_HEX_RE = /^[0-9a-fA-F]{64}$/;\r\n\r\nexport function derivePythPushOraclePDA(feedIdHex: string): [PublicKey, number] {\r\n const normalized = normalizePythFeedIdHex(feedIdHex);\r\n if (!FEED_HEX_RE.test(normalized)) {\r\n throw new Error(\r\n `derivePythPushOraclePDA: feedIdHex must be 64 hex digits (32 bytes); got ${normalized.length === 64 ? \"non-hexadecimal characters\" : normalized.length + \" chars\"}`, );\r\n }\r\n const feedId = new Uint8Array(32);\r\n for (let i = 0; i < 32; i++) {\r\n feedId[i] = parseInt(normalized.substring(i * 2, i * 2 + 2), 16);\r\n }\r\n const shardBuf = new Uint8Array(2); // shard_id = 0 (u16 LE)\r\n return PublicKey.findProgramAddressSync(\r\n [shardBuf, feedId],\r\n PYTH_PUSH_ORACLE_PROGRAM_ID,\r\n );\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n getAssociatedTokenAddress,\r\n getAssociatedTokenAddressSync,\r\n getAccount,\r\n Account,\r\n TOKEN_PROGRAM_ID,\r\n} from \"@solana/spl-token\";\r\nimport { TOKEN_2022_PROGRAM_ID } from \"./token-program.js\";\r\n\r\n/**\r\n * Get the associated token address for an owner and mint.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport async function getAta(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAssociatedTokenAddress(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Synchronous version of getAta.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n */\r\nexport function getAtaSync(\r\n owner: PublicKey,\r\n mint: PublicKey,\r\n allowOwnerOffCurve = false,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): PublicKey {\r\n return getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, tokenProgramId);\r\n}\r\n\r\n/**\r\n * Fetch token account info.\r\n * Supports both standard SPL Token and Token2022 via optional tokenProgramId.\r\n * Throws if account doesn't exist.\r\n */\r\nexport async function fetchTokenAccount(\r\n connection: Connection,\r\n address: PublicKey,\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n): Promise {\r\n return getAccount(connection, address, undefined, tokenProgramId);\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n parseHeader,\r\n parseConfig,\r\n parseParams,\r\n detectSlabLayout,\r\n isV17MarketAccount,\r\n parseWrapperConfigV17,\r\n SLAB_TIERS_V1M,\r\n SLAB_TIERS_V1M2,\r\n SLAB_TIERS_V2,\r\n SLAB_TIERS_V_ADL,\r\n SLAB_TIERS_V12_1,\r\n SLAB_TIERS_V12_15,\r\n SLAB_TIERS_V12_17,\r\n SLAB_TIERS_V12_19,\r\n SLAB_TIERS_V_SETDEXPOOL,\r\n type SlabHeader,\r\n type MarketConfig,\r\n type EngineState,\r\n type RiskParams,\r\n type SlabLayout,\r\n type WrapperConfigV17,\r\n} from \"./slab.js\";\r\nimport { getStaticMarkets, type StaticMarketEntry } from \"./static-markets.js\";\r\nimport { type Network } from \"../config/program-ids.js\";\r\n\r\n/** V1 bitmap offset within engine struct (updated for PERC-120/121/122 struct changes) */\r\nconst ENGINE_BITMAP_OFF = 656; // Updated for PERC-299 (608 + 24 emergency OI fields)\r\n/** V0 bitmap offset within engine struct (deployed devnet program) */\r\nconst ENGINE_BITMAP_OFF_V0 = 320;\r\n\r\n/**\r\n * A discovered Percolator market from on-chain program accounts.\r\n */\r\nexport interface DiscoveredMarket {\r\n slabAddress: PublicKey;\r\n /** The program that owns this slab account */\r\n programId: PublicKey;\r\n /**\r\n * v12.x slab header. Present when the market is a v12 slab account (PERCOLAT magic).\r\n * Absent (undefined) for v17 market group accounts (PERCV16\\0 magic) — use configV17 instead.\r\n */\r\n header: SlabHeader;\r\n /**\r\n * v12.x market config parsed from the slab CONFIG region (536 bytes at offset 104).\r\n * Present for v12 slab accounts. Absent for v17 accounts — use configV17 instead.\r\n */\r\n config: MarketConfig;\r\n /**\r\n * v12.x engine state (bitmap, account counts).\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n engine: EngineState;\r\n /**\r\n * v12.x risk parameters.\r\n * Present for v12 slab accounts. Absent for v17 accounts.\r\n */\r\n params: RiskParams;\r\n /**\r\n * v17 wrapper config (WrapperConfigV16 struct, 496 bytes at header offset 16;\r\n * post-protocol-fee — was 432 bytes / VERSION 16 pre-protocol-fee).\r\n * Present when the market is a v17 market group account (PERCV16\\0 magic).\r\n * Absent for v12 slab accounts.\r\n *\r\n * Use `isV17Market(m)` to narrow the type:\r\n * ```ts\r\n * if (m.configV17) {\r\n * console.log(m.configV17.collateralMint.toBase58());\r\n * }\r\n * ```\r\n */\r\n configV17?: WrapperConfigV17;\r\n}\r\n\r\n/** PERCOLAT magic bytes (v12.x slabs) — stored little-endian on-chain as TALOCREP */\r\nconst MAGIC_BYTES = new Uint8Array([0x54, 0x41, 0x4c, 0x4f, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * v17 market group magic bytes — \"PERCV16\\0\" as little-endian bytes.\r\n * These are the first 8 bytes of every v17 percolator-owned market group account.\r\n * The program writes MAGIC.to_le_bytes() (v16_program.rs:966), so the on-chain bytes\r\n * are LITTLE-ENDIAN: 0x5045_5243_5631_3600 (\"PERCV16\\0\") -> [0x00,0x36,0x31,0x56,0x43,0x52,0x45,0x50].\r\n * A memcmp filter at offset 0 must use this exact LE order (isV17Account reads it via readU64LE).\r\n */\r\nconst V17_MAGIC_BYTES = new Uint8Array([0x00, 0x36, 0x31, 0x56, 0x43, 0x52, 0x45, 0x50]);\r\n\r\n/**\r\n * Slab tier definitions — V1 layout (all tiers upgraded as of 2026-03-13).\r\n * IMPORTANT: dataSize must match the compiled program's SLAB_LEN for that MAX_ACCOUNTS.\r\n * The on-chain program has a hardcoded SLAB_LEN — slab account data.len() must equal it exactly.\r\n *\r\n * Layout: HEADER(104) + CONFIG(536) + RiskEngine(variable by tier)\r\n * ENGINE_OFF = 640 (HEADER=104 + CONFIG=536, padded to 8-byte align on SBF)\r\n * RiskEngine = fixed(656) + bitmap(BW*8) + post_bitmap(18) + next_free(N*2) + pad + accounts(N*248)\r\n *\r\n * Values are empirically verified against on-chain initialized accounts (GH #1109):\r\n * small = 65,352 (256-acct program, verified on-chain post-V1 upgrade)\r\n * medium = 257,448 (1024-acct program g9msRSV3, verified on-chain)\r\n * large = 1,025,832 (4096-acct program FxfD37s1, pre-PERC-118, matches slabDataSizeV1(4096) formula)\r\n *\r\n * NOTE: small program (FwfBKZXb) redeployed with --features small,devnet (2026-03-13).\r\n * Large program FxfD37s1 is pre-PERC-118 — SLAB_LEN=1,025,832, matching formula.\r\n * See GH #1109, GH #1112.\r\n *\r\n * History: Small was V0 (62_808) until 2026-03-13 program upgrade. V0 values preserved\r\n * in SLAB_TIERS_V0 for discovery of legacy on-chain accounts.\r\n */\r\n/**\r\n * Default slab tiers for the current mainnet program (v12.17).\r\n * These are used by useCreateMarket to allocate slab accounts of the correct size.\r\n * V12_17: two-bucket warmup, per-side funding, ACCOUNT_SIZE=352 (SBF).\r\n */\r\nexport const SLAB_TIERS = {\r\n small: SLAB_TIERS_V12_17[\"small\"],\r\n medium: SLAB_TIERS_V12_17[\"medium\"],\r\n large: SLAB_TIERS_V12_17[\"large\"],\r\n} as const;\r\n\r\n/** @deprecated V0 slab sizes — kept for backward compatibility with old on-chain slabs */\r\nexport const SLAB_TIERS_V0 = {\r\n small: { maxAccounts: 256, dataSize: 62_808, label: \"Small\", description: \"256 slots · ~0.44 SOL\" },\r\n medium: { maxAccounts: 1024, dataSize: 248_760, label: \"Medium\", description: \"1,024 slots · ~1.73 SOL\" },\r\n large: { maxAccounts: 4096, dataSize: 992_568, label: \"Large\", description: \"4,096 slots · ~6.90 SOL\" },\r\n} as const;\r\n\r\n/**\r\n * V1D slab sizes — actually-deployed devnet V1 program (ENGINE_OFF=424, BITMAP_OFF=624).\r\n * PR #1200 added V1D layout detection in slab.ts but discovery.ts ALL_TIERS was missing\r\n * these sizes, causing V1D slabs to fall through to the memcmp fallback with wrong dataSize\r\n * hints → detectSlabLayout returning null → parse failure (GH#1205).\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=2):\r\n * The V1D deployed program uses postBitmap=2 (free_head u16 only — no num_used/pad/next_account_id).\r\n * This is 16 bytes smaller per tier than the SDK default (postBitmap=18). GH#1234.\r\n * micro = 17,064 (64 slots)\r\n * small = 65,088 (256 slots)\r\n * medium = 257,184 (1,024 slots)\r\n * large = 1,025,568 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D = {\r\n micro: { maxAccounts: 64, dataSize: 17_064, label: \"Micro\", description: \"64 slots (V1D devnet)\" },\r\n small: { maxAccounts: 256, dataSize: 65_088, label: \"Small\", description: \"256 slots (V1D devnet)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_184, label: \"Medium\", description: \"1,024 slots (V1D devnet)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_568, label: \"Large\", description: \"4,096 slots (V1D devnet)\" },\r\n} as const;\r\n\r\n/**\r\n * V1D legacy slab sizes — on-chain V1D slabs created before GH#1234 when the SDK assumed\r\n * postBitmap=18. These are 16 bytes larger per tier than SLAB_TIERS_V1D.\r\n * PR #1236 fixed postBitmap for new slabs (→2) but caused slab 6ZytbpV4 (65104 bytes,\r\n * top active market ~$15k 24h vol) to be unrecognized → \"Failed to load market\". GH#1237.\r\n *\r\n * Sizes computed via computeSlabSize(ENGINE_OFF=424, BITMAP_OFF=624, ACCOUNT_SIZE=248, N, postBitmap=18):\r\n * micro = 17,080 (64 slots)\r\n * small = 65,104 (256 slots) ← slab 6ZytbpV4 TEST/USD\r\n * medium = 257,200 (1,024 slots)\r\n * large = 1,025,584 (4,096 slots)\r\n */\r\nexport const SLAB_TIERS_V1D_LEGACY = {\r\n micro: { maxAccounts: 64, dataSize: 17_080, label: \"Micro\", description: \"64 slots (V1D legacy, postBitmap=18)\" },\r\n small: { maxAccounts: 256, dataSize: 65_104, label: \"Small\", description: \"256 slots (V1D legacy, postBitmap=18)\" },\r\n medium: { maxAccounts: 1024, dataSize: 257_200, label: \"Medium\", description: \"1,024 slots (V1D legacy, postBitmap=18)\" },\r\n large: { maxAccounts: 4096, dataSize: 1_025_584, label: \"Large\", description: \"4,096 slots (V1D legacy, postBitmap=18)\" },\r\n} as const;\r\n\r\n/** @deprecated Alias — use SLAB_TIERS (already V1) */\r\nexport const SLAB_TIERS_V1 = SLAB_TIERS;\r\n\r\n/**\r\n * V_ADL slab tier sizes — PERC-8270/8271 ADL-upgraded program.\r\n * ENGINE_OFF=624, BITMAP_OFF=1006, ACCOUNT_SIZE=312, postBitmap=18.\r\n * New account layout adds ADL tracking fields (+64 bytes/account).\r\n * BPF SLAB_LEN verified by cargo build-sbf in PERC-8271: large (4096) = 1288304 bytes.\r\n */\r\n// Single source of truth lives in slab.ts (SLAB_TIERS_V_ADL).\r\nexport const SLAB_TIERS_V_ADL_DISCOVERY = SLAB_TIERS_V_ADL;\r\n\r\nexport type SlabTierKey = keyof typeof SLAB_TIERS;\r\n\r\n/** Calculate slab data size for arbitrary account count.\r\n *\r\n * Layout (SBF, u128 align = 8):\r\n * HEADER(104) + CONFIG(536) → ENGINE_OFF = 640\r\n * RiskEngine fixed scalars: 656 bytes (PERC-299: +24 emergency OI, +32 long/short OI)\r\n * + bitmap: ceil(N/64)*8\r\n * + num_used_accounts(u16) + pad(6) + next_account_id(u64) + free_head(u16) = 18\r\n * + next_free: N*2\r\n * + pad to 8-byte alignment for Account array\r\n * + accounts: N*248\r\n *\r\n * Must match the on-chain program's SLAB_LEN exactly.\r\n */\r\nexport function slabDataSize(maxAccounts: number): number {\r\n // V0 layout (deployed devnet): ENGINE_OFF=480, ENGINE_BITMAP_OFF=320, ACCOUNT_SIZE=240\r\n const ENGINE_OFF_V0 = 480;\r\n const ENGINE_BITMAP_OFF_V0 = 320;\r\n const ACCOUNT_SIZE_V0 = 240;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V0 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V0 + accountsOff + maxAccounts * ACCOUNT_SIZE_V0;\r\n}\r\n\r\n/**\r\n * Calculate slab data size for V1 layout (ENGINE_OFF=640).\r\n *\r\n * NOTE: This formula is accurate for small (256) and medium (1024) tiers but\r\n * underestimates large (4096) by 16 bytes — likely due to a padding/alignment\r\n * difference at high account counts or a post-PERC-118 struct addition in the\r\n * deployed binary. Always prefer the hardcoded SLAB_TIERS values (empirically\r\n * verified on-chain) over this formula for production use.\r\n */\r\nexport function slabDataSizeV1(maxAccounts: number): number {\r\n const ENGINE_OFF_V1 = 640; // HEADER(104) + CONFIG(536) aligned to 8 on SBF = 640\r\n const ENGINE_BITMAP_OFF_V1 = 656;\r\n const ACCOUNT_SIZE_V1 = 248;\r\n const bitmapBytes = Math.ceil(maxAccounts / 64) * 8;\r\n const postBitmap = 18;\r\n const nextFreeBytes = maxAccounts * 2;\r\n const preAccountsLen = ENGINE_BITMAP_OFF_V1 + bitmapBytes + postBitmap + nextFreeBytes;\r\n const accountsOff = Math.ceil(preAccountsLen / 8) * 8;\r\n return ENGINE_OFF_V1 + accountsOff + maxAccounts * ACCOUNT_SIZE_V1;\r\n}\r\n\r\n/**\r\n * Validate that a slab data size matches one of the known tier sizes.\r\n * Use this to catch tier↔program mismatches early (PERC-277).\r\n *\r\n * @param dataSize - The expected slab data size (from SLAB_TIERS[tier].dataSize)\r\n * @param programSlabLen - The program's compiled SLAB_LEN (from on-chain error logs or program introspection)\r\n * @returns true if sizes match, false if there's a mismatch\r\n */\r\nexport function validateSlabTierMatch(dataSize: number, programSlabLen: number): boolean {\r\n return dataSize === programSlabLen;\r\n}\r\n\r\n/** All known slab data sizes for discovery (V0 + V1 + V1D + V1D legacy + V1M + V_ADL tiers) */\r\nconst ALL_SLAB_SIZES = [\r\n ...Object.values(SLAB_TIERS).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V0).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V1M).map(t => t.dataSize),\r\n ...Object.values(SLAB_TIERS_V_ADL).map(t => t.dataSize),\r\n];\r\n\r\n/** Legacy constant for backward compat */\r\nconst SLAB_DATA_SIZE = SLAB_TIERS.large.dataSize;\r\n\r\n/** We need header(104) + config(536) + engine up to nextAccountId (~1200). Total ~1840. Use 1940 for margin. */\r\nconst HEADER_SLICE_LENGTH = 1940;\r\n\r\nfunction dv(data: Uint8Array): DataView {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n}\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n return dv(data).getUint16(off, true);\r\n}\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigUint64(off, true);\r\n}\r\nfunction readI64LE(data: Uint8Array, off: number): bigint {\r\n return dv(data).getBigInt64(off, true);\r\n}\r\nfunction readU128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n return (hi << 64n) | lo;\r\n}\r\nfunction readI128LE(buf: Uint8Array, offset: number): bigint {\r\n const lo = readU64LE(buf, offset);\r\n const hi = readU64LE(buf, offset + 8);\r\n const unsigned = (hi << 64n) | lo;\r\n const SIGN_BIT = 1n << 127n;\r\n if (unsigned >= SIGN_BIT) return unsigned - (1n << 128n);\r\n return unsigned;\r\n}\r\n\r\n/**\r\n * Light engine parser that works with partial slab data (dataSlice, no accounts array).\r\n * Requires a layout hint (from detectSlabLayout on the actual slab size) to use correct offsets.\r\n *\r\n * @param data — partial slab slice (HEADER_SLICE_LENGTH bytes)\r\n * @param layout — SlabLayout from detectSlabLayout(actualDataSize). If null, falls back to V0.\r\n * @param maxAccounts — tier's max accounts for bitmap offset calculation\r\n */\r\nexport function parseEngineLight(\r\n data: Uint8Array,\r\n layout: SlabLayout | null,\r\n maxAccounts: number = 4096,\r\n): EngineState {\r\n const isV0 = !layout || layout.version === 0;\r\n const base = layout ? layout.engineOff : 480; // V0=480, V1=640\r\n const bitmapOff = layout ? layout.engineBitmapOff : ENGINE_BITMAP_OFF_V0;\r\n\r\n const minLen = base + bitmapOff;\r\n if (data.length < minLen) {\r\n throw new Error(`Slab data too short for engine light parse: ${data.length} < ${minLen}`);\r\n }\r\n\r\n // Compute tier-dependent offsets for numUsedAccounts and nextAccountId\r\n const bitmapWords = Math.ceil(maxAccounts / 64);\r\n const numUsedOff = bitmapOff + bitmapWords * 8; // u16 right after bitmap\r\n const nextAccountIdOff = Math.ceil((numUsedOff + 2) / 8) * 8; // u64, 8-byte aligned\r\n\r\n const canReadNumUsed = data.length >= base + numUsedOff + 2;\r\n const canReadNextId = data.length >= base + nextAccountIdOff + 8;\r\n\r\n if (isV0) {\r\n // V0 engine struct (deployed devnet): ENGINE_OFF=480\r\n // vault(0,16) + insurance(16,32) + params(48,56) + currentSlot(104,8)\r\n // + fundingIndex(112,16) + lastFundingSlot(128,8) + fundingRateBps(136,8)\r\n // + lastCrankSlot(144,8) + maxCrankStaleness(152,8) + totalOI(160,16)\r\n // + cTot(176,16) + pnlPosTot(192,16) + liqCursor(208,2) + gcCursor(210,2)\r\n // + lastSweepStart(216,8) + lastSweepComplete(224,8) + crankCursor(232,2) + sweepStartIdx(234,2)\r\n // + lifetimeLiquidations(240,8) + lifetimeForceCloses(248,8)\r\n // + netLpPos(256,16) + lpSumAbs(272,16) + lpMaxAbs(288,16) + bitmap(320)\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + 16),\r\n feeRevenue: readU128LE(data, base + 32),\r\n isolatedBalance: 0n,\r\n isolationBps: 0,\r\n },\r\n currentSlot: readU64LE(data, base + 104),\r\n fundingIndexQpbE6: readI128LE(data, base + 112),\r\n lastFundingSlot: readU64LE(data, base + 128),\r\n fundingRateBpsPerSlotLast: readI64LE(data, base + 136),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: readU64LE(data, base + 144),\r\n maxCrankStalenessSlots: readU64LE(data, base + 152),\r\n totalOpenInterest: readU128LE(data, base + 160),\r\n longOi: 0n,\r\n shortOi: 0n,\r\n cTot: readU128LE(data, base + 176),\r\n pnlPosTot: readU128LE(data, base + 192),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: readU16LE(data, base + 208),\r\n gcCursor: readU16LE(data, base + 210),\r\n lastSweepStartSlot: readU64LE(data, base + 216),\r\n lastSweepCompleteSlot: readU64LE(data, base + 224),\r\n crankCursor: readU16LE(data, base + 232),\r\n sweepStartIdx: readU16LE(data, base + 234),\r\n lifetimeLiquidations: readU64LE(data, base + 240),\r\n lifetimeForceCloses: readU64LE(data, base + 248),\r\n netLpPos: readI128LE(data, base + 256),\r\n lpSumAbs: readU128LE(data, base + 272),\r\n lpMaxAbs: readU128LE(data, base + 288),\r\n lpMaxAbsSweep: 0n,\r\n emergencyOiMode: false,\r\n emergencyStartSlot: 0n,\r\n lastBreakerSlot: 0n,\r\n markPriceE6: 0n, // V0 engine has no mark_price field\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n, fShortNum: 0n, negPnlAccountCount: 0n, fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n, resolvedKShortTerminalDelta: 0n, resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // NOTE: a hardcoded \"V2 engine struct (BPF intermediate)\" branch used to live here,\r\n // gated on `layout?.version === 2`. It was dead/stale: `SlabLayout.version === 2` is\r\n // also set by buildLayoutV12_15/17/19 (V12_19 inherits it by spreading V12_17's base\r\n // layout) — an unrelated reuse of the same discriminant — which meant V12_15/17/19\r\n // (the currently-deployed mainnet tier line) were being routed through this branch's\r\n // long-stale hardcoded offsets (e.g. currentSlot at a fixed `base+352`) instead of\r\n // their own correct per-field offsets (V12_19's real engineCurrentSlotOff is 200).\r\n // Every field this branch returned was potentially wrong for V12_15/17/19. Removed\r\n // per the layout-driven branch's own comment below, which already documents that it\r\n // covers V12_15/17/19 — that was the intended path all along.\r\n\r\n // Layout-driven engine parse: covers V_ADL (engineOff=624, accountSize=312), V12_1, V12_15,\r\n // V12_17, V12_19, V1M, V1M2, V_SETDEXPOOL and any future layout registered in slab.ts.\r\n // PR #185 / PR #151: replaced the narrow isVAdl gate (engineOff===624 && accountSize===312)\r\n // with a general layout !== null check so ALL layout variants use the descriptor-driven path.\r\n // The old hardcoded V1 fallback block (fixed offsets) is removed — it misread V12_1x slabs\r\n // that share engineOff=640 but have different internal struct sizes.\r\n if (layout !== null) {\r\n const l = layout;\r\n // hasInsuranceIsolation: v17+ layouts expose isolatedBalance/isolationBps; older ones set -1.\r\n const hasInsuranceIsolation = l.engineInsuranceIsolatedOff >= 0 && l.engineInsuranceIsolationBpsOff >= 0;\r\n // Absent-field guards. A SlabLayout sets an offset to -1 when the engine\r\n // struct for that tier has no such field, and `base + (-1)` would read\r\n // garbage straddling the byte before the engine region rather than failing.\r\n // V12_15 has 25 such fields and V12_17/V12_19 have 22 each, so every read\r\n // below goes through these instead of reading the offset directly.\r\n const u16At = (off: number): number => (off >= 0 ? readU16LE(data, base + off) : 0);\r\n const u64At = (off: number): bigint => (off >= 0 ? readU64LE(data, base + off) : 0n);\r\n const i64At = (off: number): bigint => (off >= 0 ? readI64LE(data, base + off) : 0n);\r\n const u128At = (off: number): bigint => (off >= 0 ? readU128LE(data, base + off) : 0n);\r\n const i128At = (off: number): bigint => (off >= 0 ? readI128LE(data, base + off) : 0n);\r\n return {\r\n vault: readU128LE(data, base + 0),\r\n insuranceFund: {\r\n balance: readU128LE(data, base + l.engineInsuranceOff),\r\n feeRevenue: readU128LE(data, base + l.engineInsuranceOff + 16),\r\n isolatedBalance: hasInsuranceIsolation ? readU128LE(data, base + l.engineInsuranceIsolatedOff) : 0n,\r\n isolationBps: hasInsuranceIsolation ? readU16LE(data, base + l.engineInsuranceIsolationBpsOff) : 0,\r\n },\r\n currentSlot: readU64LE(data, base + l.engineCurrentSlotOff),\r\n // engineFundingIndexOff is -1 on V12_15/17/19 (this field doesn't exist in those\r\n // engine structs) — guard the same way the heavy parser does (slab.ts parseEngine)\r\n // or `base + (-1)` reads 16 bytes starting one byte before the engine region.\r\n fundingIndexQpbE6: l.engineFundingIndexOff >= 0\r\n ? ((l.engineLastFundingSlotOff >= 0 && l.engineLastFundingSlotOff - l.engineFundingIndexOff === 8)\r\n ? BigInt(readI64LE(data, base + l.engineFundingIndexOff))\r\n : readI128LE(data, base + l.engineFundingIndexOff))\r\n : 0n,\r\n lastFundingSlot: u64At(l.engineLastFundingSlotOff),\r\n fundingRateBpsPerSlotLast: i64At(l.engineFundingRateBpsOff),\r\n fundingRateE9: 0n,\r\n marketMode: null,\r\n lastCrankSlot: u64At(l.engineLastCrankSlotOff),\r\n maxCrankStalenessSlots: u64At(l.engineMaxCrankStalenessOff),\r\n totalOpenInterest: u128At(l.engineTotalOiOff),\r\n longOi: u128At(l.engineLongOiOff),\r\n shortOi: u128At(l.engineShortOiOff),\r\n cTot: readU128LE(data, base + l.engineCTotOff),\r\n pnlPosTot: readU128LE(data, base + l.enginePnlPosTotOff),\r\n pnlMaturedPosTot: 0n,\r\n liqCursor: u16At(l.engineLiqCursorOff),\r\n gcCursor: u16At(l.engineGcCursorOff),\r\n lastSweepStartSlot: u64At(l.engineLastSweepStartOff),\r\n lastSweepCompleteSlot: u64At(l.engineLastSweepCompleteOff),\r\n crankCursor: u16At(l.engineCrankCursorOff),\r\n sweepStartIdx: u16At(l.engineSweepStartIdxOff),\r\n lifetimeLiquidations: u64At(l.engineLifetimeLiquidationsOff),\r\n lifetimeForceCloses: u64At(l.engineLifetimeForceClosesOff),\r\n netLpPos: i128At(l.engineNetLpPosOff),\r\n lpSumAbs: u128At(l.engineLpSumAbsOff),\r\n lpMaxAbs: u128At(l.engineLpMaxAbsOff),\r\n lpMaxAbsSweep: u128At(l.engineLpMaxAbsSweepOff),\r\n emergencyOiMode: l.engineEmergencyOiModeOff >= 0 ? data[base + l.engineEmergencyOiModeOff] !== 0 : false,\r\n emergencyStartSlot: u64At(l.engineEmergencyStartSlotOff),\r\n lastBreakerSlot: u64At(l.engineLastBreakerSlotOff),\r\n markPriceE6: u64At(l.engineMarkPriceOff),\r\n oraclePriceE6: 0n,\r\n fLongNum: 0n,\r\n fShortNum: 0n,\r\n negPnlAccountCount: 0n,\r\n fundPxLast: 0n,\r\n resolvedKLongTerminalDelta: 0n,\r\n resolvedKShortTerminalDelta: 0n,\r\n resolvedLivePrice: 0n,\r\n numUsedAccounts: canReadNumUsed ? readU16LE(data, base + numUsedOff) : 0,\r\n nextAccountId: canReadNextId ? readU64LE(data, base + nextAccountIdOff) : 0n,\r\n };\r\n }\r\n\r\n // layout === null: unrecognized slab format — callers should have skipped via the\r\n // layout !== null guard in discoverMarkets before calling parseEngineLight.\r\n throw new Error(`parseEngineLight: unrecognized slab layout (isV0=${isV0})`);\r\n}\r\n\r\n/** Options for `discoverMarkets`. */\r\nexport interface DiscoverMarketsOptions {\r\n /**\r\n * Run tier queries sequentially with per-tier retry on HTTP 429 instead of\r\n * firing all in parallel. Reduces RPC rate-limit pressure at the cost of\r\n * slightly slower discovery (~14 round-trips instead of 1 concurrent batch).\r\n * Default: false (preserves original parallel behaviour).\r\n *\r\n * PERC-1650: keeper uses this flag to avoid 429 storms on its fallback RPC\r\n * (Helius starter tier). Pass `sequential: true` from CrankService.discover().\r\n */\r\n sequential?: boolean;\r\n /**\r\n * Delay in ms between sequential tier queries (only used when sequential=true).\r\n * Default: 200 ms.\r\n */\r\n interTierDelayMs?: number;\r\n /**\r\n * Per-tier retry backoff delays on 429 (ms). Jitter of up to +25% is applied.\r\n * Only used when sequential=true. Default: [1_000, 3_000, 9_000, 27_000].\r\n */\r\n rateLimitBackoffMs?: number[];\r\n\r\n /**\r\n * In parallel mode (the default), cap how many tier RPC requests are in-flight\r\n * at once to avoid accidental RPC storms from client code.\r\n *\r\n * Default: 6\r\n */\r\n maxParallelTiers?: number;\r\n\r\n /**\r\n * Hard cap on how many tier dataSize queries are attempted.\r\n * Default: all known tiers.\r\n */\r\n maxTierQueries?: number;\r\n\r\n /**\r\n * Base URL of the Percolator REST API (e.g. `\"https://percolatorlaunch.com/api\"`).\r\n *\r\n * When set, `discoverMarkets` will fall back to the REST API's `GET /markets`\r\n * endpoint if `getProgramAccounts` fails or returns 0 results (common on public\r\n * mainnet RPCs that reject `getProgramAccounts`).\r\n *\r\n * The API returns slab addresses which are then fetched on-chain via\r\n * `getMarketsByAddress` (uses `getMultipleAccounts`, works on all RPCs).\r\n *\r\n * GH#59 / PERC-8424: Unblocks mainnet users without a Helius API key.\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * });\r\n * ```\r\n */\r\n apiBaseUrl?: string;\r\n\r\n /**\r\n * Timeout in ms for the API fallback HTTP request.\r\n * Only used when `apiBaseUrl` is set.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n apiTimeoutMs?: number;\r\n\r\n /**\r\n * Network hint for tier-3 static bundle fallback (`\"mainnet\"` or `\"devnet\"`).\r\n *\r\n * When both `getProgramAccounts` (tier 1) and the REST API (tier 2) fail,\r\n * `discoverMarkets` will fall back to a bundled static list of known slab\r\n * addresses for the specified network. The addresses are fetched on-chain\r\n * via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * If not set, tier-3 fallback is disabled.\r\n *\r\n * The static list can be extended at runtime via `registerStaticMarkets()`.\r\n *\r\n * @see {@link registerStaticMarkets} to add addresses at runtime\r\n * @see {@link getStaticMarkets} to inspect the current static list\r\n *\r\n * @example\r\n * ```ts\r\n * const markets = await discoverMarkets(connection, programId, {\r\n * apiBaseUrl: \"https://percolatorlaunch.com/api\",\r\n * network: \"mainnet\", // enables tier-3 static fallback\r\n * });\r\n * ```\r\n */\r\n network?: Network;\r\n}\r\n\r\n/** Return true if the error looks like an HTTP 429 / rate-limit response. */\r\nfunction isRateLimitError(err: unknown): boolean {\r\n if (!err) return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return (\r\n msg.includes(\"429\") ||\r\n msg.toLowerCase().includes(\"rate limit\") ||\r\n msg.toLowerCase().includes(\"too many requests\")\r\n );\r\n}\r\n\r\n/** Add equal-distribution jitter (range: [delayMs/2, delayMs]) to avoid thundering-herd on retry. */\r\nfunction withJitter(delayMs: number): number {\r\n const half = Math.floor(delayMs / 2);\r\n return half + Math.floor(Math.random() * (delayMs - half + 1));\r\n}\r\n\r\n/**\r\n * Discover all Percolator markets owned by the given program.\r\n * Uses getProgramAccounts with dataSize filter + dataSlice to download only ~1400 bytes per slab.\r\n *\r\n * @param options.sequential - Run tier queries sequentially with 429 retry (PERC-1650).\r\n */\r\nexport async function discoverMarkets(\r\n connection: Connection,\r\n programId: PublicKey,\r\n options: DiscoverMarketsOptions = {},\r\n): Promise {\r\n const {\r\n sequential = false,\r\n interTierDelayMs = 200,\r\n rateLimitBackoffMs = [1_000, 3_000, 9_000, 27_000],\r\n maxParallelTiers = 6,\r\n } = options;\r\n\r\n // Query all known slab sizes in parallel — V0, V1D (deployed devnet), V1D legacy, and V1 (upgraded) tiers.\r\n // We track the actual dataSize per entry so detectSlabLayout can determine the correct layout,\r\n // and pass that layout to all parse functions (avoids wrong-version offsets on partial slices).\r\n // GH#1205: V1D tiers were missing here — V1D slabs fell through to memcmp fallback with wrong\r\n // dataSize hints → detectSlabLayout returned null → parse failure in discoverMarkets.\r\n // GH#1237/GH#1238: SLAB_TIERS_V1D_LEGACY (postBitmap=18, e.g. 65,104-byte slabs created before\r\n // GH#1234) must also be included; omitting them causes legacy on-chain slabs to be missed by\r\n // dataSize filter queries and fall through to memcmp with wrong maxAccounts hint.\r\n // 2026-04-29: SLAB_TIERS_V12_19 added — same class of bug. v12.19 mainnet slabs (deployed\r\n // 2026-05-01 to ESa89R5...) produce 96784-byte (small) accounts that none of the older tiers\r\n // match. Without this entry, discoverMarkets on the upgraded program returns 0 markets via the\r\n // dataSize-filter path and falls through to memcmp with wrong layout hints.\r\n //\r\n // PR #199: Build ALL_TIERS via a Map keyed on dataSize to eliminate duplicate tier entries.\r\n // SLAB_TIERS and SLAB_TIERS_V12_17 are intentionally identical (both emit small/medium/large\r\n // v12.17 entries), producing duplicate dataSize values that caused redundant RPC calls.\r\n // Tie-break: keep the entry with higher maxAccounts (more capable parse context).\r\n const ALL_TIERS_RAW = [\r\n ...Object.values(SLAB_TIERS), // v12.17 (default)\r\n ...Object.values(SLAB_TIERS_V12_19), // v12.19 (deployed mainnet)\r\n ...Object.values(SLAB_TIERS_V12_17), // v12.17 (explicit)\r\n ...Object.values(SLAB_TIERS_V12_15), // v12.15\r\n ...Object.values(SLAB_TIERS_V12_1), // v12.1\r\n ...Object.values(SLAB_TIERS_V0),\r\n ...Object.values(SLAB_TIERS_V1D),\r\n ...Object.values(SLAB_TIERS_V1D_LEGACY),\r\n ...Object.values(SLAB_TIERS_V2),\r\n ...Object.values(SLAB_TIERS_V1M),\r\n ...Object.values(SLAB_TIERS_V1M2),\r\n ...Object.values(SLAB_TIERS_V_ADL),\r\n ...Object.values(SLAB_TIERS_V_SETDEXPOOL),\r\n ];\r\n const tierBySize = new Map();\r\n for (const tier of ALL_TIERS_RAW) {\r\n const existing = tierBySize.get(tier.dataSize);\r\n if (!existing || tier.maxAccounts > existing.maxAccounts) {\r\n tierBySize.set(tier.dataSize, tier);\r\n }\r\n }\r\n const ALL_TIERS = [...tierBySize.values()];\r\n type RawEntry = { pubkey: PublicKey; account: { data: Buffer | Uint8Array }; maxAccounts: number; dataSize: number };\r\n let rawAccounts: RawEntry[] = [];\r\n\r\n /**\r\n * Fetch one tier with per-attempt 429 retry (sequential mode only).\r\n * Returns an array of RawEntry on success, or an empty array after exhausting retries.\r\n */\r\n async function fetchTierWithRetry(\r\n tier: { dataSize: number; maxAccounts: number },\r\n ): Promise {\r\n for (let attempt = 0; attempt <= rateLimitBackoffMs.length; attempt++) {\r\n try {\r\n const results = await connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n return results.map(entry => ({ ...entry, maxAccounts: tier.maxAccounts, dataSize: tier.dataSize }));\r\n } catch (err) {\r\n if (isRateLimitError(err) && attempt < rateLimitBackoffMs.length) {\r\n const delay = withJitter(rateLimitBackoffMs[attempt]);\r\n console.warn(\r\n `[discoverMarkets] 429 on tier dataSize=${tier.dataSize} attempt=${attempt + 1}, backing off ${delay}ms`,\r\n );\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n // Non-429 or exhausted retries\r\n console.warn(\r\n `[discoverMarkets] Tier query failed (dataSize=${tier.dataSize}, attempt=${attempt + 1}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n return [];\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n const maxTierQueries = options.maxTierQueries ?? ALL_TIERS.length;\r\n const tiersToQuery = ALL_TIERS.slice(0, maxTierQueries);\r\n\r\n // Avoid accidental `0`/negative or NaN causing infinite loops.\r\n const effectiveMaxParallelTiers = Math.max(1, Number.isFinite(maxParallelTiers) ? maxParallelTiers : 6);\r\n\r\n try {\r\n if (sequential) {\r\n // PERC-1650: sequential mode — one tier at a time with inter-tier spacing + per-tier 429 retry.\r\n for (let i = 0; i < tiersToQuery.length; i++) {\r\n const tier = tiersToQuery[i];\r\n const entries = await fetchTierWithRetry(tier);\r\n rawAccounts.push(...entries);\r\n if (i < tiersToQuery.length - 1) {\r\n await new Promise(r => setTimeout(r, interTierDelayMs));\r\n }\r\n }\r\n } else {\r\n // Parallel mode: cap tier concurrency so we don't fire 20+ large\r\n // getProgramAccounts calls at once from a single client call.\r\n for (let offset = 0; offset < tiersToQuery.length; offset += effectiveMaxParallelTiers) {\r\n const chunk = tiersToQuery.slice(offset, offset + effectiveMaxParallelTiers);\r\n const queries = chunk.map(tier =>\r\n connection.getProgramAccounts(programId, {\r\n filters: [{ dataSize: tier.dataSize }],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n }).then(results =>\r\n results.map(entry => ({\r\n ...entry,\r\n maxAccounts: tier.maxAccounts,\r\n dataSize: tier.dataSize,\r\n })),\r\n ),\r\n );\r\n\r\n const results = await Promise.allSettled(queries);\r\n for (const result of results) {\r\n if (result.status === \"fulfilled\") {\r\n for (const entry of result.value) {\r\n rawAccounts.push(entry as RawEntry);\r\n }\r\n } else {\r\n console.warn(\r\n \"[discoverMarkets] Tier query rejected:\",\r\n result.reason instanceof Error ? result.reason.message : result.reason,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n // TASK C: Fetch v17 market group accounts via memcmp on the v17 magic bytes.\r\n // V17 accounts have dynamic sizes and do NOT appear in fixed dataSize tier filters.\r\n // The memcmp bytes are derived in-code from V17_MAGIC_BYTES (the on-chain LE order) via\r\n // base64 (web3.js >=1.87) so the filter cannot drift from / mis-order the magic constant.\r\n try {\r\n const v17Results = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: Buffer.from(V17_MAGIC_BYTES).toString(\"base64\"),\r\n encoding: \"base64\",\r\n },\r\n },\r\n ],\r\n dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH },\r\n });\r\n for (const e of v17Results) {\r\n rawAccounts.push({ ...e, maxAccounts: 0, dataSize: e.account.data.length } as RawEntry);\r\n }\r\n } catch {\r\n // v17 memcmp query is best-effort — silently ignore failures (RPC may reject getProgramAccounts)\r\n }\r\n\r\n // NOTE: hadRejection guard removed — dataSize filters silently return 0 when on-chain\r\n // account size changed; RPC returns no error, so we must fallback on empty results too.\r\n if (rawAccounts.length === 0) {\r\n console.warn(\"[discoverMarkets] dataSize filters returned 0 markets, falling back to memcmp\");\r\n // PR #183 / PR #166: fetch full account data (no dataSlice) so detectSlabLayout can\r\n // identify the actual tier from account.data.length instead of hardcoding large/4096.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n }\r\n } catch (err) {\r\n console.warn(\r\n \"[discoverMarkets] dataSize filters failed, falling back to memcmp:\",\r\n err instanceof Error ? err.message : err,\r\n );\r\n try {\r\n // PR #183 / PR #166: same full-data fetch as the empty-result fallback above.\r\n const fallback = await connection.getProgramAccounts(programId, {\r\n filters: [\r\n {\r\n memcmp: {\r\n offset: 0,\r\n bytes: \"F6P2QNqpQV5\", // base58 of TALOCREP (u64 LE magic)\r\n },\r\n },\r\n ],\r\n });\r\n rawAccounts = [...fallback].map(e => {\r\n const len = e.account.data.length;\r\n const lay = detectSlabLayout(len, new Uint8Array(e.account.data));\r\n return { ...e, maxAccounts: lay?.maxAccounts ?? 4096, dataSize: len };\r\n }) as RawEntry[];\r\n } catch (memcmpErr) {\r\n // GH#59: memcmp also rejected (public mainnet RPCs reject all getProgramAccounts)\r\n console.warn(\r\n \"[discoverMarkets] memcmp fallback also failed:\",\r\n memcmpErr instanceof Error ? memcmpErr.message : memcmpErr,\r\n );\r\n }\r\n }\r\n\r\n // GH#59 / PERC-8424: If getProgramAccounts returned nothing (public mainnet RPC\r\n // rejects it) and an API base URL is configured, fall back to the REST API to\r\n // discover slab addresses, then use getMarketsByAddress (getMultipleAccounts).\r\n if (rawAccounts.length === 0 && options.apiBaseUrl) {\r\n console.warn(\r\n \"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API\",\r\n );\r\n try {\r\n const apiResult = await discoverMarketsViaApi(\r\n connection,\r\n programId,\r\n options.apiBaseUrl,\r\n { timeoutMs: options.apiTimeoutMs },\r\n );\r\n if (apiResult.length > 0) {\r\n return apiResult;\r\n }\r\n // API returned 0 markets — fall through to tier 3\r\n console.warn(\r\n \"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle\",\r\n );\r\n } catch (apiErr) {\r\n console.warn(\r\n \"[discoverMarkets] API fallback also failed:\",\r\n apiErr instanceof Error ? apiErr.message : apiErr,\r\n );\r\n // Fall through to tier 3\r\n }\r\n }\r\n\r\n // PERC-8435: Tier 3 — static bundle fallback. If both getProgramAccounts and\r\n // the REST API failed (or returned 0 results) and a network hint is provided,\r\n // use the bundled static market list as a last-resort address directory.\r\n if (rawAccounts.length === 0 && options.network) {\r\n const staticEntries = getStaticMarkets(options.network);\r\n if (staticEntries.length > 0) {\r\n console.warn(\r\n `[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`,\r\n );\r\n try {\r\n return await discoverMarketsViaStaticBundle(\r\n connection,\r\n programId,\r\n staticEntries,\r\n );\r\n } catch (staticErr) {\r\n console.warn(\r\n \"[discoverMarkets] Static bundle fallback also failed:\",\r\n staticErr instanceof Error ? staticErr.message : staticErr,\r\n );\r\n // Fall through to return empty array\r\n }\r\n } else {\r\n console.warn(\r\n `[discoverMarkets] Static bundle has 0 entries for ${options.network} — skipping tier 3`,\r\n );\r\n }\r\n }\r\n\r\n const accounts = rawAccounts;\r\n\r\n const markets: DiscoveredMarket[] = [];\r\n // GH#1115: deduplicate raw accounts by pubkey — the same slab can appear in multiple\r\n // tier queries if both V0 and V1 sizes match or if the RPC returns duplicate entries.\r\n const seenPubkeys = new Set();\r\n\r\n for (const { pubkey, account, maxAccounts, dataSize } of accounts) {\r\n const pkStr = pubkey.toBase58();\r\n if (seenPubkeys.has(pkStr)) continue;\r\n seenPubkeys.add(pkStr);\r\n const data = new Uint8Array(account.data);\r\n\r\n // Check for v17 market group account (magic = \"PERCV16\\0\", kind == KIND_MARKET).\r\n // The data slice is HEADER_SLICE_LENGTH=1940 bytes, which exceeds the 512-byte\r\n // minimum needed by parseWrapperConfigV17 (post-protocol-fee; was 448). V17 accounts have dynamic sizes and\r\n // do NOT appear in the fixed-size tier queries; they reach this loop only via the\r\n // memcmp fallback or if the account happens to match a tier size by coincidence.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) so portfolio/ledger/\r\n // registry accounts — which share the magic+version but carry no WrapperConfigV16\r\n // — are not mis-parsed as markets.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse v17 account ${pkStr}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) continue;\r\n\r\n // Detect layout from actual slab size — not slice length — so parse functions\r\n // get correct V0/V1 offsets even when working on the partial HEADER_SLICE_LENGTH slice.\r\n // Pass the data buffer so V2 slabs (same size as V1D) can be disambiguated via version field.\r\n const layout = detectSlabLayout(dataSize, data);\r\n\r\n if (!layout) {\r\n console.warn(\r\n `[discoverMarkets] Skipping account ${pkStr}: unrecognized layout for dataSize=${dataSize}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[discoverMarkets] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n/**\r\n * Options for `getMarketsByAddress`.\r\n */\r\nexport interface GetMarketsByAddressOptions {\r\n /**\r\n * Maximum number of addresses per `getMultipleAccounts` RPC call.\r\n * Solana limits a single call to 100 accounts; callers may lower this\r\n * to reduce per-request payload size or avoid 429s.\r\n *\r\n * Default: 100 (Solana maximum).\r\n */\r\n batchSize?: number;\r\n\r\n /**\r\n * Delay in ms between batches when the address list exceeds `batchSize`.\r\n * Helps avoid rate-limiting on public RPCs.\r\n *\r\n * Default: 0 (no delay).\r\n */\r\n interBatchDelayMs?: number;\r\n}\r\n\r\n/**\r\n * Fetch and parse Percolator markets by their known slab addresses.\r\n *\r\n * Unlike `discoverMarkets()` — which uses `getProgramAccounts` and is blocked\r\n * on public mainnet RPCs — this function uses `getMultipleAccounts`, which works\r\n * on any RPC endpoint (including `api.mainnet-beta.solana.com`).\r\n *\r\n * Callers must already know the market slab addresses (e.g. from an indexer,\r\n * a hardcoded registry, or a previous `discoverMarkets` call on a permissive RPC).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param programId - The Percolator program that owns these slabs\r\n * @param addresses - Array of slab account public keys to fetch\r\n * @param options - Optional batching/delay configuration\r\n * @returns Parsed markets for all valid slab accounts; invalid/missing accounts are silently skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getMarketsByAddress, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection, PublicKey } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const slabs = [\r\n * new PublicKey(\"So11111111111111111111111111111111111111112\"),\r\n * // ... more known slab addresses\r\n * ];\r\n *\r\n * const markets = await getMarketsByAddress(connection, programId, slabs);\r\n * console.log(`Found ${markets.length} markets`);\r\n * ```\r\n */\r\nexport async function getMarketsByAddress(\r\n connection: Connection,\r\n programId: PublicKey,\r\n addresses: PublicKey[],\r\n options: GetMarketsByAddressOptions = {},\r\n): Promise {\r\n if (addresses.length === 0) return [];\r\n\r\n const {\r\n batchSize = 100,\r\n interBatchDelayMs = 0,\r\n } = options;\r\n\r\n const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));\r\n\r\n // Fetch account data in batches (Solana caps getMultipleAccounts at 100)\r\n type AccountResult = { pubkey: PublicKey; data: Buffer | Uint8Array } | null;\r\n const fetched: AccountResult[] = [];\r\n\r\n for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {\r\n const batch = addresses.slice(offset, offset + effectiveBatchSize);\r\n\r\n const response = await connection.getMultipleAccountsInfo(batch);\r\n\r\n for (let i = 0; i < batch.length; i++) {\r\n const info = response[i];\r\n if (info && info.data) {\r\n if (!info.owner.equals(programId)) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch ` +\r\n `(expected ${programId.toBase58()}, got ${info.owner.toBase58()})`,\r\n );\r\n continue;\r\n }\r\n fetched.push({ pubkey: batch[i], data: info.data });\r\n }\r\n }\r\n\r\n // Inter-batch delay to avoid rate-limiting\r\n if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {\r\n await new Promise(r => setTimeout(r, interBatchDelayMs));\r\n }\r\n }\r\n\r\n // Parse each account into a DiscoveredMarket\r\n const markets: DiscoveredMarket[] = [];\r\n\r\n for (const entry of fetched) {\r\n if (!entry) continue;\r\n const { pubkey, data: rawData } = entry;\r\n const data = new Uint8Array(rawData);\r\n\r\n // Gate: check for a v17 MARKET account first, then fall through to v12 slab path.\r\n // #264: gate on isV17MarketAccount (kind byte @10 == 1) — portfolio/ledger/registry\r\n // accounts share the magic+version but are not markets and carry no WrapperConfigV16.\r\n if (isV17MarketAccount(data)) {\r\n try {\r\n const configV17 = parseWrapperConfigV17(data);\r\n // v17 accounts have no slab header/config/engine/params; supply defaults so\r\n // the DiscoveredMarket type is satisfied. Callers should check configV17 !== undefined\r\n // to detect a v17 market.\r\n markets.push({\r\n slabAddress: pubkey,\r\n programId,\r\n header: {} as SlabHeader,\r\n config: {} as MarketConfig,\r\n engine: {} as EngineState,\r\n params: {} as RiskParams,\r\n configV17,\r\n });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse v17 account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n // Validate v12 magic bytes\r\n let valid = true;\r\n for (let i = 0; i < MAGIC_BYTES.length; i++) {\r\n if (data[i] !== MAGIC_BYTES[i]) {\r\n valid = false;\r\n break;\r\n }\r\n }\r\n if (!valid) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`,\r\n );\r\n continue;\r\n }\r\n\r\n // Detect layout from full account data length\r\n const layout = detectSlabLayout(data.length, data);\r\n if (!layout) {\r\n console.warn(\r\n `[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`,\r\n );\r\n continue;\r\n }\r\n\r\n try {\r\n const header = parseHeader(data);\r\n const config = parseConfig(data, layout);\r\n const engine = parseEngineLight(data, layout, layout.maxAccounts);\r\n const params = parseParams(data, layout);\r\n\r\n markets.push({ slabAddress: pubkey, programId, header, config, engine, params });\r\n } catch (err) {\r\n console.warn(\r\n `[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n }\r\n\r\n return markets;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// REST API-based market discovery (GH#59 / PERC-8424)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Shape of a single market entry returned by the Percolator REST API\r\n * (`GET /markets`). Only the fields needed for discovery are typed here;\r\n * the full API response may contain additional statistics fields.\r\n */\r\nexport interface ApiMarketEntry {\r\n slab_address: string;\r\n symbol?: string;\r\n name?: string;\r\n decimals?: number;\r\n status?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Options for {@link discoverMarketsViaApi}. */\r\nexport interface DiscoverMarketsViaApiOptions {\r\n /**\r\n * Timeout in ms for the HTTP request to the REST API.\r\n * Default: 10_000 (10 seconds).\r\n */\r\n timeoutMs?: number;\r\n\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets by first querying the REST API for slab addresses,\r\n * then fetching full on-chain data via `getMarketsByAddress` (which uses\r\n * `getMultipleAccounts` — works on all RPCs including public mainnet nodes).\r\n *\r\n * This is the recommended discovery path for mainnet users who do not have a\r\n * Helius API key, since `getProgramAccounts` is rejected by public RPCs.\r\n *\r\n * The REST API acts as an address directory only — all market data is verified\r\n * on-chain via `getMarketsByAddress`, so the caller gets the same\r\n * `DiscoveredMarket[]` result as `discoverMarkets()`.\r\n *\r\n * @param connection - Solana RPC connection (any endpoint, including public)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param apiBaseUrl - Base URL of the Percolator REST API\r\n * (e.g. `\"https://percolatorlaunch.com/api\"`)\r\n * @param options - Optional timeout and on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts discovered via the API\r\n *\r\n * @example\r\n * ```ts\r\n * import { discoverMarketsViaApi, getProgramId } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const markets = await discoverMarketsViaApi(\r\n * connection,\r\n * programId,\r\n * \"https://percolatorlaunch.com/api\",\r\n * );\r\n * console.log(`Discovered ${markets.length} markets via API fallback`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaApi(\r\n connection: Connection,\r\n programId: PublicKey,\r\n apiBaseUrl: string,\r\n options: DiscoverMarketsViaApiOptions = {},\r\n): Promise {\r\n const { timeoutMs = 10_000, onChainOptions } = options;\r\n\r\n // Normalise base URL — strip trailing slash to avoid double-slash in path\r\n const base = apiBaseUrl.replace(/\\/+$/, \"\");\r\n const url = `${base}/markets`;\r\n\r\n // Fetch market list from REST API\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let response: Response;\r\n try {\r\n response = await fetch(url, {\r\n method: \"GET\",\r\n headers: { Accept: \"application/json\" },\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`,\r\n );\r\n }\r\n\r\n const body = (await response.json()) as { markets?: ApiMarketEntry[] };\r\n const apiMarkets = body.markets;\r\n\r\n if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] API returned 0 markets\");\r\n return [];\r\n }\r\n\r\n // Extract valid slab addresses\r\n const addresses: PublicKey[] = [];\r\n for (const entry of apiMarkets) {\r\n if (!entry.slab_address || typeof entry.slab_address !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slab_address));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaApi] No valid slab addresses from API\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`,\r\n );\r\n\r\n // Fetch full on-chain data via getMultipleAccounts (works on all RPCs)\r\n return getMarketsByAddress(connection, programId, addresses, onChainOptions);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Static bundle fallback (PERC-8435 — tier 3)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options for {@link discoverMarketsViaStaticBundle}. */\r\nexport interface DiscoverMarketsViaStaticBundleOptions {\r\n /**\r\n * Options forwarded to {@link getMarketsByAddress} for the on-chain fetch\r\n * step (batch size, inter-batch delay).\r\n */\r\n onChainOptions?: GetMarketsByAddressOptions;\r\n}\r\n\r\n/**\r\n * Discover Percolator markets from a static list of known slab addresses.\r\n *\r\n * This is the tier-3 (last-resort) fallback for `discoverMarkets()`. It uses\r\n * a bundled list of known slab addresses and fetches their full account data\r\n * on-chain via `getMarketsByAddress` (`getMultipleAccounts` — works on all RPCs).\r\n *\r\n * The static list acts as an address directory only — all market data is verified\r\n * on-chain, so stale entries are silently skipped (the account won't have valid\r\n * magic bytes or will have been closed).\r\n *\r\n * @param connection - Solana RPC connection (any endpoint)\r\n * @param programId - The Percolator program that owns the slabs\r\n * @param entries - Static market entries (typically from {@link getStaticMarkets})\r\n * @param options - Optional on-chain fetch configuration\r\n * @returns Parsed markets for all valid slab accounts; stale/missing entries are skipped.\r\n *\r\n * @example\r\n * ```ts\r\n * import {\r\n * discoverMarketsViaStaticBundle,\r\n * getStaticMarkets,\r\n * getProgramId,\r\n * } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const connection = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const programId = getProgramId(\"mainnet\");\r\n * const entries = getStaticMarkets(\"mainnet\");\r\n *\r\n * const markets = await discoverMarketsViaStaticBundle(\r\n * connection,\r\n * programId,\r\n * entries,\r\n * );\r\n * console.log(`Recovered ${markets.length} markets from static bundle`);\r\n * ```\r\n */\r\nexport async function discoverMarketsViaStaticBundle(\r\n connection: Connection,\r\n programId: PublicKey,\r\n entries: StaticMarketEntry[],\r\n options: DiscoverMarketsViaStaticBundleOptions = {},\r\n): Promise {\r\n if (entries.length === 0) return [];\r\n\r\n // Extract valid slab addresses from static entries\r\n const addresses: PublicKey[] = [];\r\n for (const entry of entries) {\r\n if (!entry.slabAddress || typeof entry.slabAddress !== \"string\") continue;\r\n try {\r\n addresses.push(new PublicKey(entry.slabAddress));\r\n } catch {\r\n console.warn(\r\n `[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`,\r\n );\r\n }\r\n }\r\n\r\n if (addresses.length === 0) {\r\n console.warn(\"[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle\");\r\n return [];\r\n }\r\n\r\n console.log(\r\n `[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`,\r\n );\r\n\r\n return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);\r\n}\r\n","/**\r\n * Static market registry — bundled list of known Percolator slab addresses.\r\n *\r\n * This is the tier-3 fallback for `discoverMarkets()`: when both\r\n * `getProgramAccounts` (tier 1) and the REST API (tier 2) are unavailable,\r\n * the SDK falls back to this bundled list to bootstrap market discovery.\r\n *\r\n * The addresses are fetched on-chain via `getMarketsByAddress`\r\n * (`getMultipleAccounts`), so all data is still verified on-chain. The static\r\n * list only provides the *address directory* — no cached market data is used.\r\n *\r\n * ## Maintenance\r\n *\r\n * Update this list when new markets are deployed or old ones are retired.\r\n * Run `scripts/update-static-markets.ts` to regenerate from a permissive RPC\r\n * or the REST API.\r\n *\r\n * @module\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\nimport type { Network } from \"../config/program-ids.js\";\r\n\r\n/**\r\n * A single entry in the static market registry.\r\n *\r\n * Only the slab address (base58) is required. Optional metadata fields\r\n * (`symbol`, `name`) are provided for debugging/logging purposes only —\r\n * they are **not** used for on-chain data and may become stale.\r\n */\r\nexport interface StaticMarketEntry {\r\n /** Base58-encoded slab account address. */\r\n slabAddress: string;\r\n /** Optional human-readable symbol (e.g. \"SOL-PERP\"). */\r\n symbol?: string;\r\n /** Optional descriptive name. */\r\n name?: string;\r\n}\r\n\r\n/**\r\n * Known mainnet market slab addresses.\r\n *\r\n * These are the markets deployed to the mainnet Percolator program\r\n * (`ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv`).\r\n *\r\n * **Last updated:** 2026-04-11 (V12_1_EP mainnet market with entry_price support).\r\n */\r\nconst MAINNET_MARKETS: StaticMarketEntry[] = [\r\n { slabAddress: \"7psyeWRts4pRX2cyAWD1NH87bR9ugXP7pe6ARgfG79Do\", symbol: \"SOL-PERP\", name: \"SOL/USDC Perpetual\" },\r\n];\r\n\r\n/**\r\n * Known devnet market slab addresses.\r\n *\r\n * These are discovered from the devnet Percolator program\r\n * (`FxfD37s1AZTeWfFQps9Zpebi2dNQ9QSSDtfMKdbsfKrD`).\r\n *\r\n * **Last updated:** 2026-04-04.\r\n */\r\nconst DEVNET_MARKETS: StaticMarketEntry[] = [\r\n // Populated from prior discoverMarkets() runs on devnet.\r\n // These serve as the tier-3 safety net for devnet users.\r\n];\r\n\r\n/**\r\n * Full static registry indexed by network.\r\n */\r\nconst STATIC_REGISTRY: Record = {\r\n mainnet: MAINNET_MARKETS,\r\n devnet: DEVNET_MARKETS,\r\n};\r\n\r\n/**\r\n * User-provided market entries appended at runtime via {@link registerStaticMarkets}.\r\n * Keyed by network.\r\n */\r\nconst USER_MARKETS: Record = {\r\n mainnet: [],\r\n devnet: [],\r\n};\r\n\r\n/**\r\n * Get the bundled static market list for a given network.\r\n *\r\n * Returns the built-in list merged with any entries added via\r\n * {@link registerStaticMarkets}. Duplicates (by `slabAddress`) are removed\r\n * automatically — user-registered entries take precedence.\r\n *\r\n * @param network - Target network (`\"mainnet\"` or `\"devnet\"`)\r\n * @returns Array of static market entries (may be empty if no markets are known)\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * const markets = getStaticMarkets(\"mainnet\");\r\n * console.log(`${markets.length} known mainnet slab addresses`);\r\n * ```\r\n */\r\nexport function getStaticMarkets(network: Network): StaticMarketEntry[] {\r\n const builtin = STATIC_REGISTRY[network] ?? [];\r\n const user = USER_MARKETS[network] ?? [];\r\n\r\n if (user.length === 0) return [...builtin];\r\n\r\n // Merge: user entries override builtin entries with same slabAddress\r\n const seen = new Map();\r\n for (const entry of builtin) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n for (const entry of user) {\r\n seen.set(entry.slabAddress, entry);\r\n }\r\n return [...seen.values()];\r\n}\r\n\r\n/**\r\n * Register additional static market entries at runtime.\r\n *\r\n * Use this to inject known slab addresses before calling `discoverMarkets()`\r\n * so that tier-3 fallback has addresses to work with — especially useful\r\n * right after mainnet launch when the bundled list may be empty.\r\n *\r\n * Entries are deduplicated by `slabAddress` — calling this multiple times\r\n * with the same address is safe.\r\n *\r\n * @param network - Target network\r\n * @param entries - One or more static market entries to register\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerStaticMarkets } from \"@percolator/sdk\";\r\n *\r\n * registerStaticMarkets(\"mainnet\", [\r\n * { slabAddress: \"ABC123...\", symbol: \"SOL-PERP\" },\r\n * { slabAddress: \"DEF456...\", symbol: \"ETH-PERP\" },\r\n * ]);\r\n * ```\r\n */\r\nexport function registerStaticMarkets(\r\n network: Network,\r\n entries: StaticMarketEntry[],\r\n): void {\r\n const existing = USER_MARKETS[network];\r\n const seen = new Set(existing.map(e => e.slabAddress));\r\n\r\n for (const entry of entries) {\r\n if (!entry.slabAddress) continue;\r\n if (seen.has(entry.slabAddress)) continue;\r\n // Validate that slabAddress is a valid base58 public key\r\n try {\r\n new PublicKey(entry.slabAddress);\r\n } catch {\r\n console.warn(\r\n `[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`,\r\n );\r\n continue;\r\n }\r\n seen.add(entry.slabAddress);\r\n existing.push(entry);\r\n }\r\n}\r\n\r\n/**\r\n * Clear all user-registered static market entries for a network.\r\n *\r\n * Useful in tests or when resetting state.\r\n *\r\n * @param network - Target network to clear (omit to clear all networks)\r\n */\r\nexport function clearStaticMarkets(network?: Network): void {\r\n if (network) {\r\n USER_MARKETS[network] = [];\r\n } else {\r\n USER_MARKETS.mainnet = [];\r\n USER_MARKETS.devnet = [];\r\n }\r\n}\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport {\r\n PUMPSWAP_PROGRAM_ID,\r\n RAYDIUM_CLMM_PROGRAM_ID,\r\n METEORA_DLMM_PROGRAM_ID,\r\n} from \"./pda.js\";\r\n\r\nexport type DexType = \"pumpswap\" | \"raydium-clmm\" | \"meteora-dlmm\";\r\n\r\nexport interface DexPoolInfo {\r\n dexType: DexType;\r\n poolAddress: PublicKey;\r\n baseMint: PublicKey;\r\n quoteMint: PublicKey;\r\n baseVault?: PublicKey; // PumpSwap only\r\n quoteVault?: PublicKey; // PumpSwap only\r\n}\r\n\r\n/**\r\n * Detect DEX type from the program that owns the pool account.\r\n *\r\n * @param ownerProgramId - The program ID that owns the pool account\r\n * @returns The detected DEX type, or `null` if the owner is not a supported DEX program\r\n *\r\n * Supported DEX programs:\r\n * - PumpSwap (constant-product AMM)\r\n * - Raydium CLMM (concentrated liquidity)\r\n * - Meteora DLMM (discretized liquidity)\r\n */\r\nexport function detectDexType(ownerProgramId: PublicKey): DexType | null {\r\n if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return \"pumpswap\";\r\n if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return \"raydium-clmm\";\r\n if (ownerProgramId.equals(METEORA_DLMM_PROGRAM_ID)) return \"meteora-dlmm\";\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse a DEX pool account into a {@link DexPoolInfo} struct.\r\n *\r\n * @param dexType - The type of DEX (pumpswap, raydium-clmm, or meteora-dlmm)\r\n * @param poolAddress - The on-chain address of the pool account\r\n * @param data - Raw account data bytes\r\n * @returns Parsed pool info including mints and (for PumpSwap) vault addresses\r\n * @throws Error if data is too short for the given DEX type\r\n */\r\nexport function parseDexPool(\r\n dexType: DexType,\r\n poolAddress: PublicKey,\r\n data: Uint8Array,\r\n): DexPoolInfo {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n return parsePumpSwapPool(poolAddress, data);\r\n case \"raydium-clmm\":\r\n return parseRaydiumClmmPool(poolAddress, data);\r\n case \"meteora-dlmm\":\r\n return parseMeteoraPool(poolAddress, data);\r\n }\r\n}\r\n\r\n/**\r\n * Compute the spot price from a DEX pool in e6 format (i.e., 1.0 = 1_000_000).\r\n *\r\n * **SECURITY NOTE:** DEX spot prices have no staleness or confidence checks and are\r\n * vulnerable to flash-loan manipulation within a single transaction. For high-value\r\n * markets, prefer Pyth or Chainlink oracles.\r\n *\r\n * @param dexType - The type of DEX\r\n * @param data - Raw pool account data\r\n * @param vaultData - For PumpSwap only: base and quote vault account data\r\n * @param decimals - Base/quote mint decimals. REQUIRED for meteora-dlmm and pumpswap\r\n * (neither pool layout stores decimals inline in a form usable without a mint lookup);\r\n * ignored for raydium-clmm (decimals are embedded in the pool account).\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. Only consulted for PumpSwap\r\n * pools whose quote mint is native WSOL (the vast majority of pump.fun pools) — see\r\n * {@link computePumpSwapPriceE6} for the conversion. Ignored for all other dex types\r\n * and for PumpSwap pools quoted in a non-WSOL mint.\r\n * @returns Price in e6 format. For pumpswap/raydium-clmm/meteora-dlmm quoted in USDC\r\n * (or another USD-pegged stable), this is already a USD price. For pumpswap pools\r\n * quoted in WSOL, this is a USD price ONLY if `solPriceE6` was supplied — otherwise\r\n * {@link computePumpSwapPriceE6} throws rather than silently returning a token/SOL\r\n * price mislabeled as USD.\r\n * @throws Error if data is too short, required params are missing, or computation fails\r\n */\r\nexport function computeDexSpotPriceE6(\r\n dexType: DexType,\r\n data: Uint8Array,\r\n vaultData?: { base: Uint8Array; quote: Uint8Array },\r\n decimals?: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n switch (dexType) {\r\n case \"pumpswap\":\r\n if (!vaultData) throw new Error(\"PumpSwap requires vaultData (base and quote vault accounts)\");\r\n // #PS-1: base/quote mint decimals were not applied to the raw vault-reserve\r\n // ratio (pump.fun tokens are 6dp, WSOL is 9dp) — a 1000x mispricing. The caller\r\n // MUST supply decimals (fetched from the base/quote mints), matching the\r\n // meteora-dlmm contract below.\r\n if (!decimals) {\r\n throw new Error(\"PumpSwap requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computePumpSwapPriceE6(data, vaultData, decimals, solPriceE6);\r\n case \"raydium-clmm\":\r\n return computeRaydiumClmmPriceE6(data);\r\n case \"meteora-dlmm\":\r\n // #226: Meteora's LbPair does not store token decimals inline, so the caller MUST\r\n // supply them (fetched from the base/quote mints). Without the decimal adjustment\r\n // the mark price is wrong by 10^(decBase-decQuote) → mass mispricing/liquidations.\r\n if (!decimals) {\r\n throw new Error(\"Meteora DLMM requires decimals { base, quote } (mint decimals)\");\r\n }\r\n return computeMeteoraDlmmPriceE6(data, decimals.base, decimals.quote);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Mint decimals helper\r\n// ============================================================================\r\n\r\n/**\r\n * Offset of the `decimals` byte in a standard SPL Mint account. Exported so\r\n * callers that batch-fetch several mint accounts in one `getMultipleAccountsInfo`\r\n * (e.g. to resolve PumpSwap base/quote decimals without N extra RPC round-trips)\r\n * can read this field directly instead of duplicating the magic number.\r\n */\r\nexport const SPL_MINT_DECIMALS_OFFSET = 44;\r\n\r\n/**\r\n * Read the `decimals` field of any SPL mint account (including native WSOL).\r\n *\r\n * This replaces `getMint(connection, mint).decimals` for callers that need to\r\n * supply decimals to {@link computeDexSpotPriceE6} for Meteora DLMM pools.\r\n * `getMint()` throws on native WSOL (`So11111111111111111111111111111111111111112`)\r\n * because the system account is not a valid token-program mint; this function\r\n * reads raw account data and extracts byte 44 directly, which works for all\r\n * SPL mints, Token-2022 mints, and native WSOL (which stores `9` at that byte).\r\n *\r\n * @param connection - Solana RPC connection\r\n * @param mint - The mint public key to query\r\n * @returns The `decimals` field value (0–255)\r\n * @throws Error if the account does not exist or is too short to hold a mint\r\n *\r\n * @example\r\n * ```ts\r\n * import { fetchMintDecimals, computeDexSpotPriceE6 } from \"@percolator/sdk\";\r\n *\r\n * const baseDecimals = await fetchMintDecimals(connection, pool.baseMint);\r\n * const quoteDecimals = await fetchMintDecimals(connection, pool.quoteMint);\r\n * const priceE6 = computeDexSpotPriceE6(\"meteora-dlmm\", poolData, undefined, {\r\n * base: baseDecimals,\r\n * quote: quoteDecimals,\r\n * });\r\n * ```\r\n */\r\nexport async function fetchMintDecimals(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) {\r\n throw new Error(`fetchMintDecimals: account not found for mint ${mint.toBase58()}`);\r\n }\r\n if (info.data.length <= SPL_MINT_DECIMALS_OFFSET) {\r\n throw new Error(\r\n `fetchMintDecimals: account data too short (${info.data.length} bytes) for mint ${mint.toBase58()}`,\r\n );\r\n }\r\n return info.data[SPL_MINT_DECIMALS_OFFSET];\r\n}\r\n\r\n// ============================================================================\r\n// PumpSwap\r\n// ============================================================================\r\n\r\n/**\r\n * Native SOL mint — PumpSwap pools overwhelmingly quote in this. Exported so\r\n * callers can pre-check `parsed.quoteMint.equals(WSOL_MINT)` before deciding\r\n * whether a `solPriceE6` conversion is needed, without duplicating the address.\r\n */\r\nexport const WSOL_MINT = new PublicKey(\"So11111111111111111111111111111111111111112\");\r\n\r\n// PumpSwap (pump.fun AMM, program pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA) `Pool`\r\n// account layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8] pool_bump u8\r\n// [9:11] index u16\r\n// [11:43] creator Pubkey\r\n// [43:75] base_mint Pubkey ← corrected from erroneous 35\r\n// [75:107] quote_mint Pubkey ← corrected from erroneous 67\r\n// [107:139] lp_mint Pubkey\r\n// [139:171] pool_base_token_account Pubkey ← corrected from erroneous 131\r\n// [171:203] pool_quote_token_account Pubkey ← corrected from erroneous 163\r\n// [203:211] lp_supply u64\r\n// [211:243] coin_creator Pubkey\r\n//\r\n// The OLD offsets (35/67/131/163) were uniformly 8 bytes short of the real fields\r\n// — every prior read was silently pulling from inside the PRECEDING field (e.g. the\r\n// tail of `creator` instead of `base_mint`), producing plausible-looking but wrong\r\n// pubkeys. Verified against the live ANSEM pool on mainnet\r\n// (`FnzKY6x7entQ1eR3D225dQyT7ybfka4PskBMQhb8L3CC`, Jul 2026): base_mint decodes to\r\n// `9cRCn9rGT8V2imeM2BaKs13yhMEais3ruM3rPvTGpump` (matches the known ANSEM mint) and\r\n// pool_quote_token_account decodes to the pool's actual WSOL vault, independently\r\n// confirmed via `getTokenAccountsByOwner(pool)` (owner = pool PDA, ~15,062 SOL\r\n// balance at verification time). Note the base vault (holding the pump.fun token)\r\n// is an SPL **Token-2022** account (immutableOwner extension), while the quote\r\n// (WSOL) vault is a classic SPL Token account — fetch each with the correct program.\r\nconst PUMPSWAP_MIN_LEN = 203; // through end of pool_quote_token_account (171 + 32)\r\n\r\n/**\r\n * Parse a PumpSwap constant-product AMM pool account.\r\n * @internal\r\n */\r\nfunction parsePumpSwapPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${data.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"pumpswap\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(43, 75)),\r\n quoteMint: new PublicKey(data.slice(75, 107)),\r\n baseVault: new PublicKey(data.slice(139, 171)),\r\n quoteVault: new PublicKey(data.slice(171, 203)),\r\n };\r\n}\r\n\r\nconst SPL_TOKEN_AMOUNT_MIN_LEN = 72;\r\n\r\n/**\r\n * Compute PumpSwap spot price, decimal-adjusted and (when quoted in WSOL)\r\n * converted to USD.\r\n *\r\n * Formula: `price = (quote_raw / 10^quoteDecimals) / (base_raw / 10^baseDecimals)`\r\n *\r\n * #PS-1/#PS-2 fix: the previous implementation computed `quote_raw / base_raw`\r\n * directly on RAW token-account amounts, ignoring mint decimals entirely. Since\r\n * pump.fun base tokens are almost always 6dp and the WSOL quote is 9dp, this\r\n * silently mispriced every PumpSwap market by exactly 1000x. It also returned a\r\n * token/SOL ratio unconverted — for a WSOL-quoted pool that is not a USD price\r\n * at all unless multiplied by the SOL/USD rate.\r\n *\r\n * @param poolData - Raw pool account data (used to read `quote_mint` and decide\r\n * whether SOL→USD conversion applies)\r\n * @param vaultData - Base and quote vault (SPL token account) raw data\r\n * @param decimals - Base/quote mint decimals (fetch via {@link fetchMintDecimals})\r\n * @param solPriceE6 - Current SOL/USD price in e6 format. REQUIRED when the pool's\r\n * quote mint is native WSOL (`So111...112`) — throws otherwise, rather than\r\n * silently returning a token/SOL price mislabeled as USD. Ignored for pools\r\n * quoted in a non-WSOL mint (already ~USD, e.g. a hypothetical USDC-quoted\r\n * PumpSwap pool).\r\n * @internal\r\n */\r\nfunction computePumpSwapPriceE6(\r\n poolData: Uint8Array,\r\n vaultData: { base: Uint8Array; quote: Uint8Array },\r\n decimals: { base: number; quote: number },\r\n solPriceE6?: bigint,\r\n): bigint {\r\n if (poolData.length < PUMPSWAP_MIN_LEN) {\r\n throw new Error(`PumpSwap pool data too short: ${poolData.length} < ${PUMPSWAP_MIN_LEN}`);\r\n }\r\n if (vaultData.base.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap base vault data too short: ${vaultData.base.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n if (vaultData.quote.length < SPL_TOKEN_AMOUNT_MIN_LEN) {\r\n throw new Error(`PumpSwap quote vault data too short: ${vaultData.quote.length} < ${SPL_TOKEN_AMOUNT_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"PumpSwap\", \"base\", decimals.base);\r\n assertTokenDecimals(\"PumpSwap\", \"quote\", decimals.quote);\r\n\r\n const baseDv = new DataView(vaultData.base.buffer, vaultData.base.byteOffset, vaultData.base.byteLength);\r\n const quoteDv = new DataView(vaultData.quote.buffer, vaultData.quote.byteOffset, vaultData.quote.byteLength);\r\n\r\n const baseAmount = readU64LE(baseDv, 64);\r\n const quoteAmount = readU64LE(quoteDv, 64);\r\n\r\n if (baseAmount === 0n) return 0n;\r\n\r\n // Deferred truncation (same philosophy as Raydium #210 / Meteora #226): scale\r\n // the numerator by both the base-decimal correction AND the 1e6 output scale\r\n // before the single division, so low-priced tokens don't truncate to 0n.\r\n // price = (quote_raw / 10^quoteDec) / (base_raw / 10^baseDec)\r\n // price_e6 = quote_raw * 10^baseDec * 1e6 / (10^quoteDec * base_raw)\r\n const baseScale = 10n ** BigInt(decimals.base);\r\n const quoteScale = 10n ** BigInt(decimals.quote);\r\n const quotePerBaseE6 = (quoteAmount * baseScale * 1_000_000n) / (quoteScale * baseAmount);\r\n\r\n const quoteMint = new PublicKey(poolData.slice(75, 107));\r\n if (quoteMint.equals(WSOL_MINT)) {\r\n // #PS-3: pump.fun pools quote in WSOL, not USD. Convert token/SOL → token/USD.\r\n if (solPriceE6 === undefined) {\r\n throw new Error(\r\n \"PumpSwap: pool is WSOL-quoted but no solPriceE6 was supplied — cannot \" +\r\n \"convert to USD. Pass the current SOL/USD price (e6) to computeDexSpotPriceE6.\",\r\n );\r\n }\r\n return (quotePerBaseE6 * solPriceE6) / 1_000_000n;\r\n }\r\n // Non-WSOL quote mint (e.g. a hypothetical USDC-quoted PumpSwap pool) is\r\n // already ~USD once decimal-adjusted — no further conversion needed.\r\n return quotePerBaseE6;\r\n}\r\n\r\n// ============================================================================\r\n// Raydium CLMM\r\n// ============================================================================\r\n\r\nconst RAYDIUM_CLMM_MIN_LEN = 269; // need at least through sqrt_price_x64 (253 + 16)\r\n\r\n/**\r\n * Parse a Raydium CLMM (concentrated liquidity) pool account.\r\n * @internal\r\n */\r\nfunction parseRaydiumClmmPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM pool data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"raydium-clmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(73, 105)),\r\n quoteMint: new PublicKey(data.slice(105, 137)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Raydium CLMM spot price from sqrt_price_x64 (Q64.64 fixed-point).\r\n *\r\n * Formula: `price_e6 = (sqrt^2 / 2^128) * 10^(6 + decimals0 - decimals1)`\r\n *\r\n * Uses a precision-preserving approach: scales sqrt by 1e6 before shifting,\r\n * preventing zero results for micro-priced tokens (memecoins where sqrt < 2^64).\r\n *\r\n * @internal\r\n */\r\nconst MAX_TOKEN_DECIMALS = 24;\r\n\r\nfunction assertTokenDecimals(dexName: string, label: string, decimals: number): void {\r\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `${dexName}: ${label} decimals out of range (${decimals}); expected integer 0..${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n}\r\n\r\nfunction computeRaydiumClmmPriceE6(data: Uint8Array): bigint {\r\n if (data.length < RAYDIUM_CLMM_MIN_LEN) {\r\n throw new Error(`Raydium CLMM data too short: ${data.length} < ${RAYDIUM_CLMM_MIN_LEN}`);\r\n }\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n const decimals0 = data[233];\r\n const decimals1 = data[234];\r\n\r\n if (decimals0 > MAX_TOKEN_DECIMALS || decimals1 > MAX_TOKEN_DECIMALS) {\r\n throw new Error(\r\n `Raydium CLMM: decimals out of range (${decimals0}, ${decimals1}); max ${MAX_TOKEN_DECIMALS}`,\r\n );\r\n }\r\n\r\n const sqrtPriceX64 = readU128LE(dv, 253);\r\n\r\n if (sqrtPriceX64 === 0n) return 0n;\r\n\r\n // #210: defer truncation to a single shift at the very end. The previous form\r\n // truncated twice (`>> 64` then `>> 64`) BEFORE applying the decimal scale, so for\r\n // low-priced / large-decimal-asymmetry assets (e.g. decimals0=18, decimals1=6) the\r\n // raw value truncated to 0n before being scaled up by 10^12 — silently returning 0n.\r\n // Fold the decimal scale into the numerator/denominator and truncate exactly ONCE.\r\n // BigInt is arbitrary-precision, so the squared term cannot overflow.\r\n // priceE6 = (sqrtPriceX64 / 2^64)^2 * 1e6 * 10^adjustedDiff\r\n // = sqrtPriceX64^2 * 1e6 * 10^adjustedDiff >> 128\r\n const sq1e6 = sqrtPriceX64 * sqrtPriceX64 * 1_000_000n;\r\n\r\n const decimalDiff = 6 + decimals0 - decimals1;\r\n const adjustedDiff = decimalDiff - 6;\r\n\r\n if (adjustedDiff >= 0) {\r\n return (sq1e6 * 10n ** BigInt(adjustedDiff)) >> 128n;\r\n } else {\r\n return sq1e6 / ((1n << 128n) * 10n ** BigInt(-adjustedDiff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Meteora DLMM\r\n// ============================================================================\r\n\r\n// Meteora DLMM LbPair struct layout (Anchor discriminator = 8 bytes):\r\n// [0:8] discriminator\r\n// [8:40] parameters (StaticParameters, 32 bytes)\r\n// [40:72] v_parameters (VariableParameters, 32 bytes)\r\n// [72] bump_seed u8\r\n// [73:75] bin_step_seed [u8;2]\r\n// [75] pair_type u8\r\n// [76:80] active_id i32\r\n// [80:82] bin_step u16\r\n// [82] status u8\r\n// [83] require_base_factor_seed u8\r\n// [84:86] base_factor_seed [u8;2]\r\n// [86] activation_type u8\r\n// [87] creator_pool_on_off_control u8\r\n// [88:120] token_x_mint Pubkey ← corrected from erroneous 81\r\n// [120:152] token_y_mint Pubkey ← corrected from erroneous 113\r\n// [152:184] reserve_x Pubkey\r\n// [184:216] reserve_y Pubkey\r\nconst METEORA_DLMM_MIN_LEN = 152; // need through end of token_y_mint (120 + 32)\r\n\r\n/**\r\n * Parse a Meteora DLMM (discretized liquidity) pool account.\r\n *\r\n * Reads `token_x_mint` at byte 88 and `token_y_mint` at byte 120, matching the\r\n * on-chain `LbPair` struct layout (verified against mainnet pool\r\n * `5rCf1DM8LjKTw4YqhnoLcngyZYeNnQqztScTogYHAS6` — WSOL/USDC, Jun 2026).\r\n *\r\n * @internal\r\n */\r\nfunction parseMeteoraPool(poolAddress: PublicKey, data: Uint8Array): DexPoolInfo {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM pool data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n return {\r\n dexType: \"meteora-dlmm\",\r\n poolAddress,\r\n baseMint: new PublicKey(data.slice(88, 120)),\r\n quoteMint: new PublicKey(data.slice(120, 152)),\r\n };\r\n}\r\n\r\n/**\r\n * Compute Meteora DLMM spot price from active_id and bin_step.\r\n *\r\n * Formula: `price = (1 + bin_step/10000) ^ active_id`\r\n *\r\n * Uses binary exponentiation with 1e18 fixed-point precision, then converts to e6.\r\n * For negative active_id, computes the inverse.\r\n *\r\n * @internal\r\n */\r\nconst MAX_BIN_STEP = 10_000;\r\nconst MAX_ACTIVE_ID_ABS = 500_000;\r\n\r\nfunction computeMeteoraDlmmPriceE6(\r\n data: Uint8Array,\r\n decimalsBase: number,\r\n decimalsQuote: number,\r\n): bigint {\r\n if (data.length < METEORA_DLMM_MIN_LEN) {\r\n throw new Error(`Meteora DLMM data too short: ${data.length} < ${METEORA_DLMM_MIN_LEN}`);\r\n }\r\n assertTokenDecimals(\"Meteora DLMM\", \"base\", decimalsBase);\r\n assertTokenDecimals(\"Meteora DLMM\", \"quote\", decimalsQuote);\r\n const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // bin_step is at offset 80 (u16 LE), not 73 which is bin_step_seed ([u8;2]).\r\n // They happen to encode the same integer for most pools (explaining why the\r\n // old code produced correct prices), but reading the correct field is required\r\n // for correctness once those fields diverge.\r\n const binStep = dv.getUint16(80, true);\r\n const activeId = dv.getInt32(76, true);\r\n\r\n if (binStep === 0) return 0n;\r\n if (binStep > MAX_BIN_STEP) {\r\n throw new Error(`Meteora DLMM: binStep ${binStep} exceeds max ${MAX_BIN_STEP}`);\r\n }\r\n if (Math.abs(activeId) > MAX_ACTIVE_ID_ABS) {\r\n throw new Error(\r\n `Meteora DLMM: |activeId| ${Math.abs(activeId)} exceeds max ${MAX_ACTIVE_ID_ABS}`,\r\n );\r\n }\r\n\r\n const SCALE = 1_000_000_000_000_000_000n; // 1e18\r\n const base = SCALE + (BigInt(binStep) * SCALE) / 10_000n;\r\n\r\n const isNeg = activeId < 0;\r\n let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);\r\n\r\n let result = SCALE;\r\n let b = base;\r\n\r\n while (exp > 0n) {\r\n if (exp & 1n) {\r\n result = (result * b) / SCALE;\r\n }\r\n exp >>= 1n;\r\n if (exp > 0n) {\r\n b = (b * b) / SCALE;\r\n }\r\n }\r\n\r\n // #226: the bin formula yields the price of ONE ATOMIC base unit in ATOMIC quote\r\n // units (lamport-per-lamport), exactly like Raydium's sqrt_price. Convert to a\r\n // human/E6 price by multiplying by 10^(decimalsBase - decimalsQuote) — without this\r\n // the mark price is wrong by that factor for any pair with asymmetric decimals.\r\n // Apply the decimal scale and divide ONCE at the end (deferred truncation, like the\r\n // Raydium #210 fix) so sub-1e-6 micro-prices aren't truncated to 0n. BigInt is\r\n // arbitrary-precision, so the intermediate products cannot overflow.\r\n const diff = decimalsBase - decimalsQuote;\r\n\r\n if (isNeg) {\r\n if (result === 0n) return 0n;\r\n // price_e6 = (1e24 / result) * 10^diff [1e24 = 1e18 (inverse) * 1e6 (e6 scale)]\r\n const num = 1_000_000_000_000_000_000_000_000n; // 1e24\r\n if (diff >= 0) {\r\n return (num * 10n ** BigInt(diff)) / result;\r\n }\r\n return num / (result * 10n ** BigInt(-diff));\r\n } else {\r\n // price_e6 = (result / 1e12) * 10^diff\r\n if (diff >= 0) {\r\n return (result * 10n ** BigInt(diff)) / 1_000_000_000_000n;\r\n }\r\n return result / (1_000_000_000_000n * 10n ** BigInt(-diff));\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Read a little-endian u64 from a DataView. */\r\nfunction readU64LE(dv: DataView, offset: number): bigint {\r\n const lo = BigInt(dv.getUint32(offset, true));\r\n const hi = BigInt(dv.getUint32(offset + 4, true));\r\n return lo | (hi << 32n);\r\n}\r\n\r\n/** Read a little-endian u128 from a DataView. */\r\nfunction readU128LE(dv: DataView, offset: number): bigint {\r\n const lo = readU64LE(dv, offset);\r\n const hi = readU64LE(dv, offset + 8);\r\n return lo | (hi << 64n);\r\n}\r\n","/**\r\n * Oracle account parsing utilities.\r\n *\r\n * Chainlink transmissions-account layout, taken from the DEPLOYED wrapper\r\n * percolator-prog@19d5d932 (`read_chainlink_price_e6`, src/v16_program.rs:5636)\r\n * so that this parser and the on-chain program agree byte-for-byte:\r\n *\r\n * CHAINLINK_HEADER_SIZE = 192\r\n * offset 8: version (u8) CL_OFF_VERSION\r\n * offset 138: decimals (u8) CL_OFF_DECIMALS\r\n * offset 143: latest_round_id (u32 LE) CL_OFF_LATEST_ROUND_ID\r\n * offset 148: live_length (u32 LE) CL_OFF_LIVE_LENGTH\r\n * offset 200: transmission record CL_OFF_TRANSMISSION = 8 + 192\r\n * +0 (200): slot (u64 LE) CL_TRANS_OFF_SLOT\r\n * +8 (208): timestamp (u32 LE, Unix secs) CL_TRANS_OFF_TIMESTAMP\r\n * +16 (216): answer (i128 LE) CL_TRANS_OFF_ANSWER\r\n *\r\n * Minimum account size: 248 bytes = 8 + 192 + 48 (CHAINLINK_FEED_MIN_LEN).\r\n *\r\n * These utilities validate oracle data BEFORE parsing to prevent silent\r\n * propagation of stale or malformed Chainlink data as price.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Minimum buffer size to read Chainlink price data.\r\n * Mirrors the program's CHAINLINK_FEED_MIN_LEN = 8 + CHAINLINK_HEADER_SIZE(192) + 48.\r\n * The previous value (224) was smaller than the program's own floor, so the SDK\r\n * accepted buffers the chain rejects — and 224 cannot even hold the 16-byte\r\n * answer at offset 216.\r\n */\r\nconst CHAINLINK_MIN_SIZE = 248; // 8 + 192 + 48\r\n\r\n/** Maximum reasonable decimals for a price feed */\r\nconst MAX_DECIMALS = 18;\r\n\r\n/** Offset of decimals field in Chainlink aggregator account */\r\nconst CHAINLINK_DECIMALS_OFFSET = 138;\r\n\r\n/**\r\n * Offset of the transmission timestamp (u32 LE, Unix seconds).\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_TIMESTAMP(8).\r\n * NOTE: u32, not i64 — the program reads it with read_u32_le.\r\n */\r\nconst CHAINLINK_TIMESTAMP_OFFSET = 208;\r\n\r\n/**\r\n * Offset of the latest answer.\r\n * = CL_OFF_TRANSMISSION(200) + CL_TRANS_OFF_ANSWER(16).\r\n */\r\nconst CHAINLINK_ANSWER_OFFSET = 216;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface OraclePrice {\r\n price: bigint;\r\n decimals: number;\r\n /** Unix timestamp (seconds) of the last oracle update, if available. */\r\n updatedAt?: number;\r\n}\r\n\r\nexport interface ParseChainlinkOptions {\r\n /** Maximum allowed staleness in seconds. If the oracle update is older, an error is thrown. */\r\n maxStalenessSeconds?: number;\r\n /**\r\n * How far ahead of the local clock a publish timestamp may be before it is\r\n * treated as invalid rather than as clock skew. Defaults to 60s.\r\n * Only consulted when `maxStalenessSeconds` is set.\r\n */\r\n futureToleranceSeconds?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Browser-compatible read helpers using DataView\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8(data: Uint8Array, off: number): number {\r\n return data[off];\r\n}\r\n\r\nfunction readBigInt64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);\r\n}\r\n\r\nfunction readBigUint64LE(data: Uint8Array, off: number): bigint {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigUint64(off, true);\r\n}\r\n\r\nfunction readU32LE(data: Uint8Array, off: number): number {\r\n return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(off, true);\r\n}\r\n\r\n/**\r\n * Default tolerance for a publish timestamp that appears to be in the future.\r\n *\r\n * The program compares the feed timestamp against the on-chain clock\r\n * (`now_unix_ts`) and rejects a negative age. This runs off-chain against\r\n * `Date.now()`, which is the CLIENT's clock, so an ordinary few seconds of skew\r\n * between a user's machine and the cluster would otherwise reject a perfectly\r\n * healthy feed. Allow a small window before treating \"in the future\" as a fault.\r\n */\r\nconst DEFAULT_FUTURE_TOLERANCE_SECONDS = 60;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse price data from a Chainlink aggregator account buffer.\r\n *\r\n * Validates:\r\n * - Buffer is large enough to contain the required fields (>= 248 bytes, the\r\n * program's own CHAINLINK_FEED_MIN_LEN)\r\n * - Decimals are in a reasonable range (0-18)\r\n * - Price is positive (non-zero)\r\n *\r\n * @param data - Raw account data from Chainlink aggregator\r\n * @param options - Optional staleness check (maxStalenessSeconds)\r\n * @returns Parsed oracle price with decimals and last-update timestamp\r\n * @throws if the buffer is invalid, contains unreasonable data, or (when\r\n * maxStalenessSeconds is set) the last update is older than that bound\r\n */\r\nexport function parseChainlinkPrice(data: Uint8Array, options?: ParseChainlinkOptions): OraclePrice {\r\n if (data.length < CHAINLINK_MIN_SIZE) {\r\n throw new Error(\r\n `Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`\r\n );\r\n }\r\n\r\n const decimals = readU8(data, CHAINLINK_DECIMALS_OFFSET);\r\n if (decimals > MAX_DECIMALS) {\r\n throw new Error(\r\n `Oracle decimals out of range: ${decimals} (max ${MAX_DECIMALS})`\r\n );\r\n }\r\n\r\n // The program reads the answer as a full i128 LE (read_i128_le at\r\n // v16_program.rs:5657). Reconstruct the same i128 from its low (unsigned) and\r\n // high (signed) halves rather than reading only the low 8 bytes, which would\r\n // silently truncate a large answer into a different price than the chain sees.\r\n //\r\n // No i64 ceiling is imposed here: that would be STRICTER than the chain. The\r\n // program feeds the whole i128 to scale_decimal_to_e6 (v16_program.rs:5557),\r\n // which rejects only `mantissa <= 0`, and then bounds the SCALED result against\r\n // MAX_ORACLE_PRICE — so a large mantissa with high `decimals` is perfectly valid\r\n // on-chain. `price` is a bigint and holds the full i128 range.\r\n const answer =\r\n (readBigInt64LE(data, CHAINLINK_ANSWER_OFFSET + 8) << 64n) |\r\n readBigUint64LE(data, CHAINLINK_ANSWER_OFFSET);\r\n if (answer <= 0n) {\r\n throw new Error(\r\n `Oracle price is non-positive: ${answer}`\r\n );\r\n }\r\n const price = answer;\r\n\r\n // Transmission timestamp: u32 LE at offset 208 (see the layout note above).\r\n const updatedAt = readU32LE(data, CHAINLINK_TIMESTAMP_OFFSET);\r\n\r\n if (options?.maxStalenessSeconds !== undefined) {\r\n // Mirror the program, which rejects `publish_time <= 0` outright rather than\r\n // skipping the check: a zero timestamp means the feed has never published,\r\n // which is maximally stale, not exempt from staleness.\r\n if (updatedAt <= 0) {\r\n throw new Error(\r\n `Oracle has no valid publish timestamp (updatedAt=${updatedAt})`\r\n );\r\n }\r\n const now = Math.floor(Date.now() / 1000);\r\n const age = now - updatedAt;\r\n // The program rejects a negative age, but it measures against the on-chain\r\n // clock. We only have the local one, so a couple of seconds of ordinary skew\r\n // must not condemn a healthy feed — only an implausible jump ahead should.\r\n const futureTolerance =\r\n options.futureToleranceSeconds ?? DEFAULT_FUTURE_TOLERANCE_SECONDS;\r\n if (age < -futureTolerance) {\r\n throw new Error(\r\n `Oracle publish timestamp is ${-age}s in the future (tolerance ${futureTolerance}s) — ` +\r\n `check the feed or the local clock`\r\n );\r\n }\r\n if (age > options.maxStalenessSeconds) {\r\n throw new Error(\r\n `Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`\r\n );\r\n }\r\n }\r\n\r\n return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : undefined };\r\n}\r\n\r\n/**\r\n * Validate that a buffer looks like a valid Chainlink aggregator account.\r\n * Returns true if the buffer passes all validation checks, false otherwise.\r\n * Use this for non-throwing validation.\r\n */\r\nexport function isValidChainlinkOracle(data: Uint8Array): boolean {\r\n try {\r\n parseChainlinkPrice(data);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// Re-export constants for consumers\r\nexport { CHAINLINK_MIN_SIZE, CHAINLINK_DECIMALS_OFFSET, CHAINLINK_TIMESTAMP_OFFSET, CHAINLINK_ANSWER_OFFSET, MAX_DECIMALS };\r\n","import { Connection, PublicKey } from \"@solana/web3.js\";\r\nimport { TOKEN_PROGRAM_ID } from \"@solana/spl-token\";\r\n\r\n/**\r\n * Token2022 (Token Extensions) program ID.\r\n */\r\nexport const TOKEN_2022_PROGRAM_ID = new PublicKey(\r\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\",\r\n);\r\n\r\n/**\r\n * Detect which token program owns a given mint account.\r\n * Returns the canonical program ID — TOKEN_PROGRAM_ID or TOKEN_2022_PROGRAM_ID.\r\n *\r\n * #266: previously this returned `info.owner` verbatim, which FAILS OPEN — an\r\n * attacker-controlled account owned by an arbitrary program (or a non-mint\r\n * account) would be accepted and its owner propagated as the \"token program\",\r\n * letting a forged program be passed into a later token CPI. Now we branch on\r\n * the owner and accept ONLY the two real token programs, throwing otherwise.\r\n *\r\n * @throws if the mint account doesn't exist, or is not owned by SPL Token or\r\n * Token-2022.\r\n */\r\nexport async function detectTokenProgram(\r\n connection: Connection,\r\n mint: PublicKey,\r\n): Promise {\r\n const info = await connection.getAccountInfo(mint);\r\n if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);\r\n\r\n if (info.owner.equals(TOKEN_PROGRAM_ID)) return TOKEN_PROGRAM_ID;\r\n if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;\r\n\r\n throw new Error(\r\n `Account ${mint.toBase58()} is not a token mint: owner ${info.owner.toBase58()} ` +\r\n `is neither SPL Token (${TOKEN_PROGRAM_ID.toBase58()}) nor ` +\r\n `Token-2022 (${TOKEN_2022_PROGRAM_ID.toBase58()})`,\r\n );\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is Token2022.\r\n */\r\nexport function isToken2022(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if a given token program ID is the standard SPL Token program.\r\n */\r\nexport function isStandardToken(tokenProgramId: PublicKey): boolean {\r\n return tokenProgramId.equals(TOKEN_PROGRAM_ID);\r\n}\r\n","/**\r\n * @module stake\r\n * Percolator Insurance LP Staking program — instruction encoders, PDA derivation, and account specs.\r\n *\r\n * Program: percolator-stake (dcccrypto/percolator-stake)\r\n * Deployed devnet: GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3 (fresh v17 triple,\r\n * deployed 2026-07-17, hash-verified — see PROGRAM_IDS_V17.vault in\r\n * `src/config/program-ids.ts`)\r\n * Deployed mainnet: DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F (unverified — no confirmed\r\n * mainnet deployment of any stake/vault lineage found in the v17 planning docs as of\r\n * this writing; treat as a placeholder until DevOps confirms)\r\n *\r\n * LINEAGE (as of 2026-07-17): the devnet address GCHhcgw... was deployed FRESH from\r\n * `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`) — the ADOPTED\r\n * `percolator-stake@feat/adopt-stake-lineage-plus-n7` lineage's instruction set, matching\r\n * this module's STAKE_IX tag table and decodeStakePool below exactly (no on-chain drift).\r\n * This is a NEW address, NOT an in-place upgrade of the old `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (which ran `percolator-vault@eb3ebe8` and is now SUPERSEDED / no longer the SDK default —\r\n * do not use it for new integrations).\r\n */\r\n\r\nimport { PublicKey, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';\r\nimport { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\r\nexport { TOKEN_2022_PROGRAM_ID };\r\nimport { safeEnv } from '../config/program-ids.js';\r\nimport { concatBytes } from '../abi/encode.js';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Program ID — network-conditional (mirrors program-ids.ts pattern)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Known stake program addresses per network.\r\n *\r\n * devnet: UPDATED from the SUPERSEDED `51CeUNpbXovK2BRADPyssuf3Q1xWGabEK9pYkp5mqVhQ`\r\n * (the old `percolator-vault@eb3ebe8` deployment) to the FRESH v17 devnet triple's\r\n * stake address `GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3`, deployed 2026-07-17\r\n * from `~/v17/percolator-stake@1e08d35` (hash `0e9c2572...`), cross-verified against\r\n * `PROGRAM_IDS_V17.vault` in `src/config/program-ids.ts` (\"v17 vault — deployed\r\n * devnet 2026-07-17, hash-verified\"). This is a NEW address (not an in-place upgrade\r\n * of the old 51CeUNpb... address, which is now superseded and should not be used for\r\n * new integrations) and already runs the ADOPTED `percolator-stake` lineage this\r\n * module targets — see the module doc above.\r\n *\r\n * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists\r\n * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as\r\n * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps\r\n * confirms.\r\n *\r\n * IMPORTANT: \"unverified\" does NOT mean \"inert\". Checked against mainnet RPC on\r\n * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable\r\n * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not\r\n * silently default to mainnet: an unconfigured browser caller would have resolved to\r\n * a real, executing mainnet program rather than failing safe.\r\n */\r\nexport const STAKE_PROGRAM_IDS = {\r\n devnet: 'GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3',\r\n mainnet: 'DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F',\r\n} as const;\r\nObject.freeze(STAKE_PROGRAM_IDS);\r\n\r\n/** Allowlist of legitimate stake program addresses (devnet + mainnet). */\r\nconst KNOWN_STAKE_PROGRAM_IDS = new Set(Object.values(STAKE_PROGRAM_IDS));\r\n\r\n/**\r\n * Resolve the stake program ID for the given network.\r\n *\r\n * Priority:\r\n * 1. STAKE_PROGRAM_ID env var (explicit override — DevOps sets this for mainnet until constant is filled)\r\n * 2. Network-specific constant from STAKE_PROGRAM_IDS\r\n *\r\n * Throws a clear error on mainnet when no address is available so callers\r\n * surface the gap instead of silently hitting the devnet program.\r\n */\r\nexport function getStakeProgramId(network?: 'devnet' | 'mainnet'): PublicKey {\r\n // Only consult the env override when no explicit network arg is provided.\r\n // An explicit network argument always wins so tests and multi-network callers\r\n // are not silently redirected to a DevOps-set override address.\r\n if (!network) {\r\n const override = safeEnv('STAKE_PROGRAM_ID');\r\n if (override) {\r\n // #308: reject an unlisted override unless the operator explicitly opts in (blocks\r\n // ambient env poisoning while allowing fresh pre-deploy addresses).\r\n if (\r\n !KNOWN_STAKE_PROGRAM_IDS.has(override) &&\r\n safeEnv('PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE') !== '1'\r\n ) {\r\n throw new Error(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env var \"${override}\" is not a known stake program address. ` +\r\n `Allowed values: ${[...KNOWN_STAKE_PROGRAM_IDS].join(', ')}. ` +\r\n `Pass an explicit network argument, or set PERCOLATOR_SDK_ALLOW_PROGRAM_OVERRIDE=1 ` +\r\n `to intentionally allow an unlisted program (e.g. a fresh pre-deploy address).`,\r\n );\r\n }\r\n console.warn(\r\n `[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override}`,\r\n );\r\n return new PublicKey(override);\r\n }\r\n }\r\n\r\n const detectedNetwork =\r\n network ??\r\n (() => {\r\n const n = safeEnv('NEXT_PUBLIC_DEFAULT_NETWORK')?.toLowerCase() ??\r\n safeEnv('NETWORK')?.toLowerCase() ?? '';\r\n if (n === 'mainnet' || n === 'mainnet-beta') return 'mainnet' as const;\r\n if (n === 'devnet') return 'devnet' as const;\r\n // SECURITY: this used to return 'mainnet' whenever `window` was defined —\r\n // i.e. in every browser bundle, where process.env is empty because env vars\r\n // are not inlined into third-party SDK code. An unconfigured frontend caller\r\n // was therefore resolved to STAKE_PROGRAM_IDS.mainnet, which is a LIVE,\r\n // executable BPFLoaderUpgradeable program on mainnet (checked 2026-08-16).\r\n //\r\n // We deliberately do NOT substitute a devnet default here. Unlike\r\n // getCurrentNetwork() in program-ids.ts, which fails open to devnet because\r\n // it returns a label, this function returns a PROGRAM ADDRESS THAT RECEIVES\r\n // FUNDS. A wrong answer in either direction is a silent wrong-network bug;\r\n // defaulting to devnet would merely defer it to the day mainnet launches and\r\n // a forgotten env var silently points a mainnet UI at the devnet vault.\r\n // Refuse to guess: the network must be explicit.\r\n // The message must not assert a cause it has not established. This fires in\r\n // Node too — whenever NETWORK / NEXT_PUBLIC_DEFAULT_NETWORK is simply unset,\r\n // with process.env fully available — so claiming \"browser bundle\" would send\r\n // a server-side caller chasing the wrong thing.\r\n throw new Error(\r\n 'getStakeProgramId: cannot determine the network. Neither NETWORK nor ' +\r\n 'NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is ' +\r\n 'empty, so this is expected there; in Node it means the variable is unset). ' +\r\n \"Pass an explicit network argument — getStakeProgramId('devnet') or \" +\r\n \"getStakeProgramId('mainnet') — or set STAKE_PROGRAM_ID to override the \" +\r\n 'address directly. Refusing to guess: this resolves a fund-custody program ' +\r\n 'address, and callers that derive PDAs from it (deriveStakePool, ' +\r\n 'deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses ' +\r\n 'for the wrong network.',\r\n );\r\n })();\r\n\r\n const id = STAKE_PROGRAM_IDS[detectedNetwork];\r\n if (!id) {\r\n throw new Error(\r\n `Stake program not deployed on ${detectedNetwork}. ` +\r\n `Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`,\r\n );\r\n }\r\n return new PublicKey(id);\r\n}\r\n\r\n/**\r\n * Default export — resolves for the current runtime network.\r\n * Use getStakeProgramId() with an explicit network argument where possible.\r\n *\r\n * @deprecated Direct use of STAKE_PROGRAM_ID is being phased out in favour of\r\n * getStakeProgramId() so mainnet callers get a clear error rather than silently\r\n * resolving to the devnet address.\r\n */\r\nexport const STAKE_PROGRAM_ID = new PublicKey(STAKE_PROGRAM_IDS.devnet);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Tags — ADOPTED percolator-stake lineage\r\n// (feat/adopt-stake-lineage-plus-n7, HEAD 9ec1c3a, src/instruction.rs)\r\n//\r\n// BREAKING vs the OLD, now-SUPERSEDED percolator-vault@eb3ebe8 program (formerly\r\n// deployed at 51CeUNpb...): tags 5-9 are completely repurposed (were admin\r\n// CPI proxies / TransferAdmin, now two-step admin rotation + #242 cooldown\r\n// timelock), tag 15 moves from BindInsuranceAuthority to AdminSetTrancheConfig,\r\n// BindInsuranceAuthority moves to 19, tags 16/18 go live (were unhandled), and\r\n// tags 20-23 are new. See ~/v17/RESEARCH-issue6-lineage.md §1.1 for the full\r\n// side-by-side tag-delta table this was verified against. The comparison is now\r\n// purely historical: the fresh devnet deployment (GCHhcgw..., 2026-07-17) is a\r\n// NEW address that already runs the ADOPTED lineage below — there is no more\r\n// live percolator-vault@eb3ebe8 program for these tags to collide with on devnet.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport const STAKE_IX = {\r\n InitPool: 0,\r\n Deposit: 1,\r\n Withdraw: 2,\r\n FlushToInsurance: 3,\r\n UpdateConfig: 4,\r\n /**\r\n * ProposeAdmin (tag 5) — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes a new admin (written to `pool.pending_admin`); the\r\n * proposed admin gains no authority until AcceptAdmin (tag 6). Proposing the\r\n * zero pubkey CANCELS an outstanding proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 5 there is the\r\n * removed `TransferAdmin` (one-step, rejects on-chain). Do NOT confuse with\r\n * wrapper marketauth rotation (a completely different key, done via the\r\n * wrapper's own UpdateAuthority tag 32, CPI'd from stake InitPool).\r\n *\r\n * Wire: tag(1) + new_admin(32) = 33 bytes.\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\n ProposeAdmin: 5,\r\n /**\r\n * AcceptAdmin (tag 6) — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to take ownership; requires an outstanding proposal\r\n * and the signer to equal `pool.pending_admin`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 6 there is the\r\n * removed `AdminSetOracleAuthority` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\n AcceptAdmin: 6,\r\n /**\r\n * ProposeCooldownIncrease (tag 7) — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldown_slots`; takes effect only\r\n * after CommitCooldownIncrease is called >= TIMELOCK_SLOTS later, guaranteeing\r\n * LP holders an exit window. A decrease/unchanged value is rejected here\r\n * (use UpdateConfig, which applies decreases immediately).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 7 there is the\r\n * removed `AdminSetRiskThreshold` (rejects on-chain).\r\n *\r\n * Wire: tag(1) + new_cooldown_slots(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n ProposeCooldownIncrease: 7,\r\n /**\r\n * CommitCooldownIncrease (tag 8) — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if TIMELOCK_SLOTS has not elapsed.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 8 there is the\r\n * removed `AdminSetMaintenanceFee` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\n CommitCooldownIncrease: 8,\r\n /**\r\n * CancelCooldownIncrease (tag 9) — withdraws an outstanding #242 cooldown\r\n * proposal.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 9 there is the\r\n * removed `AdminResolveMarket` (rejects on-chain).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n CancelCooldownIncrease: 9,\r\n /** @deprecated Alias for ProposeAdmin — the OLD percolator-vault semantics\r\n * (one-step TransferAdmin) no longer apply; tag 5 is now ProposeAdmin. */\r\n TransferAdmin: 5,\r\n /** @deprecated Alias for AcceptAdmin — the OLD percolator-vault semantics\r\n * (AdminSetOracleAuthority) no longer apply; tag 6 is now AcceptAdmin. */\r\n AdminSetOracleAuthority: 6,\r\n /** @deprecated Alias for ProposeCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetRiskThreshold) no longer apply; tag 7 is now\r\n * ProposeCooldownIncrease with a DIFFERENT wire format (u64, not removed-stub). */\r\n AdminSetRiskThreshold: 7,\r\n /** @deprecated Alias for CommitCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminSetMaintenanceFee) no longer apply; tag 8 is now\r\n * CommitCooldownIncrease. */\r\n AdminSetMaintenanceFee: 8,\r\n /** @deprecated Alias for CancelCooldownIncrease — the OLD percolator-vault\r\n * semantics (AdminResolveMarket) no longer apply; tag 9 is now\r\n * CancelCooldownIncrease. */\r\n AdminResolveMarket: 9,\r\n /**\r\n * ReturnInsurance (tag 10) — unchanged wire/semantics vs the deployed\r\n * percolator-vault program: transfer withdrawn insurance back into the pool\r\n * vault (admin calls wrapper WithdrawInsurance directly first, then this\r\n * books admin-ATA -> pool-vault).\r\n */\r\n ReturnInsurance: 10,\r\n /** @deprecated Legacy alias for ReturnInsurance. */\r\n AdminWithdrawInsurance: 10,\r\n /** @deprecated Tombstoned in BOTH lineages (was an admin CPI proxy —\r\n * SetInsurancePolicy). This tag rejects on-chain in the adopted lineage too. */\r\n AdminSetInsurancePolicy: 11,\r\n /** PERC-272: Accrue trading fees to LP vault. Unchanged vs deployed vault. */\r\n AccrueFees: 12,\r\n /** PERC-272: Init pool in trading LP mode. Unchanged vs deployed vault. */\r\n InitTradingPool: 13,\r\n /** PERC-313: Set HWM config (enable + floor bps). Unchanged vs deployed vault. */\r\n AdminSetHwmConfig: 14,\r\n /**\r\n * AdminSetTrancheConfig (tag 15) — enable/configure senior-junior LP\r\n * tranches. Sets `junior_fee_mult_bps`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * below). Sending this payload against the DEPLOYED vault program would\r\n * execute BindInsuranceAuthority instead; only send it against the\r\n * ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n AdminSetTrancheConfig: 15,\r\n /**\r\n * DepositJunior (tag 16) — deposit into the junior (first-loss) tranche.\r\n * Same account shape as Deposit (tag 1).\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\n DepositJunior: 16,\r\n /**\r\n * BindInsuranceAuthority (tag 19 / 0x13) — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator via two CPIs to UpdateAssetAuthority (tag 65,\r\n * kind=1 INSURANCE then kind=2 INSURANCE_OPERATOR) — the adopted lineage\r\n * binds both in one call, unlike the deployed vault program which only\r\n * bound insurance_authority. The human admin signs the outer tx as the\r\n * current authority/operator; vault_auth signs via invoke_signed.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n BindInsuranceAuthority: 19,\r\n /**\r\n * RotateInsuranceAuthority (tag 20) — admin-gated migration/incident\r\n * escape that moves the market's `insurance_authority` OFF our vault_auth\r\n * PDA to an admin-specified `newTarget`. The PDA signs as the CURRENT\r\n * authority (invoke_signed); newTarget co-signs the outer tx as the NEW\r\n * authority. NEW in the adopted lineage — no equivalent in the deployed\r\n * percolator-vault program (which has no un-bind escape at all).\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceAuthority: 20,\r\n /**\r\n * BurnAssetAdmin (tag 21) — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after BindInsuranceAuthority\r\n * has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer, writable), poolPda(writable), vaultAuth(placeholder), slab(writable), percolatorProgram]\r\n */\r\n BurnAssetAdmin: 21,\r\n /**\r\n * RotateInsuranceOperator (tag 22) — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, newTarget(signer), slab(writable), percolatorProgram]\r\n */\r\n RotateInsuranceOperator: 22,\r\n /**\r\n * RecoverFlushedInsurance (tag 23) — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA). Survives BurnAssetAdmin because tag 57 gates on\r\n * insurance_operator, not asset_admin. `amount` capped to\r\n * `total_flushed - total_returned`; funds can only land in `pool.vault`.\r\n * NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n * Accounts: [caller(no signer check), poolPda(writable), poolVault(writable),\r\n * vaultAuth, wrapperMarket(writable), wrapperVault(writable), wrapperVaultAuth,\r\n * tokenProgram, percolatorProgram]\r\n */\r\n RecoverFlushedInsurance: 23,\r\n /**\r\n * AdminResolveMarketCpi (tag 24) — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). InitPool rotates `cfg.marketauth` to this pool's PDA, so\r\n * only a CPI signed by that PDA can ever call the wrapper's ResolveMarket;\r\n * without this proxy every stake-initialized market would be permanently\r\n * stuck in Live mode. The pool PDA signs the wrapper CPI via\r\n * `invoke_signed`; no local stake-side state is mutated (SetMarketResolved,\r\n * tag 18, remains the separate, explicit local bookkeeping step). NEW in\r\n * percolator-stake (see src/instruction.rs / src/processor.rs\r\n * `process_admin_resolve_market`, tag 24).\r\n *\r\n * NOTE on the name: the on-chain enum variant is literally\r\n * `AdminResolveMarket` (matching the DEPRECATED tag-9 name from the OLD\r\n * percolator-vault lineage, see `AdminResolveMarket: 9` above / its throwing\r\n * `encodeStakeAdminResolveMarket()` alias). This key is suffixed `Cpi` to\r\n * avoid re-using that already-claimed object key/export name — the tag-9\r\n * alias and this tag-24 instruction are unrelated aside from sharing an\r\n * on-chain name across two different lineages.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n */\r\n AdminResolveMarketCpi: 24,\r\n /**\r\n * SetMarketResolved (tag 18) — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\n SetMarketResolved: 18,\r\n /**\r\n * AdminUpdateFeeSplit (tag 25) — CPI proxy for the wrapper's UpdateFeeSplit\r\n * (wrapper tag 86). GROUP A: the wrapper gate is `cfg.marketauth`, which\r\n * `StakeInitPool` irreversibly rotates to the pool PDA, so the pool PDA\r\n * signs the CPI via invoke_signed.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16) + lp_share_bps(u16) +\r\n * insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * Share validation is the WRAPPER's (`policy_v16::validate_fee_split`) and is\r\n * deliberately not duplicated stake-side — a bad split surfaces as wrapper\r\n * Custom(52)/Custom(51) through the CPI.\r\n */\r\n AdminUpdateFeeSplit: 25,\r\n /**\r\n * AdminUpdateMaintenanceFeePerSlot (tag 26) — CPI proxy for the wrapper's\r\n * UpdateMaintenanceFeePerSlot (wrapper tag 88). GROUP A, same accounts and\r\n * signer model as tag 25.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128) = 17 bytes.\r\n * Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64 — the stake program itself rejects a\r\n * payload whose `rest.len() != 16`, and the wrapper decodes tag 88 with\r\n * `read_u128`.\r\n */\r\n AdminUpdateMaintenanceFeePerSlot: 26,\r\n /**\r\n * AdminUpdateBackingFeePolicy (tag 27) — CPI proxy for the wrapper's\r\n * UpdateBackingFeePolicy (wrapper tag 51). GROUP B: the wrapper gate is\r\n * ASSET 0's `insurance_authority`, which `BindInsuranceAuthority` moves to\r\n * the `vault_auth` PDA, so `vault_auth` (not the pool PDA) signs the CPI.\r\n *\r\n * THE FEE-SPLIT UNBLOCKER: wrapper tag 51 is the setter for\r\n * `backing_trade_fee_bps`. Once bound, this CPI is the only way to reach it.\r\n *\r\n * Wire: tag(1) + domain(u16) + fee_bps(u16) + insurance_share_bps(u16) = 7 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n */\r\n AdminUpdateBackingFeePolicy: 27,\r\n /**\r\n * AdminUpdateTradeFeePolicy (tag 28) — CPI proxy for the wrapper's\r\n * UpdateTradeFeePolicy (wrapper tag 55). GROUP B, same accounts and signer\r\n * model as tag 27.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64) = 9 bytes.\r\n * Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n *\r\n * ⚠ Note the type asymmetry with tag 26: wrapper tag 55 decodes with\r\n * `read_u64`, wrapper tag 88 with `read_u128`.\r\n */\r\n AdminUpdateTradeFeePolicy: 28,\r\n} as const;\r\nObject.freeze(STAKE_IX);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Error hint table — StakeError (src/error.rs, ADOPTED percolator-stake lineage)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * User-facing hint text for `StakeError` custom program error codes\r\n * (`ProgramError::Custom(code)`, `percolator-stake/src/error.rs`).\r\n *\r\n * Codes 0-24 mirror `error.rs`'s on-chain `error_hint()` fallback text.\r\n * Codes 25-27 (#242 cooldown-increase timelock) and 28\r\n * (`DepositBelowMinimumLiquidity`, N7 anti-inflation hardening) are new in\r\n * the ADOPTED lineage — 28 is the entry this table exists to add. NOTE:\r\n * the on-chain `error_hint()` itself has a gap (falls through to \"Unknown\r\n * error\" for 25-27 despite them being named enum variants); the hints below\r\n * for 25-27 are derived from `error.rs`'s doc comments, not copied from a\r\n * (missing) on-chain string.\r\n */\r\nexport const STAKE_ERRORS: Record = {\r\n 0: \"Pool already initialized — use a different slab address or check if InitPool was already called\",\r\n 1: \"Pool not initialized — call InitPool first to create the stake pool\",\r\n 2: \"Unauthorized — you must be the pool admin to perform this action\",\r\n 3: \"Cooldown not elapsed — wait for the cooldown period before withdrawing again\",\r\n 4: \"Insufficient LP tokens — you don't have enough LP tokens to burn\",\r\n 5: \"Zero amount — deposit and withdrawal amounts must be greater than zero\",\r\n 6: \"Arithmetic overflow — pool values exceeded u64 bounds, operation blocked\",\r\n 7: \"Invalid mint — LP mint doesn't match the pool's LP mint\",\r\n 8: \"Market is resolved — no new deposits allowed after resolution\",\r\n 9: \"Deposit cap exceeded — pool has reached its maximum deposit limit\",\r\n 10: \"Invalid PDA — account is not a valid PDA for the expected seed\",\r\n 11: \"Deprecated (was AdminAlreadyTransferred) — code kept for stable numbering; should not occur\",\r\n 12: \"Deprecated (was AdminNotTransferred) — code kept for stable numbering; should not occur\",\r\n 13: \"Insufficient vault balance — vault doesn't have enough collateral for this withdrawal\",\r\n 14: \"Invalid percolator program — percolator program ID doesn't match\",\r\n 15: \"CPI to percolator failed — the cross-program invoke to percolator failed\",\r\n 16: \"Invalid account — account is not owned by the expected program or is not writable\",\r\n 17: \"Pool mode mismatch — operation not valid for this pool's mode (e.g., AccrueFees on insurance pool)\",\r\n 18: \"Withdrawal blocked — would breach high-water mark floor protection\",\r\n 19: \"Tranches not enabled — senior/junior tranches are not enabled on this pool\",\r\n 20: \"Junior balance insufficient — junior tranche doesn't have enough balance for this operation\",\r\n 21: \"Wrong tranche — deposit already belongs to a different tranche\",\r\n 22: \"Zero shares minted — deposit amount too small to mint any LP at the current share price; increase the amount\",\r\n 23: \"No pending admin — there is no admin transfer to accept (propose one first, or it was cancelled)\",\r\n 24: \"Insurance loss outstanding — junior tranche deposits are paused until the flushed insurance is returned (total_flushed > total_returned)\",\r\n 25: \"Cooldown increase requires timelock — a cooldown_slots INCREASE must go through ProposeCooldownIncrease -> wait -> CommitCooldownIncrease, not UpdateConfig (decreases are still immediate via UpdateConfig)\",\r\n 26: \"Timelock not elapsed — CommitCooldownIncrease was called before the required timelock window had passed since ProposeCooldownIncrease; LP holders are still inside their exit window\",\r\n 27: \"No pending cooldown proposal — CommitCooldownIncrease / CancelCooldownIncrease called with no active ProposeCooldownIncrease proposal outstanding\",\r\n 28: \"Deposit below minimum liquidity — the pool's first-ever deposit must exceed MINIMUM_LIQUIDITY so a permanent dead-share floor can be locked (N7 anti-inflation hardening); deposit a larger amount\",\r\n};\r\nObject.freeze(STAKE_ERRORS);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PDA Derivation\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nconst TEXT = new TextEncoder();\r\n\r\n/** Derive the stake pool PDA for a given slab (market). */\r\nexport function deriveStakePool(slab: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_pool'), slab.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the vault authority PDA (signs CPI, owns LP mint + vault). */\r\nexport function deriveStakeVaultAuth(pool: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('vault_auth'), pool.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n/** Derive the per-user deposit PDA (tracks cooldown, deposit time). */\r\nexport function deriveDepositPda(pool: PublicKey, user: PublicKey, programId?: PublicKey) {\r\n return PublicKey.findProgramAddressSync(\r\n [TEXT.encode('stake_deposit'), pool.toBytes(), user.toBytes()], programId ?? getStakeProgramId(), );\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Browser-safe binary helpers (DataView, no Node.js Buffer dependency)// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Read a u64 little-endian from a Uint8Array at the given offset. */\r\nfunction readU64LE(data: Uint8Array, off: number): bigint {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getBigUint64(off, /* littleEndian= */ true);\r\n}\r\n\r\n/** Read a u16 little-endian from a Uint8Array at the given offset. */\r\nfunction readU16LE(data: Uint8Array, off: number): number {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n return view.getUint16(off, /* littleEndian= */ true);\r\n}\r\n\r\nfunction requireDiscriminator(\r\n accountName: string,\r\n data: Uint8Array,\r\n offset: number,\r\n expected: Uint8Array,\r\n): void {\r\n for (let i = 0; i < expected.length; i += 1) {\r\n if (data[offset + i] !== expected[i]) {\r\n throw new Error(`${accountName} invalid discriminator`);\r\n }\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Instruction Encoders\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction u64Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);\r\n if (big > 0xFFFF_FFFF_FFFF_FFFFn) throw new Error(`u64Le: value exceeds u64 max`);\r\n const arr = new Uint8Array(8);\r\n new DataView(arr.buffer).setBigUint64(0, big, true); return arr;\r\n}\r\n\r\nfunction u128Le(v: bigint | number): Uint8Array {\r\n if (typeof v === \"number\" && !Number.isSafeInteger(v)) {\r\n throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER — use BigInt`);\r\n }\r\n\r\n const big = BigInt(v);\r\n if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);\r\n if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);\r\n const arr = new Uint8Array(16);\r\n const view = new DataView(arr.buffer); view.setBigUint64(0, big & 0xFFFFFFFFFFFFFFFFn, true);\r\n view.setBigUint64(8, big >> 64n, true);\r\n return arr;\r\n}\r\n\r\nfunction u16Le(v: number): Uint8Array {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new Error(`u16Le: value out of u16 range (0..65535), got ${v}`); const arr = new Uint8Array(2); new DataView(arr.buffer).setUint16(0, v, true);\r\n return arr;\r\n}\r\n\r\n/** Tag 0: InitPool — create stake pool for a slab. */\r\nexport function encodeStakeInitPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 1: Deposit — deposit collateral, receive LP tokens. */\r\nexport function encodeStakeDeposit(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Deposit]), u64Le(amount));\r\n}\r\n\r\n/** Tag 2: Withdraw — burn LP tokens, receive collateral (subject to cooldown). */\r\nexport function encodeStakeWithdraw(lpAmount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.Withdraw]), u64Le(lpAmount));\r\n}\r\n\r\n/** Tag 3: FlushToInsurance — move collateral from stake vault to wrapper insurance. */\r\nexport function encodeStakeFlushToInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.FlushToInsurance]), u64Le(amount));\r\n}\r\n\r\n/** Tag 4: UpdateConfig — update cooldown and/or deposit cap. */\r\nexport function encodeStakeUpdateConfig(\r\n newCooldownSlots?: bigint | number,\r\n newDepositCap?: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.UpdateConfig]),\r\n new Uint8Array([newCooldownSlots != null ? 1 : 0]),\r\n u64Le(newCooldownSlots ?? 0n),\r\n new Uint8Array([newDepositCap != null ? 1 : 0]),\r\n u64Le(newDepositCap ?? 0n),\r\n );\r\n}\r\n\r\nfunction removedStakeInstruction(name: string, tag: number): never {\r\n throw new Error(\r\n `${name} (stake tag ${tag}) was removed on-chain in percolator-stake v3 and must not be sent.`,\r\n );\r\n}\r\n\r\n/**\r\n * Tag 5: ProposeAdmin — step 1 of two-step `pool.admin` rotation. The\r\n * CURRENT admin proposes `newAdmin` (written to `pool.pending_admin`); it\r\n * does not gain any authority until AcceptAdmin (tag 6) is called by that\r\n * key. Pass `PublicKey.default` (zero pubkey) to CANCEL an outstanding\r\n * proposal.\r\n *\r\n * Accounts: [currentAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeProposeAdmin(newAdmin: PublicKey): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeAdmin]),\r\n newAdmin.toBytes(),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 6: AcceptAdmin — step 2 of two-step `pool.admin` rotation. The\r\n * PENDING admin signs to become admin. Requires an outstanding proposal.\r\n *\r\n * Accounts: [pendingAdmin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAcceptAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AcceptAdmin]);\r\n}\r\n\r\n/**\r\n * Tag 7: ProposeCooldownIncrease — step 1 of the #242 cooldown-increase\r\n * timelock. Proposes a NEW (larger) `cooldownSlots`; does not take effect\r\n * until CommitCooldownIncrease is called after the on-chain timelock has\r\n * elapsed. A decrease/unchanged value is rejected (use UpdateConfig instead).\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeProposeCooldownIncrease(newCooldownSlots: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ProposeCooldownIncrease]),\r\n u64Le(newCooldownSlots),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 8: CommitCooldownIncrease — step 2 of the #242 timelock. Applies the\r\n * pending cooldown increase; rejects if the timelock has not yet elapsed.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable), clockSysvar]\r\n */\r\nexport function encodeStakeCommitCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CommitCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * Tag 9: CancelCooldownIncrease — withdraws an outstanding #242 cooldown\r\n * increase proposal.\r\n *\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeCancelCooldownIncrease(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.CancelCooldownIncrease]);\r\n}\r\n\r\n/**\r\n * @deprecated The deployed percolator-vault program's one-step TransferAdmin\r\n * (tag 5) was removed on-chain there too (rejects). On the ADOPTED\r\n * percolator-stake lineage this module targets, tag 5 is the two-step\r\n * ProposeAdmin — use `encodeStakeProposeAdmin(newAdmin)` followed by the\r\n * proposed admin calling `encodeStakeAcceptAdmin()`. Throws.\r\n */\r\nexport function encodeStakeTransferAdmin(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeTransferAdmin: tag 5 is ProposeAdmin (two-step rotation) in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeAdmin(newAdmin) + encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 6 is AcceptAdmin in the adopted percolator-stake lineage\r\n * (this instruction, AdminSetOracleAuthority, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetOracleAuthority(newAuthority: PublicKey): Uint8Array {\r\n void newAuthority;\r\n throw new Error(\r\n 'encodeStakeAdminSetOracleAuthority: tag 6 is AcceptAdmin in the adopted percolator-stake ' +\r\n 'lineage — use encodeStakeAcceptAdmin() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 7 is ProposeCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetRiskThreshold, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetRiskThreshold(newThreshold: bigint | number): Uint8Array {\r\n void newThreshold;\r\n throw new Error(\r\n 'encodeStakeAdminSetRiskThreshold: tag 7 is ProposeCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeProposeCooldownIncrease(newCooldownSlots) instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 8 is CommitCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminSetMaintenanceFee, was removed on-chain in\r\n * both lineages). Throws.\r\n */\r\nexport function encodeStakeAdminSetMaintenanceFee(newFee: bigint | number): Uint8Array {\r\n void newFee;\r\n throw new Error(\r\n 'encodeStakeAdminSetMaintenanceFee: tag 8 is CommitCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCommitCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/**\r\n * @deprecated Tag 9 is CancelCooldownIncrease in the adopted percolator-stake\r\n * lineage (this instruction, AdminResolveMarket, was removed on-chain in both\r\n * lineages). Throws.\r\n */\r\nexport function encodeStakeAdminResolveMarket(): Uint8Array {\r\n throw new Error(\r\n 'encodeStakeAdminResolveMarket: tag 9 is CancelCooldownIncrease in the adopted ' +\r\n 'percolator-stake lineage — use encodeStakeCancelCooldownIncrease() instead.',\r\n );\r\n}\r\n\r\n/** Tag 10: ReturnInsurance — transfer withdrawn insurance back into the stake pool vault. */\r\nexport function encodeStakeReturnInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.ReturnInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/** @deprecated Legacy alias for tag 10. Current on-chain semantics are ReturnInsurance. */\r\nexport function encodeStakeAdminWithdrawInsurance(amount: bigint | number): Uint8Array {\r\n return encodeStakeReturnInsurance(amount);\r\n}\r\n\r\n/** Tag 12: AccrueFees — permissionless: accrue trading fees to LP vault. */\r\nexport function encodeStakeAccrueFees(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AccrueFees]);\r\n}\r\n\r\n/** Tag 13: InitTradingPool — create pool in trading LP mode (pool_mode = 1). */\r\nexport function encodeStakeInitTradingPool(cooldownSlots: bigint | number, depositCap: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.InitTradingPool]),\r\n u64Le(cooldownSlots),\r\n u64Le(depositCap),\r\n );\r\n}\r\n\r\n/** Tag 14 (PERC-313): AdminSetHwmConfig — enable HWM protection and set floor BPS. */\r\nexport function encodeStakeAdminSetHwmConfig(\r\n enabled: boolean,\r\n hwmFloorBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetHwmConfig]),\r\n new Uint8Array([enabled ? 1 : 0]),\r\n u16Le(hwmFloorBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 15: AdminSetTrancheConfig — enable/configure senior-junior LP tranches.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 15 there is\r\n * BindInsuranceAuthority (moved to tag 19 in the adopted lineage — see\r\n * `encodeStakeBindInsuranceAuthority()`). Only send this against the ADOPTED\r\n * percolator-stake lineage; sending it against the currently-deployed vault\r\n * program would silently execute BindInsuranceAuthority instead.\r\n *\r\n * Wire: tag(1) + junior_fee_mult_bps(u16) = 3 bytes.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeAdminSetTrancheConfig(juniorFeeMultBps: number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminSetTrancheConfig]),\r\n u16Le(juniorFeeMultBps),\r\n );\r\n}\r\n\r\n/**\r\n * Tag 16: DepositJunior — deposit into the junior (first-loss) tranche. Same\r\n * account shape as Deposit (tag 1) — see `StakeAccounts['deposit']`.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 16 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n */\r\nexport function encodeStakeDepositJunior(amount: bigint | number): Uint8Array {\r\n return concatBytes(new Uint8Array([STAKE_IX.DepositJunior]), u64Le(amount));\r\n}\r\n\r\n/**\r\n * Tag 18: SetMarketResolved — admin marks the pool as market-resolved\r\n * (blocks new deposits). Call after resolving the market on the wrapper\r\n * directly.\r\n *\r\n * BREAKING vs the deployed percolator-vault program: tag 18 is UNHANDLED\r\n * there (rejects). Live only on the ADOPTED percolator-stake lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n * Accounts: [admin(signer), poolPda(writable)]\r\n */\r\nexport function encodeStakeSetMarketResolved(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.SetMarketResolved]);\r\n}\r\n\r\n/**\r\n * Tag 19 (0x13): BindInsuranceAuthority — FIND-4 fix, MOVED from tag 15\r\n * (0x0F) in the deployed percolator-vault program.\r\n *\r\n * Binds the vault_auth PDA as BOTH the wrapper's asset-0 insurance_authority\r\n * AND insurance_operator (two CPIs to UpdateAssetAuthority, tag 65, kind=1\r\n * then kind=2) — a broader bind than the deployed vault program's\r\n * single-CPI version (insurance_authority only). Must be called once after\r\n * InitPool, before FlushToInsurance will work.\r\n *\r\n * Wire: tag(1) = 0x13 — no payload beyond the tag byte (1 byte total).\r\n *\r\n * @returns 1-byte Uint8Array `[0x13]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBindInsuranceAuthority();\r\n * // accounts: bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBindInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BindInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Account inputs for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * @param admin Current insurance_authority/insurance_operator (human admin wallet; outer tx signer).\r\n * @param poolPda Stake pool PDA (derived via deriveStakePool()).\r\n * @param vaultAuth Vault authority PDA (derived via deriveStakeVaultAuth()).\r\n * @param slab Wrapper market-group slab (writable — needed for UpdateAssetAuthority CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BindInsuranceAuthorityAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BindInsuranceAuthority (tag 19 / 0x13).\r\n *\r\n * Account order matches src/processor.rs process_bind_insurance_authority\r\n * (adopted lineage — same account shape as the deployed vault program's tag\r\n * 15, only the tag byte moved):\r\n * [0] admin signer, read-only (current insurance_authority/insurance_operator)\r\n * [1] pool_pda writable (stake pool PDA)\r\n * [2] vault_auth read-only (new authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n *\r\n * @example\r\n * ```ts\r\n * const [poolPda] = deriveStakePool(slab, stakeProgramId);\r\n * const [vaultAuth] = deriveStakeVaultAuth(poolPda, stakeProgramId);\r\n * const keys = bindInsuranceAuthorityAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function bindInsuranceAuthorityAccounts(\r\n a: BindInsuranceAuthorityAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 20: RotateInsuranceAuthority — admin-gated migration/incident escape\r\n * that moves the market's `insurance_authority` OFF our vault_auth PDA to an\r\n * admin-specified `newTarget`. NEW in the adopted lineage — no equivalent in\r\n * the deployed percolator-vault program (which has no un-bind escape).\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceAuthority();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceAuthority(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceAuthority]);\r\n}\r\n\r\n/**\r\n * Tag 22: RotateInsuranceOperator — analogous to RotateInsuranceAuthority\r\n * (tag 20) but for `insurance_operator` (kind=2). Part of the no-lockout\r\n * migration sequence before a final BurnAssetAdmin. NEW in the adopted\r\n * lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRotateInsuranceOperator();\r\n * // accounts: rotateInsuranceAccounts({ admin, poolPda, vaultAuth, newTarget, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRotateInsuranceOperator(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.RotateInsuranceOperator]);\r\n}\r\n\r\n/**\r\n * Account inputs shared by RotateInsuranceAuthority (tag 20) and\r\n * RotateInsuranceOperator (tag 22) — identical 6-account shape.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA.\r\n * @param vaultAuth Vault authority PDA — the CURRENT authority/operator, signs via invoke_signed.\r\n * @param newTarget The successor authority/operator — co-signs the outer tx.\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RotateInsuranceAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n newTarget: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RotateInsuranceAuthority (tag 20) / RotateInsuranceOperator\r\n * (tag 22) — identical account order in both (src/processor.rs\r\n * process_rotate_insurance_authority / process_rotate_insurance_operator):\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only\r\n * [2] vault_auth read-only (current authority/operator; signs via invoke_signed)\r\n * [3] new_target signer, read-only (successor; co-signs the outer tx)\r\n * [4] slab writable (wrapper market; needed for CPI)\r\n * [5] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function rotateInsuranceAccounts(\r\n a: RotateInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.newTarget, isSigner: true, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 21: BurnAssetAdmin — IRREVERSIBLE removal of the admin's rotate-back\r\n * capability. CPIs UpdateAssetAuthority(kind=0 ASSET_ADMIN, new_pubkey=[0;32]).\r\n * After this, no key can rotate ANY per-asset authority back to an\r\n * admin-controlled key. Call ONCE per market, only after\r\n * BindInsuranceAuthority has completed. NEW in the adopted lineage.\r\n *\r\n * Wire: tag(1) — no payload.\r\n *\r\n * @returns 1-byte Uint8Array.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeBurnAssetAdmin();\r\n * // accounts: burnAssetAdminAccounts({ admin, poolPda, vaultAuth, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeBurnAssetAdmin(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.BurnAssetAdmin]);\r\n}\r\n\r\n/**\r\n * Account inputs for BurnAssetAdmin (tag 21).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin; current asset_admin).\r\n * @param poolPda Stake pool PDA (writable — records the burn).\r\n * @param vaultAuth Vault authority PDA (placeholder new_authority slot — not checked for the burn CPI).\r\n * @param slab Wrapper market-group slab (writable — needed for the CPI).\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface BurnAssetAdminAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for BurnAssetAdmin (tag 21) — src/processor.rs\r\n * process_burn_asset_admin:\r\n * [0] admin signer, writable (current asset_admin == pool.admin)\r\n * [1] pool_pda writable (records asset_admin_burned)\r\n * [2] vault_auth read-only (placeholder new_authority slot)\r\n * [3] slab writable (wrapper market; needed for CPI)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function burnAssetAdminAccounts(\r\n a: BurnAssetAdminAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 23: RecoverFlushedInsurance — PERMISSIONLESS recovery of tokens from\r\n * the wrapper's insurance fund back into the stake pool vault, via a CPI to\r\n * wrapper tag 57 `WithdrawInsuranceAsset` (gated on insurance_operator ==\r\n * vault_auth PDA — set by BindInsuranceAuthority tag 19). Survives\r\n * BurnAssetAdmin because tag 57 gates on insurance_operator, not asset_admin.\r\n * `amount` is capped on-chain to `total_flushed - total_returned`; funds can\r\n * only land in `pool.vault` (drain check on the CPI destination). NEW in the\r\n * adopted lineage.\r\n *\r\n * Wire: tag(1) + amount(u64) = 9 bytes.\r\n *\r\n * @param amount Atoms to recover (u64, non-zero, <= outstanding).\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeRecoverFlushedInsurance(1_000_000n);\r\n * // accounts: recoverFlushedInsuranceAccounts({ caller, poolPda, poolVault, vaultAuth,\r\n * // wrapperMarket, wrapperVault, wrapperVaultAuth, tokenProgram, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeRecoverFlushedInsurance(amount: bigint | number): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.RecoverFlushedInsurance]),\r\n u64Le(amount),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for RecoverFlushedInsurance (tag 23).\r\n *\r\n * @param caller Permissionless caller — no signer check required.\r\n * @param poolPda Stake pool PDA (writable).\r\n * @param poolVault Pool vault token account — destination (writable, must equal pool.vault).\r\n * @param vaultAuth Vault authority PDA — the insurance_operator; signs the CPI via invoke_signed.\r\n * @param wrapperMarket Wrapper market/slab account (writable).\r\n * @param wrapperVault Wrapper insurance vault token account — source (writable).\r\n * @param wrapperVaultAuth Wrapper vault authority PDA.\r\n * @param tokenProgram Token program.\r\n * @param percolatorProgram Wrapper program ID.\r\n */\r\nexport interface RecoverFlushedInsuranceAccounts {\r\n caller: PublicKey;\r\n poolPda: PublicKey;\r\n poolVault: PublicKey;\r\n vaultAuth: PublicKey;\r\n wrapperMarket: PublicKey;\r\n wrapperVault: PublicKey;\r\n wrapperVaultAuth: PublicKey;\r\n tokenProgram: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for RecoverFlushedInsurance (tag 23) — src/processor.rs\r\n * process_recover_flushed_insurance:\r\n * [0] caller (no signer check — permissionless)\r\n * [1] pool_pda writable\r\n * [2] vault (pool vault) writable (destination; must equal pool.vault)\r\n * [3] vault_auth read-only (signs the wrapper CPI via invoke_signed)\r\n * [4] market (wrapper) writable\r\n * [5] wrapper_vault writable (source — wrapper insurance vault)\r\n * [6] wrapper_vault_auth read-only\r\n * [7] token_program read-only\r\n * [8] percolator_program read-only\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function recoverFlushedInsuranceAccounts(\r\n a: RecoverFlushedInsuranceAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.caller, isSigner: false, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: true },\r\n { pubkey: a.poolVault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.wrapperMarket, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.tokenProgram, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Tag 24: AdminResolveMarketCpi — CPI proxy for the wrapper's ResolveMarket\r\n * (wrapper tag 19). Only the pool PDA (bound as `cfg.marketauth` by InitPool)\r\n * can call the wrapper's ResolveMarket directly; this instruction has the\r\n * stake program sign that CPI via `invoke_signed` with the pool PDA seeds so\r\n * the (human) admin can trigger resolution. Does not mutate any local\r\n * stake-side state — call `encodeStakeSetMarketResolved()` (tag 18)\r\n * separately afterward for local bookkeeping.\r\n *\r\n * Wire: tag(1) = 24 — no payload beyond the tag byte.\r\n *\r\n * @returns 1-byte Uint8Array `[24]`.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminResolveMarketCpi();\r\n * // accounts: adminResolveMarketCpiAccounts({ admin, poolPda, slab, percolatorProgram })\r\n * ```\r\n */\r\nexport function encodeStakeAdminResolveMarketCpi(): Uint8Array {\r\n return new Uint8Array([STAKE_IX.AdminResolveMarketCpi]);\r\n}\r\n\r\n/**\r\n * Account inputs for AdminResolveMarketCpi (tag 24).\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — signs the wrapper CPI via invoke_signed (marketauth).\r\n * @param slab Wrapper market-group slab (writable — target of the ResolveMarket CPI).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface AdminResolveMarketCpiAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for AdminResolveMarketCpi (tag 24) — src/processor.rs\r\n * process_admin_resolve_market:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs the CPI via invoke_signed)\r\n * [2] slab writable (wrapper market; ResolveMarket CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function adminResolveMarketCpiAccounts(\r\n a: AdminResolveMarketCpiAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CPI proxies for wrapper setters stranded by staking (tags 25-28)\r\n// percolator-stake feat/adopt-stake-lineage-plus-n7@474079f\r\n//\r\n// WHY THESE EXIST. `StakeInitPool` irreversibly rotates `cfg.marketauth` to\r\n// the stake-pool PDA, and `BindInsuranceAuthority` hands asset 0's\r\n// `insurance_authority` to `vault_auth`. A PDA cannot sign a top-level\r\n// transaction, so the affected wrapper setters become reachable ONLY through a\r\n// stake-program CPI proxy. Before these four, exactly one proxy existed\r\n// (AdminResolveMarket -> wrapper tag 19), leaving 1 of 16 marketauth-gated\r\n// wrapper handlers reachable — which is the mechanical reason the fee split\r\n// was unachievable on a staked market.\r\n//\r\n// GROUP A (tags 25, 26): wrapper gate is `cfg.marketauth`; the POOL PDA signs.\r\n// Accounts: [admin(signer), poolPda, slab(writable), percolatorProgram]\r\n// GROUP B (tags 27, 28): wrapper gate is asset 0's `insurance_authority`; the\r\n// VAULT_AUTH PDA signs.\r\n// Accounts: [admin(signer), poolPda, vaultAuth, slab(writable), percolatorProgram]\r\n//\r\n// All four are gated stake-side on `pool.admin`, matching AdminResolveMarket.\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Encode AdminUpdateFeeSplit (stake tag 25) — CPI proxy for wrapper tag 86.\r\n *\r\n * Wire: tag(1) + creator_share_bps(u16 LE) + lp_share_bps(u16 LE) +\r\n * insurance_share_bps(u16 LE) = 7 bytes. The stake program rejects any payload\r\n * whose length is not exactly 6 bytes after the tag.\r\n *\r\n * Use this instead of `encodeUpdateFeeSplit` once `StakeInitPool` has rotated\r\n * `cfg.marketauth` to the pool PDA. Before that, call the wrapper directly.\r\n *\r\n * Share validation happens in the WRAPPER, not here: a split that does not sum\r\n * to 8000 surfaces as wrapper Custom(52) FeeSplitSumInvalid through the CPI,\r\n * and a floor breach as Custom(51) FeeSplitFloorViolation.\r\n *\r\n * @param creatorShareBps Creator's share of T in bps (<= 3600).\r\n * @param lpShareBps LP vault's share of T in bps (>= 3200).\r\n * @param insuranceShareBps Insurance/staker share of T in bps (>= 1200).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateFeeSplit(1600, 4800, 1600);\r\n * const keys = adminUpdateFeeSplitAccounts({ admin, poolPda, slab, percolatorProgram });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateFeeSplit(\r\n creatorShareBps: number,\r\n lpShareBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateFeeSplit]),\r\n u16Le(creatorShareBps),\r\n u16Le(lpShareBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateMaintenanceFeePerSlot (stake tag 26) — CPI proxy for\r\n * wrapper tag 88.\r\n *\r\n * Wire: tag(1) + maintenance_fee_per_slot(u128 LE) = 17 bytes.\r\n *\r\n * ⚠ THE PAYLOAD IS u128, NOT u64. The stake program checks `rest.len() == 16`\r\n * and rejects otherwise; the wrapper then decodes with `read_u128`. Passing a\r\n * u64 fails at the stake program before the CPI is even attempted.\r\n *\r\n * @param maintenanceFeePerSlot Fee charged per slot, u128. Default on-chain is\r\n * 0 (maintenance fee disabled). The wrapper\r\n * range-checks against MAX_PROTOCOL_FEE_ABS.\r\n * @returns 17-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateMaintenanceFeePerSlot(0n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateMaintenanceFeePerSlot(\r\n maintenanceFeePerSlot: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateMaintenanceFeePerSlot]),\r\n u128Le(maintenanceFeePerSlot),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateBackingFeePolicy (stake tag 27) — CPI proxy for wrapper\r\n * tag 51, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + domain(u16 LE) + fee_bps(u16 LE) + insurance_share_bps(u16 LE)\r\n * = 7 bytes.\r\n *\r\n * @param domain Backing domain index (u16). `asset_index = domain / 2`.\r\n * @param feeBps Backing fee in bps (u16).\r\n * @param insuranceShareBps Insurance share of the backing fee in bps (u16).\r\n * @returns 7-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateBackingFeePolicy(0, 30, 5000);\r\n * const keys = adminUpdateBackingFeePolicyAccounts({\r\n * admin, poolPda, vaultAuth, slab, percolatorProgram,\r\n * });\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateBackingFeePolicy(\r\n domain: number,\r\n feeBps: number,\r\n insuranceShareBps: number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateBackingFeePolicy]),\r\n u16Le(domain),\r\n u16Le(feeBps),\r\n u16Le(insuranceShareBps),\r\n );\r\n}\r\n\r\n/**\r\n * Encode AdminUpdateTradeFeePolicy (stake tag 28) — CPI proxy for wrapper tag\r\n * 55, signed by the `vault_auth` PDA.\r\n *\r\n * Wire: tag(1) + trade_fee_base_bps(u64 LE) = 9 bytes. The stake program\r\n * checks `rest.len() == 8`.\r\n *\r\n * Sets `T`, the base trade fee that the four-way split divides.\r\n *\r\n * @param tradeFeeBaseBps Base trade fee in bps (u64). The wrapper rejects\r\n * values above the market's `max_trading_fee_bps` or\r\n * above MAX_DYNAMIC_TRADE_FEE_BPS.\r\n * @returns 9-byte instruction data buffer.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = encodeStakeAdminUpdateTradeFeePolicy(30n);\r\n * ```\r\n */\r\nexport function encodeStakeAdminUpdateTradeFeePolicy(\r\n tradeFeeBaseBps: bigint | number,\r\n): Uint8Array {\r\n return concatBytes(\r\n new Uint8Array([STAKE_IX.AdminUpdateTradeFeePolicy]),\r\n u64Le(tradeFeeBaseBps),\r\n );\r\n}\r\n\r\n/**\r\n * Account inputs for the GROUP A proxies (stake tags 25 and 26), where the\r\n * wrapper gate is `cfg.marketauth` and the pool PDA signs the CPI.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — the marketauth; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupAProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP A proxies — src/processor.rs\r\n * `process_admin_update_fee_split` (tag 25) and\r\n * `process_admin_update_maintenance_fee_per_slot` (tag 26), which share an\r\n * identical layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (marketauth; signs via invoke_signed)\r\n * [2] slab writable (wrapper market; CPI target)\r\n * [3] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Identical to `adminResolveMarketCpiAccounts` (tag 24).\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupAProxyAccounts(\r\n a: StakeGroupAProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateFeeSplit (stake tag 25). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateFeeSplitAccounts = stakeGroupAProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateMaintenanceFeePerSlot (stake tag 26). Alias of {@link stakeGroupAProxyAccounts}. */\r\nexport const adminUpdateMaintenanceFeePerSlotAccounts = stakeGroupAProxyAccounts;\r\n\r\n/**\r\n * Account inputs for the GROUP B proxies (stake tags 27 and 28), where the\r\n * wrapper gate is asset 0's `insurance_authority` and `vault_auth` signs.\r\n *\r\n * @param admin Pool admin (outer tx signer; == pool.admin).\r\n * @param poolPda Stake pool PDA — used to DERIVE and verify vaultAuth; NOT a signer.\r\n * @param vaultAuth Vault authority PDA ['vault_auth', poolPda] — the\r\n * insurance_authority; signs via invoke_signed.\r\n * @param slab Wrapper market-group slab (writable — CPI target).\r\n * @param percolatorProgram Wrapper program ID (CPI target).\r\n */\r\nexport interface StakeGroupBProxyAccounts {\r\n admin: PublicKey;\r\n poolPda: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n percolatorProgram: PublicKey;\r\n}\r\n\r\n/**\r\n * Build account keys for the GROUP B proxies — src/processor.rs\r\n * `process_admin_update_backing_fee_policy` (tag 27) and\r\n * `process_admin_update_trade_fee_policy` (tag 28), which share an identical\r\n * layout:\r\n * [0] admin signer, read-only (== pool.admin)\r\n * [1] pool_pda read-only (derives/verifies vault_auth; NOT a signer)\r\n * [2] vault_auth read-only (insurance_authority; signs via invoke_signed)\r\n * [3] slab writable (wrapper market; CPI target)\r\n * [4] percolator_program read-only (wrapper program for CPI dispatch)\r\n *\r\n * Note the pool PDA sits at index 1 and does NOT sign here — that is the\r\n * difference from GROUP A, and getting it wrong makes the CPI fail its\r\n * authority check rather than fail loudly at the account level.\r\n *\r\n * @param a Named accounts.\r\n * @returns Array of `{pubkey, isSigner, isWritable}` in program-expected order.\r\n */\r\nexport function stakeGroupBProxyAccounts(\r\n a: StakeGroupBProxyAccounts,\r\n): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: false },\r\n { pubkey: a.poolPda, isSigner: false, isWritable: false },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/** Account keys for AdminUpdateBackingFeePolicy (stake tag 27). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateBackingFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** Account keys for AdminUpdateTradeFeePolicy (stake tag 28). Alias of {@link stakeGroupBProxyAccounts}. */\r\nexport const adminUpdateTradeFeePolicyAccounts = stakeGroupBProxyAccounts;\r\n\r\n/** @deprecated Removed on-chain in stake v3. Throws instead of emitting a dead instruction. */\r\nexport function encodeStakeAdminSetInsurancePolicy(\r\n authority: PublicKey,\r\n minWithdrawBase: bigint | number,\r\n maxWithdrawBps: number,\r\n cooldownSlots: bigint | number,\r\n): Uint8Array {\r\n void authority;\r\n void minWithdrawBase;\r\n void maxWithdrawBps;\r\n void cooldownSlots;\r\n return removedStakeInstruction('encodeStakeAdminSetInsurancePolicy', STAKE_IX.AdminSetInsurancePolicy);\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// On-Chain State Layout — StakePool decoded fields\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Decoded StakePool state (392 bytes on-chain — stake v3, current).\r\n * v2 adds `pending_admin` ([u8;32]) at offset 288 for the two-step admin-rotation\r\n * primitive (ProposeAdmin tag 5 / AcceptAdmin tag 6). Struct grew 352 → 384.\r\n * v3 (H-1 re-review fix, `percolator-stake@c5a901f`) appends\r\n * `total_recovered_from_wrapper` (u64) at the struct TAIL, offset 384..392 —\r\n * outside `_reserved`, which stays fixed at [320..384]. Struct grew 384 → 392;\r\n * no prior field offset shifts. Includes PERC-272 (fee yield), PERC-313 (HWM),\r\n * and PERC-303 (tranches).\r\n *\r\n * ⚠️ KNOWN BYTE-ALIASING BUG in the ADOPTED percolator-stake lineage's\r\n * `_reserved` layout (verified against `state.rs` on\r\n * feat/adopt-stake-lineage-plus-n7@9ec1c3a — this is a real on-chain bug, not\r\n * an SDK bug; flagged upstream, not fixed here since this module only decodes\r\n * whatever bytes the program actually writes):\r\n *\r\n * - PERC-313 HWM fields (`hwm_enabled` @[10], `hwm_floor_bps` @[11..13],\r\n * `epoch_high_water_tvl` @[16..24], `hwm_last_epoch` @[24..32]) and the\r\n * #242 cooldown-increase timelock fields (`pending_cooldown_slots`\r\n * @[10..18], `cooldown_proposed_at_slot` @[18..26]) OVERLAP the SAME\r\n * `_reserved` bytes [10..26]. `state.rs`'s own doc comment for the HWM\r\n * block claims bytes [10..32] are HWM-only, but the timelock accessors\r\n * (added later, #242) write into [10..18]/[18..26] regardless.\r\n * - Practical effect: enabling HWM (`AdminSetHwmConfig`, tag 14) and using\r\n * the cooldown-increase timelock (tags 7/8/9) on the SAME pool will\r\n * corrupt each other's state — e.g. `hwm_floor_bps` (bytes [11..13]) sits\r\n * inside `pending_cooldown_slots`'s u64 (bytes [10..18]), so committing a\r\n * cooldown increase can silently rewrite the HWM floor, and vice versa.\r\n * - This decoder reads both field sets as the raw bytes currently define\r\n * them (matching on-chain reality); it does NOT attempt to reconcile or\r\n * invalidate one set when the other is in use. Callers combining HWM and\r\n * the cooldown timelock on one pool should treat both `hwm*` and\r\n * `pendingCooldownSlots`/`cooldownProposedAtSlot` as UNRELIABLE and verify\r\n * against a direct on-chain read before trusting either.\r\n */\r\nexport interface StakePoolState {\r\n isInitialized: boolean;\r\n bump: number;\r\n vaultAuthorityBump: number;\r\n adminTransferred: boolean;\r\n marketResolved: boolean;\r\n\r\n slab: PublicKey;\r\n admin: PublicKey;\r\n collateralMint: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n\r\n totalDeposited: bigint;\r\n totalLpSupply: bigint;\r\n cooldownSlots: bigint;\r\n depositCap: bigint;\r\n totalFlushed: bigint;\r\n totalReturned: bigint;\r\n totalWithdrawn: bigint;\r\n\r\n percolatorProgram: PublicKey;\r\n\r\n /**\r\n * Pending admin for the two-step rotation (stake v2, offset 288).\r\n * `null` when no proposal is outstanding (all-zero bytes on-chain).\r\n * Set by ProposeAdmin (tag 5); consumed by AcceptAdmin (tag 6).\r\n */\r\n pendingAdmin: PublicKey | null;\r\n\r\n // PERC-272: Fee yield fields\r\n totalFeesEarned: bigint;\r\n lastFeeAccrualSlot: bigint;\r\n lastVaultSnapshot: bigint;\r\n poolMode: number;\r\n\r\n // _reserved layout (64 bytes) — ADOPTED lineage (state.rs@9ec1c3a):\r\n // [0..8] discriminator\r\n // [8] version\r\n // [9] market_resolved\r\n // [10..18] #242 pending_cooldown_slots (u64) ⚠️ ALIASES hwm_enabled/hwm_floor_bps, see interface doc\r\n // [18..26] #242 cooldown_proposed_at_slot (u64) ⚠️ ALIASES epoch_high_water_tvl, see interface doc\r\n // [10] PERC-313 hwm_enabled ⚠️ ALIASES pending_cooldown_slots's first byte\r\n // [11..13] PERC-313 hwm_floor_bps (u16) ⚠️ ALIASES pending_cooldown_slots\r\n // [16..24] PERC-313 epoch_high_water_tvl (u64) ⚠️ ALIASES cooldown_proposed_at_slot (partial)\r\n // [24..32] PERC-313 hwm_last_epoch (u64)\r\n // [32] PERC-303 tranche_enabled\r\n // [33..41] PERC-303 junior_balance (u64)\r\n // [41..49] PERC-303 junior_total_lp (u64)\r\n // [49..51] PERC-303 junior_fee_mult_bps (u16)\r\n // [51..59] N-realized_junior_loss (u64) — issue #161\r\n // [59] asset_admin_burned (BurnAssetAdmin tag 21 completion flag)\r\n // [60..64] free\r\n // [64..72] v3 ONLY, OUTSIDE _reserved (absolute offset 384..392):\r\n // total_recovered_from_wrapper (u64) — H-1 re-review fix, state.rs@c5a901f\r\n\r\n // PERC-313: HWM fields (from _reserved[10..32] — see aliasing warning above)\r\n hwmEnabled: boolean;\r\n epochHighWaterTvl: bigint;\r\n hwmFloorBps: number;\r\n hwmLastEpoch: bigint;\r\n\r\n // PERC-303: Tranche fields (from _reserved[32..51])\r\n trancheEnabled: boolean;\r\n juniorBalance: bigint;\r\n juniorTotalLp: bigint;\r\n juniorFeeMultBps: number;\r\n\r\n /**\r\n * #242 timelock: the `cooldown_slots` INCREASE awaiting commit (from\r\n * _reserved[10..18]). Meaningful only while `cooldownProposedAtSlot !== 0n`.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n pendingCooldownSlots: bigint;\r\n /**\r\n * #242 timelock: the slot at which the pending cooldown increase was\r\n * proposed (from _reserved[18..26]). `0n` = no active proposal.\r\n * ⚠️ Aliases HWM bytes — see interface doc.\r\n */\r\n cooldownProposedAtSlot: bigint;\r\n /**\r\n * Cumulative insurance loss a fully-exited junior tranche permanently\r\n * REALIZED (issue #161), from _reserved[51..59]. Subtracted from\r\n * total_pool_value() so recovered tokens don't windfall senior.\r\n */\r\n realizedJuniorLoss: bigint;\r\n /**\r\n * Whether BurnAssetAdmin (tag 21) has completed for this pool's market\r\n * (from _reserved[59]). Once true, stake-side rotate escapes (tags 20/22)\r\n * stay disabled — the wrapper roles cannot be moved back to an\r\n * admin-controlled key.\r\n */\r\n assetAdminBurned: boolean;\r\n /**\r\n * H-1 re-review fix (stake v3 only, `null` on v1/v2 pools): cumulative\r\n * collateral actually recovered from the WRAPPER via the tag-23\r\n * `RecoverFlushedInsurance` CPI (which itself CPIs the wrapper's tag-57\r\n * `WithdrawInsuranceAsset`) — the ONLY mechanism that pulls flushed\r\n * insurance back out of the wrapper. Real struct field at offset 384..392\r\n * (the tail, AFTER `_reserved`), NOT carved from `_reserved`.\r\n *\r\n * Deliberately separate from `totalReturned`, which is also bumped by two\r\n * mechanisms that do NOT recover funds from the wrapper (`ReturnInsurance`\r\n * tag 10 — the admin's own wallet tokens — and the #161 last-junior-exit\r\n * phantom write-off). `AdminResolveMarketCpi`/`SetMarketResolved` gate\r\n * market-resolution on `totalFlushed <= totalRecoveredFromWrapper`, not\r\n * `totalReturned` — see `state.rs@c5a901f` lines 133-159.\r\n */\r\n totalRecoveredFromWrapper: bigint | null;\r\n}\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v1 layout.\r\n * v1: 352 bytes = 288 bytes of fields + 64 bytes _reserved (no pending_admin field).\r\n * The _reserved block in v1 starts at offset 288; version byte = 1.\r\n *\r\n * LINEAGE NOTE: the ADOPTED percolator-stake lineage this module targets has\r\n * `CURRENT_VERSION = 3` unconditionally and is a \"fresh-start cutover\" (no\r\n * migration path — `state.rs@9ec1c3a` comment: \"no v1 pools exist, so no\r\n * migration is needed\"). v1/352-byte pools can only ever be observed as\r\n * LEGACY accounts from BEFORE the coordinated protocol-fee + stake-lineage\r\n * redeploy (which abandons every existing market/pool wholesale — VERSION\r\n * bump 16->17 on the wrapper fails closed on old accounts). This dual-length\r\n * detection exists purely to decode those pre-redeploy artifacts if you ever\r\n * need to; the ADOPTED program itself never creates a v1 pool.\r\n */\r\nexport const STAKE_POOL_SIZE_V1 = 352;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v2 layout.\r\n * v2: 384 (stake v1 was 352; `pending_admin: [u8;32]` added at offset 288).\r\n * The _reserved block in v2 starts at offset 320; version byte = 2.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@9ec1c3a` — 384 bytes exactly, no compiler\r\n * padding (every u64 field lands on an 8-aligned cumulative offset).\r\n *\r\n * SUPERSEDED by v3 (`STAKE_POOL_SIZE_V3`, 392 bytes) as of the H-1 re-review\r\n * fix (`percolator-stake@c5a901f`) — kept here only to decode pools created\r\n * between the v1->v2 and v2->v3 cutovers, and for any test/tooling code that\r\n * still needs to construct a v2-shaped buffer explicitly.\r\n */\r\nexport const STAKE_POOL_SIZE_V2 = 384;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — v3 layout (current, and the ONLY\r\n * layout the ADOPTED percolator-stake lineage creates as of `c5a901f`).\r\n * v3: 392 (stake v2 was 384; `total_recovered_from_wrapper: u64` appended at\r\n * the STRUCT TAIL, offset 384..392 — NOT inside `_reserved`, which stays a\r\n * fixed 64 bytes at [320..384] in both v2 and v3; every prior field offset is\r\n * therefore unchanged from v2). Added for the H-1 re-review fix: gates\r\n * `AdminResolveMarket`/`SetMarketResolved` on cumulative collateral actually\r\n * recovered from the wrapper via the tag-23 `RecoverFlushedInsurance` CPI,\r\n * instead of the broader (and gameable) `total_returned` counter — see\r\n * `state.rs@c5a901f` lines 133-159 for the full rationale.\r\n * Verified via `core::mem::size_of::()` field-by-field against\r\n * `percolator-stake/src/state.rs@c5a901f` — 392 bytes exactly, no compiler\r\n * padding (the appended u64 lands on the already-8-aligned offset 384).\r\n */\r\nexport const STAKE_POOL_SIZE_V3 = 392;\r\n\r\n/**\r\n * Size of StakePool on-chain (bytes) — alias for the CURRENT layout the\r\n * ADOPTED percolator-stake lineage creates. Currently equal to\r\n * `STAKE_POOL_SIZE_V3` (392). Prefer the explicit `STAKE_POOL_SIZE_V{1,2,3}`\r\n * constants in new code so a future version bump doesn't silently change the\r\n * meaning of call sites that hard-coded `STAKE_POOL_SIZE`.\r\n */\r\nexport const STAKE_POOL_SIZE = STAKE_POOL_SIZE_V3;\r\nexport const STAKE_POOL_DISCRIMINATOR = new Uint8Array([0x53, 0x50, 0x4f, 0x4f, 0x4c, 0x5f, 0x56, 0x31]);\r\nexport const STAKE_POOL_CURRENT_VERSION = 3;\r\n\r\n/**\r\n * Decode a StakePool account from raw data buffer.\r\n *\r\n * Supports v1 (352 bytes, no pending_admin, _reserved starts at 288), v2 (384\r\n * bytes, pending_admin at 288..320, _reserved starts at 320), and v3 (392\r\n * bytes, adds `total_recovered_from_wrapper: u64` at the struct tail,\r\n * offset 384..392 — outside `_reserved`, which stays at [320..384] in both\r\n * v2 and v3). The layout version is detected from the data length before\r\n * reading the discriminator.\r\n *\r\n * v1/v2 support exists only to decode legacy pools created before the\r\n * coordinated protocol-fee + stake-lineage redeploy (v1) or before the H-1\r\n * re-review fix (v2) — see the `STAKE_POOL_SIZE_V1`/`STAKE_POOL_SIZE_V2` docs\r\n * for why the ADOPTED program never creates new v1/v2 pools going forward.\r\n * See the `StakePoolState` interface doc for a known HWM / cooldown-timelock\r\n * byte-aliasing bug this decoder faithfully surfaces (not an SDK bug — a real\r\n * on-chain `_reserved` layout collision).\r\n *\r\n * Uses DataView for all u64/u16 reads — browser-safe.\r\n */\r\nexport function decodeStakePool(data: Uint8Array): StakePoolState {\r\n const isV3 = data.length >= STAKE_POOL_SIZE_V3;\r\n const isV2 = !isV3 && data.length >= STAKE_POOL_SIZE_V2;\r\n const isV1 = !isV3 && !isV2 && data.length >= STAKE_POOL_SIZE_V1;\r\n if (!isV3 && !isV2 && !isV1) {\r\n throw new Error(`StakePool data too short: ${data.length} < ${STAKE_POOL_SIZE_V1}`);\r\n }\r\n\r\n // _reserved block starts at 288 for v1, 320 for v2/v3 (v3's new field sits\r\n // AFTER _reserved, not inside it, so the block start doesn't move again).\r\n const reservedOffset = isV1 ? 288 : 320;\r\n requireDiscriminator(\"StakePool\", data, reservedOffset, STAKE_POOL_DISCRIMINATOR);\r\n const version = data[reservedOffset + 8];\r\n const expectedVersion = isV3 ? 3 : isV2 ? 2 : 1;\r\n if (version !== expectedVersion) {\r\n throw new Error(`StakePool unsupported version: ${version} !== ${expectedVersion}`);\r\n }\r\n\r\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\r\n let off = 0;\r\n const isInitialized = bytes[off] === 1; off += 1;\r\n const bump = bytes[off]; off += 1;\r\n const vaultAuthorityBump = bytes[off]; off += 1;\r\n const adminTransferred = bytes[off] === 1; off += 1;\r\n off += 4; // _padding\r\n\r\n const slab = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const admin = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const collateralMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const lpMint = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n const vault = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n const totalDeposited = readU64LE(bytes, off); off += 8;\r\n const totalLpSupply = readU64LE(bytes, off); off += 8;\r\n const cooldownSlots = readU64LE(bytes, off); off += 8;\r\n const depositCap = readU64LE(bytes, off); off += 8;\r\n const totalFlushed = readU64LE(bytes, off); off += 8;\r\n const totalReturned = readU64LE(bytes, off); off += 8;\r\n const totalWithdrawn = readU64LE(bytes, off); off += 8;\r\n\r\n const percolatorProgram = new PublicKey(bytes.subarray(off, off + 32)); off += 32;\r\n\r\n // PERC-272 fields (offset 256..288 in both v1 and v2)\r\n const totalFeesEarned = readU64LE(bytes, off); off += 8;\r\n const lastFeeAccrualSlot = readU64LE(bytes, off); off += 8;\r\n const lastVaultSnapshot = readU64LE(bytes, off); off += 8;\r\n const poolMode = bytes[off]; off += 1;\r\n off += 7; // _mode_padding (off is now 288)\r\n\r\n // stake v2/v3 only: pending_admin [u8;32] at offset 288 (ProposeAdmin/AcceptAdmin two-step rotation).\r\n // v1 has no pending_admin — the _reserved block begins immediately at offset 288.\r\n let pendingAdmin: PublicKey | null = null;\r\n if (isV2 || isV3) {\r\n const pendingAdminBytes = bytes.subarray(off, off + 32); off += 32;\r\n pendingAdmin = pendingAdminBytes.every(b => b === 0)\r\n ? null\r\n : new PublicKey(pendingAdminBytes);\r\n }\r\n\r\n // _reserved (64 bytes): starts at 288 (v1) or 320 (v2/v3)\r\n const reservedStart = off;\r\n // _reserved[8] = version (skipped)\r\n // _reserved[9] = market_resolved\r\n // PERC-313: _reserved[10] = hwm_enabled, [11..13] = hwm_floor_bps (u16),\r\n // [16..24] = epoch_high_water_tvl (u64), [24..32] = hwm_last_epoch (u64)\r\n const marketResolved = bytes[reservedStart + 9] === 1;\r\n const hwmEnabled = bytes[reservedStart + 10] === 1;\r\n const hwmFloorBps = readU16LE(bytes, reservedStart + 11);\r\n const epochHighWaterTvl = readU64LE(bytes, reservedStart + 16);\r\n const hwmLastEpoch = readU64LE(bytes, reservedStart + 24);\r\n\r\n // PERC-303: _reserved[32] = tranche_enabled, [33..41] = junior_balance, [41..49] = junior_total_lp, [49..51] = junior_fee_mult_bps\r\n const trancheEnabled = bytes[reservedStart + 32] === 1;\r\n const juniorBalance = readU64LE(bytes, reservedStart + 33);\r\n const juniorTotalLp = readU64LE(bytes, reservedStart + 41);\r\n const juniorFeeMultBps = readU16LE(bytes, reservedStart + 49);\r\n\r\n // #242 timelock: _reserved[10..18] = pending_cooldown_slots, [18..26] = cooldown_proposed_at_slot.\r\n // ⚠️ ALIASES the HWM fields above — see StakePoolState's doc comment.\r\n const pendingCooldownSlots = readU64LE(bytes, reservedStart + 10);\r\n const cooldownProposedAtSlot = readU64LE(bytes, reservedStart + 18);\r\n\r\n // N-realized_junior_loss (issue #161) at _reserved[51..59]; asset_admin_burned flag at [59].\r\n const realizedJuniorLoss = readU64LE(bytes, reservedStart + 51);\r\n const assetAdminBurned = bytes[reservedStart + 59] === 1;\r\n\r\n // H-1 re-review fix, stake v3 only: total_recovered_from_wrapper (u64) is a\r\n // REAL struct field appended at the tail, offset reservedStart + 64 (== 384\r\n // absolute) — i.e. immediately AFTER the 64-byte _reserved block, not\r\n // carved out of it. `null` on v1/v2 pools, which don't have this field at all.\r\n const totalRecoveredFromWrapper = isV3\r\n ? readU64LE(bytes, reservedStart + 64)\r\n : null;\r\n\r\n return {\r\n isInitialized,\r\n bump,\r\n vaultAuthorityBump,\r\n adminTransferred,\r\n marketResolved,\r\n slab,\r\n admin,\r\n collateralMint,\r\n lpMint,\r\n vault,\r\n totalDeposited,\r\n totalLpSupply,\r\n cooldownSlots,\r\n depositCap,\r\n totalFlushed,\r\n totalReturned,\r\n totalWithdrawn,\r\n percolatorProgram,\r\n pendingAdmin,\r\n totalFeesEarned,\r\n lastFeeAccrualSlot,\r\n lastVaultSnapshot,\r\n poolMode,\r\n hwmEnabled,\r\n epochHighWaterTvl,\r\n hwmFloorBps,\r\n hwmLastEpoch,\r\n trancheEnabled,\r\n juniorBalance,\r\n juniorTotalLp,\r\n juniorFeeMultBps,\r\n pendingCooldownSlots,\r\n cooldownProposedAtSlot,\r\n realizedJuniorLoss,\r\n assetAdminBurned,\r\n totalRecoveredFromWrapper,\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// StakeDeposit PDA decoder\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/** Size of StakeDeposit on-chain (bytes). */\r\nexport const STAKE_DEPOSIT_SIZE = 152;\r\nexport const STAKE_DEPOSIT_DISCRIMINATOR = new Uint8Array([0x53, 0x44, 0x45, 0x50, 0x5f, 0x56, 0x31, 0x00]);\r\nconst STAKE_DEPOSIT_RESERVED_OFFSET = 88;\r\n\r\n/** Decoded StakeDeposit PDA state. */\r\nexport interface StakeDepositState {\r\n isInitialized: boolean;\r\n bump: number;\r\n pool: PublicKey;\r\n user: PublicKey;\r\n lastDepositSlot: bigint;\r\n lpAmount: bigint;\r\n}\r\n\r\n/**\r\n * Decode a StakeDeposit PDA account from raw data.\r\n *\r\n * On-chain layout (152 bytes, percolator-stake/src/state.rs):\r\n * [0] is_initialized u8\r\n * [1] bump u8\r\n * [2..8] _padding\r\n * [8..40] pool [u8; 32]\r\n * [40..72] user [u8; 32]\r\n * [72..80] last_deposit_slot u64\r\n * [80..88] lp_amount u64\r\n * [88..152] _reserved\r\n */\r\nexport function decodeDepositPda(data: Uint8Array): StakeDepositState {\r\n if (data.length < STAKE_DEPOSIT_SIZE) {\r\n throw new Error(`StakeDeposit data too short: ${data.length} < ${STAKE_DEPOSIT_SIZE}`);\r\n }\r\n requireDiscriminator(\"StakeDeposit\", data, STAKE_DEPOSIT_RESERVED_OFFSET, STAKE_DEPOSIT_DISCRIMINATOR);\r\n return {\r\n isInitialized: data[0] === 1,\r\n bump: data[1],\r\n pool: new PublicKey(data.subarray(8, 40)),\r\n user: new PublicKey(data.subarray(40, 72)),\r\n lastDepositSlot: readU64LE(data, 72),\r\n lpAmount: readU64LE(data, 80),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// Account Specs (for building TransactionInstructions)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface StakeAccounts {\r\n /** InitPool accounts */\r\n initPool: {\r\n admin: PublicKey;\r\n slab: PublicKey;\r\n pool: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n collateralMint: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n /** Deposit accounts */\r\n deposit: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vault: PublicKey;\r\n lpMint: PublicKey;\r\n userLpAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** Withdraw accounts */\r\n withdraw: {\r\n user: PublicKey;\r\n pool: PublicKey;\r\n userLpAta: PublicKey;\r\n lpMint: PublicKey;\r\n vault: PublicKey;\r\n userCollateralAta: PublicKey;\r\n vaultAuth: PublicKey;\r\n depositPda: PublicKey;\r\n };\r\n /** FlushToInsurance accounts (CPI from stake → percolator) */\r\n flushToInsurance: {\r\n caller: PublicKey;\r\n pool: PublicKey;\r\n vault: PublicKey;\r\n vaultAuth: PublicKey;\r\n slab: PublicKey;\r\n wrapperVault: PublicKey;\r\n percolatorProgram: PublicKey;\r\n };\r\n}\r\n\r\n/**\r\n * Build account keys for InitPool instruction.\r\n * Returns array of {pubkey, isSigner, isWritable} in the order the program expects.\r\n *\r\n * @param a - Named accounts for the InitPool instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function initPoolAccounts(\r\n a: StakeAccounts['initPool'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.admin, isSigner: true, isWritable: true },\r\n { pubkey: a.slab, isSigner: false, isWritable: true }, // writable: InitPool CPIs UpdateAuthority which writes the slab\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.collateralMint, isSigner: false, isWritable: false },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Deposit instruction.\r\n *\r\n * @param a - Named accounts for the Deposit instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function depositAccounts(\r\n a: StakeAccounts['deposit'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for Withdraw instruction.\r\n *\r\n * @param a - Named accounts for the Withdraw instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function withdrawAccounts(\r\n a: StakeAccounts['withdraw'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.user, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.userLpAta, isSigner: false, isWritable: true },\r\n { pubkey: a.lpMint, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.userCollateralAta, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.depositPda, isSigner: false, isWritable: true },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n\r\n/**\r\n * Build account keys for FlushToInsurance instruction.\r\n *\r\n * @param a - Named accounts for the FlushToInsurance instruction.\r\n * @param tokenProgramId - Token program to use. Defaults to SPL Token. Pass\r\n * `TOKEN_2022_PROGRAM_ID` for Token-2022 collateral mints.\r\n */\r\nexport function flushToInsuranceAccounts(\r\n a: StakeAccounts['flushToInsurance'],\r\n tokenProgramId: PublicKey = TOKEN_PROGRAM_ID,\r\n) {\r\n return [\r\n { pubkey: a.caller, isSigner: true, isWritable: false },\r\n { pubkey: a.pool, isSigner: false, isWritable: true },\r\n { pubkey: a.vault, isSigner: false, isWritable: true },\r\n { pubkey: a.vaultAuth, isSigner: false, isWritable: false },\r\n { pubkey: a.slab, isSigner: false, isWritable: true },\r\n { pubkey: a.wrapperVault, isSigner: false, isWritable: true },\r\n { pubkey: a.percolatorProgram, isSigner: false, isWritable: false },\r\n { pubkey: tokenProgramId, isSigner: false, isWritable: false },\r\n ];\r\n}\r\n","/**\r\n * @module adl\r\n * Percolator ADL (Auto-Deleveraging) client utilities.\r\n *\r\n * PERC-8278 / PERC-8312 / PERC-305: ADL is triggered when `pnl_pos_tot > max_pnl_cap`\r\n * on a market (PnL cap exceeded) AND the insurance fund is fully depleted (balance == 0).\r\n * The most profitable positions on the dominant side are deleveraged first.\r\n *\r\n * **Note on caller permissions:** `ExecuteAdl` (tag 50) requires the caller to be the\r\n * market admin/keeper key (`header.admin`). It is NOT permissionless despite the\r\n * instruction being structurally available to any signer.\r\n *\r\n * API surface:\r\n * - fetchAdlRankedPositions() — fetch slab + rank all open positions by PnL%\r\n * - rankAdlPositions() — pure (no-RPC) variant for already-fetched slab bytes\r\n * - isAdlTriggered() — check if slab's pnl_pos_tot exceeds max_pnl_cap\r\n * - buildAdlInstruction() — unsupported in v17; throws a clear error\r\n * - buildAdlTransaction() — unsupported in v17 when an ADL target exists\r\n * - parseAdlEvent() — decode AdlEvent from transaction log lines\r\n * - fetchAdlRankings() — call /api/adl/rankings HTTP endpoint\r\n * - AdlRankedPosition — position record with adl_rank and computed pnlPct\r\n * - AdlRankingResult — full ranking with trigger status\r\n * - AdlEvent — decoded on-chain AdlEvent log entry (tag 0xAD1E_0001)\r\n * - AdlApiRanking — single ranked position from /api/adl/rankings\r\n * - AdlApiResult — full result from /api/adl/rankings\r\n * - AdlSide — \"long\" | \"short\"\r\n */\r\n\r\nimport {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n} from \"@solana/web3.js\";\r\nimport {\r\n fetchSlab,\r\n parseAllAccounts,\r\n parseEngine,\r\n parseConfig,\r\n detectSlabLayout,\r\n AccountKind,\r\n Account,\r\n SlabLayout,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Position side derived from positionSize sign. */\r\nexport type AdlSide = \"long\" | \"short\";\r\n\r\nconst V17_ADL_UNSUPPORTED_MESSAGE =\r\n \"buildAdlInstruction: ExecuteAdl transaction building is not supported by the v17 SDK because ExecuteAdl is not accepted by the v17 wrapper. Use ranking/API helpers only, or use a version-specific SDK for deployed legacy ADL.\";\r\n\r\n/**\r\n * A ranked open position for ADL purposes.\r\n * Positions are ranked descending by `pnlPct` — rank 0 is the most profitable\r\n * and will be deleveraged first.\r\n */\r\nexport interface AdlRankedPosition {\r\n /** Account index in the slab (used as `targetIdx` in ExecuteAdl). */\r\n idx: number;\r\n /** Owner public key. */\r\n owner: PublicKey;\r\n /** Raw position size (i128 — negative = short, positive = long). */\r\n positionSize: bigint;\r\n /** Realised + mark-to-market PnL in lamports (i128 from slab). */\r\n pnl: bigint;\r\n /** Capital at entry in lamports (u128). */\r\n capital: bigint;\r\n /**\r\n * PnL as a fraction of capital, expressed as basis points (scaled × 10_000).\r\n * pnlPct = pnl * 10_000 / capital.\r\n * Higher = more profitable = deleveraged first.\r\n */\r\n pnlPct: bigint;\r\n /** Long or short. */\r\n side: AdlSide;\r\n /**\r\n * ADL rank among positions on the same side (0 = highest PnL%, deleveraged first).\r\n * `-1` if position size is zero (inactive).\r\n */\r\n adlRank: number;\r\n}\r\n\r\n/**\r\n * Result of `fetchAdlRankedPositions`.\r\n */\r\nexport interface AdlRankingResult {\r\n /** All open (non-zero) user positions, sorted descending by PnLPct, ranked. */\r\n ranked: AdlRankedPosition[];\r\n /**\r\n * Longs ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable long = first to be deleveraged on a net-long market.\r\n */\r\n longs: AdlRankedPosition[];\r\n /**\r\n * Shorts ranked separately (adlRank within this subset).\r\n * Rank 0 = most profitable short (most negative pnlPct magnitude — i.e., highest\r\n * unrealised gain for the short-side holder).\r\n */\r\n shorts: AdlRankedPosition[];\r\n /** Whether ADL is currently triggered (pnlPosTot > maxPnlCap). */\r\n isTriggered: boolean;\r\n /** pnl_pos_tot from engine state. */\r\n pnlPosTot: bigint;\r\n /** max_pnl_cap from market config. */\r\n maxPnlCap: bigint;\r\n /**\r\n * The side with greater net open interest (engine.longOi vs engine.shortOi).\r\n *\r\n * `null` when the side cannot be determined — either engine state could not be\r\n * parsed at all, OR the detected slab layout carries no open-interest fields.\r\n * V0, V2 and v12.15 layouts set engineLongOiOff/engineShortOiOff to -1, and\r\n * parseEngine SUCCEEDS on those returning longOi = shortOi = 0n, so a naive\r\n * `shortOi > longOi` comparison would silently report \"long\" for a slab that\r\n * has no OI data at all. Callers must treat `null` as \"unknown\", not \"long\".\r\n *\r\n * Ties (equal, non-absent OI) resolve to \"long\". That is this SDK's own\r\n * convention, not an on-chain guarantee — the deployed wrapper\r\n * percolator-prog@19d5d932 emits no target_side log and exposes no tie rule.\r\n */\r\n dominantSide: AdlSide | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute PnL% in basis points for a position.\r\n * Returns 0n when capital is 0 to avoid division by zero.\r\n */\r\nfunction computePnlPct(pnl: bigint, capital: bigint): bigint {\r\n if (capital === 0n) return 0n;\r\n return (pnl * 10_000n) / capital;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check whether ADL is currently triggered on a slab.\r\n *\r\n * ADL triggers when pnl_pos_tot > max_pnl_cap (max_pnl_cap must be > 0).\r\n *\r\n * @param slabData - Raw slab account bytes.\r\n * @returns true if ADL is triggered.\r\n *\r\n * @example\r\n * ```ts\r\n * const data = await fetchSlab(connection, slabKey);\r\n * if (isAdlTriggered(data)) {\r\n * const ranking = await fetchAdlRankedPositions(connection, slabKey);\r\n * }\r\n * ```\r\n */\r\nexport function isAdlTriggered(slabData: Uint8Array): boolean {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n if (!layout) return false;\r\n try {\r\n const engine = parseEngine(slabData);\r\n if (engine.pnlPosTot === 0n) return false;\r\n const config = parseConfig(slabData, layout);\r\n if (config.maxPnlCap === 0n) return false;\r\n return engine.pnlPosTot > config.maxPnlCap;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Fetch a slab and rank all open user positions by PnL% for ADL targeting.\r\n *\r\n * Positions are ranked separately per side:\r\n * - Longs: rank 0 = highest positive PnL% (most profitable long)\r\n * - Shorts: rank 0 = highest negative PnL% by abs value (most profitable short)\r\n *\r\n * Rank ordering matches the on-chain ADL engine in percolator-prog (PERC-8273):\r\n * the position at rank 0 of the dominant side is deleveraged first.\r\n *\r\n * @param connection - Solana connection.\r\n * @param slab - Slab (market) public key.\r\n * @returns AdlRankingResult with ranked longs, ranked shorts, and trigger status.\r\n *\r\n * @example\r\n * ```ts\r\n * const { ranked, longs, isTriggered } = await fetchAdlRankedPositions(connection, slabKey);\r\n * if (isTriggered && longs.length > 0) {\r\n * const target = longs[0]; // highest PnL long\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, programId, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankedPositions(\r\n connection: Connection,\r\n slab: PublicKey\r\n): Promise {\r\n const data = await fetchSlab(connection, slab);\r\n return rankAdlPositions(data);\r\n}\r\n\r\n/**\r\n * Pure (no-RPC) variant — rank positions from already-fetched slab bytes.\r\n * Useful when you already have the slab data (e.g., from a subscription).\r\n */\r\nexport function rankAdlPositions(slabData: Uint8Array): AdlRankingResult {\r\n const layout = detectSlabLayout(slabData.length, slabData);\r\n\r\n let pnlPosTot = 0n;\r\n let dominantSide: AdlSide | null = null;\r\n try {\r\n const engine = parseEngine(slabData);\r\n pnlPosTot = engine.pnlPosTot;\r\n // Only meaningful when the layout actually carries OI fields. On V0, V2 and\r\n // v12.15 both offsets are -1 and parseEngine returns 0n for each, so\r\n // comparing them would fabricate \"long\" from absent data.\r\n const hasOiFields =\r\n layout !== null && layout.engineLongOiOff >= 0 && layout.engineShortOiOff >= 0;\r\n if (hasOiFields) {\r\n // Ties resolve to \"long\" (SDK convention — see AdlRankingResult.dominantSide).\r\n dominantSide = engine.shortOi > engine.longOi ? \"short\" : \"long\";\r\n }\r\n } catch (err) {\r\n console.warn(\r\n `[rankAdlPositions] parseEngine failed:`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n let maxPnlCap = 0n;\r\n let isTriggered = false;\r\n if (layout) {\r\n try {\r\n const config = parseConfig(slabData, layout);\r\n maxPnlCap = config.maxPnlCap;\r\n isTriggered = maxPnlCap > 0n && pnlPosTot > maxPnlCap;\r\n } catch {\r\n // If config parse fails, leave isTriggered=false; ranking still useful.\r\n }\r\n }\r\n\r\n // Parse all used accounts.\r\n const accounts = parseAllAccounts(slabData);\r\n\r\n // Build ranked position list (user accounts with non-zero position only).\r\n const positions: AdlRankedPosition[] = [];\r\n for (const { idx, account } of accounts) {\r\n if (account.kind !== AccountKind.User) continue;\r\n if (account.positionSize === 0n) continue;\r\n\r\n const side: AdlSide = account.positionSize > 0n ? \"long\" : \"short\";\r\n // For shorts, positionSize is negative — PnL computation is symmetric:\r\n // a short profits when price falls, so pnl stored in the slab already\r\n // reflects mark-to-market gain/loss for both sides.\r\n const pnlPct = computePnlPct(account.pnl, account.capital);\r\n\r\n positions.push({\r\n idx,\r\n owner: account.owner,\r\n positionSize: account.positionSize,\r\n pnl: account.pnl,\r\n capital: account.capital,\r\n pnlPct,\r\n side,\r\n adlRank: -1, // assigned below\r\n });\r\n }\r\n\r\n // Rank longs: descending pnlPct (most profitable first).\r\n const longs = positions\r\n .filter(p => p.side === \"long\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n longs.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Rank shorts: descending pnlPct (most profitable short = highest pnlPct\r\n // magnitude, but pnlPct can be negative; sort descending still puts\r\n // the \"least negative\" aka \"most profitable\" short first).\r\n const shorts = positions\r\n .filter(p => p.side === \"short\")\r\n .sort((a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0));\r\n shorts.forEach((p, i) => { p.adlRank = i; });\r\n\r\n // Overall ranked list = longs + shorts merged, still sorted by pnlPct desc.\r\n const ranked = [...longs, ...shorts].sort(\r\n (a, b) => (b.pnlPct > a.pnlPct ? 1 : b.pnlPct < a.pnlPct ? -1 : 0)\r\n );\r\n\r\n return { ranked, longs, shorts, isTriggered, pnlPosTot, maxPnlCap, dominantSide };\r\n}\r\n\r\n/**\r\n * Unsupported in v17: `ExecuteAdl` transaction building is not available in\r\n * the v17 wrapper path. The ranking, trigger-check, HTTP API, and event parser\r\n * utilities remain available.\r\n *\r\n * This function is kept as a deprecated compatibility stub so consumers get a\r\n * deterministic error instead of a lower-level removed-instruction throw.\r\n *\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key for this market.\r\n * @param programId - Percolator program ID.\r\n * @param targetIdx - Account index to deleverage (from `AdlRankedPosition.idx`).\r\n * @param backupOracles - Optional additional oracle accounts (non-Hyperp markets).\r\n * @deprecated ExecuteAdl transaction building is not supported in the v17 SDK.\r\n */\r\nexport function buildAdlInstruction(\r\n _caller: PublicKey,\r\n _slab: PublicKey,\r\n _oracle: PublicKey,\r\n _programId: PublicKey,\r\n targetIdx: number,\r\n _backupOracles: PublicKey[] = []\r\n): TransactionInstruction {\r\n if (!Number.isInteger(targetIdx) || targetIdx < 0) {\r\n throw new Error(\r\n `buildAdlInstruction: targetIdx must be a non-negative integer, got ${targetIdx}`,\r\n );\r\n }\r\n throw new Error(V17_ADL_UNSUPPORTED_MESSAGE);\r\n}\r\n\r\n/**\r\n * Choose which ranked position an ADL should target.\r\n *\r\n * Exported so the selection rule can be tested directly: `buildAdlTransaction`\r\n * needs a live Connection and, on v17, cannot complete anyway (see its note), so\r\n * a test routed through it could not observe the choice.\r\n *\r\n * - An explicit `preferSide` always wins.\r\n * - Otherwise the dominant side's top-ranked position. NOTE this is an SDK\r\n * heuristic, not an on-chain rule: the engine pinned to the deployed wrapper\r\n * (percolator@f53be74a) contains no long-vs-short OI comparison and no notion\r\n * of a \"dominant side\" at all. It is a reasonable default for a client picking\r\n * a candidate, nothing more.\r\n * - When `dominantSide` is null (engine unparseable, or a layout with no OI\r\n * fields such as V0/V2/v12.15) fall back to the overall top-ranked position\r\n * rather than guessing a side.\r\n */\r\nexport function selectAdlTarget(\r\n ranking: Pick,\r\n preferSide?: AdlSide,\r\n): AdlRankedPosition | undefined {\r\n if (preferSide === \"long\") return ranking.longs[0];\r\n if (preferSide === \"short\") return ranking.shorts[0];\r\n if (ranking.dominantSide === \"long\") return ranking.longs[0];\r\n if (ranking.dominantSide === \"short\") return ranking.shorts[0];\r\n return ranking.ranked[0];\r\n}\r\n\r\n/**\r\n * Convenience builder: fetch slab, rank positions, pick the highest-ranked\r\n * target on the given side, and return a ready-to-send `TransactionInstruction`.\r\n *\r\n * Returns `null` when ADL is not triggered or no eligible positions exist.\r\n *\r\n * NOTE (v17): this cannot produce a usable transaction on the deployed program.\r\n * When a target IS found it calls `buildAdlInstruction`, which throws\r\n * V17_ADL_UNSUPPORTED_MESSAGE — the deployed wrapper percolator-prog@19d5d932 has\r\n * no ExecuteAdl handler. (This module never calls `encodeExecuteAdl`; an earlier\r\n * revision of this note claimed it did, which was simply wrong.) It is kept for\r\n * v12 slabs and for when an equivalent v17 instruction lands; the target\r\n * selection in `selectAdlTarget` stays valid either way.\r\n *\r\n * @param connection - Solana connection.\r\n * @param caller - Signer — must be the market keeper/admin authority.\r\n * @param slab - Slab (market) public key.\r\n * @param oracle - Primary oracle public key.\r\n * @param programId - Percolator program ID.\r\n * @param preferSide - Optional: target \"long\" or \"short\" side only.\r\n * If omitted, picks the dominant side's (greater net OI)\r\n * top-ranked position — or the overall top-ranked position\r\n * when dominantSide is null (engine unparseable, or a\r\n * layout with no OI fields such as V0/V2/v12.15).\r\n * @param backupOracles - Optional extra oracle accounts.\r\n *\r\n * @example\r\n * ```ts\r\n * const ix = await buildAdlTransaction(\r\n * connection, caller.publicKey, slabKey, oracleKey, PROGRAM_ID\r\n * );\r\n * if (ix) {\r\n * await sendAndConfirmTransaction(connection, new Transaction().add(ix), [caller]);\r\n * }\r\n * ```\r\n */\r\nexport async function buildAdlTransaction(\r\n connection: Connection,\r\n caller: PublicKey,\r\n slab: PublicKey,\r\n oracle: PublicKey,\r\n programId: PublicKey,\r\n preferSide?: AdlSide,\r\n backupOracles: PublicKey[] = []\r\n): Promise {\r\n const ranking = await fetchAdlRankedPositions(connection, slab);\r\n\r\n if (!ranking.isTriggered) return null;\r\n\r\n const target = selectAdlTarget(ranking, preferSide);\r\n\r\n if (!target) return null;\r\n\r\n return buildAdlInstruction(caller, slab, oracle, programId, target.idx, backupOracles);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AdlEvent — on-chain log decoder (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Decoded on-chain AdlEvent emitted by the `ExecuteAdl` instruction handler.\r\n *\r\n * The on-chain handler emits via `sol_log_64(0xAD1E_0001, target_idx, price, closed_lo, closed_hi)`.\r\n * `sol_log_64` prints 5 decimal u64 values separated by spaces on a single \"Program log:\" line.\r\n *\r\n * Fields:\r\n * - `tag` — always `0xAD1E_0001` (2970353665n)\r\n * - `targetIdx` — slab account index that was deleveraged\r\n * - `price` — oracle price used (in market price units, e.g. e6)\r\n * - `closedAbs` — absolute size of the position closed (i128, reassembled from lo+hi u64 parts)\r\n *\r\n * @example\r\n * ```ts\r\n * const logs = tx.meta?.logMessages ?? [];\r\n * const event = parseAdlEvent(logs);\r\n * if (event) {\r\n * console.log(\"ADL closed position\", event.targetIdx, \"size\", event.closedAbs);\r\n * }\r\n * ```\r\n */\r\nexport interface AdlEvent {\r\n /** Tag discriminator — always 0xAD1E_0001n (2970353665). */\r\n tag: bigint;\r\n /** Slab account index that was deleveraged. */\r\n targetIdx: number;\r\n /** Oracle price used for the deleverage (market-native units, e.g. lamports/e6). */\r\n price: bigint;\r\n /**\r\n * Absolute position size closed (reassembled from lo+hi u64).\r\n * This is the i128 absolute value — always non-negative.\r\n */\r\n closedAbs: bigint;\r\n}\r\n\r\n/** Magic discriminator for the ADL event log line. */\r\nconst ADL_EVENT_TAG = 0xAD1E_0001n;\r\n\r\n/**\r\n * Parse the AdlEvent from a transaction's log messages.\r\n *\r\n * Searches for a \"Program log: \" line where the first\r\n * decimal value equals `0xAD1E_0001` (2970353665). Returns `null` if not found.\r\n *\r\n * @param logs - Array of log message strings (from `tx.meta.logMessages`).\r\n * @param percolatorProgramId - When supplied, only ADL events emitted directly\r\n * by this program ID are accepted. Events from CPI-called programs (which can\r\n * produce identical `Program log:` lines) are silently ignored. Pass the\r\n * program ID used to send the transaction (e.g. `getProgramId().toBase58()`).\r\n * Omit only in contexts where the full log has already been filtered.\r\n * @returns Decoded `AdlEvent` or `null` if the log is not present.\r\n *\r\n * @example\r\n * ```ts\r\n * const event = parseAdlEvent(tx.meta?.logMessages ?? [], getProgramId().toBase58());\r\n * if (event) {\r\n * console.log(`ADL: idx=${event.targetIdx} price=${event.price} closed=${event.closedAbs}`);\r\n * }\r\n * ```\r\n */\r\nexport function parseAdlEvent(\r\n logs: string[],\r\n percolatorProgramId?: string,\r\n): AdlEvent | null {\r\n // Track whether we are currently inside a top-level Percolator invocation.\r\n // When percolatorProgramId is omitted we skip the filter (legacy behaviour).\r\n let insidePercolator = percolatorProgramId === undefined;\r\n let cpiDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n if (percolatorProgramId !== undefined) {\r\n // Detect Percolator entry / exit.\r\n if (line.startsWith(`Program ${percolatorProgramId} invoke`)) {\r\n insidePercolator = true;\r\n cpiDepth = 0;\r\n continue;\r\n }\r\n if (\r\n line.startsWith(`Program ${percolatorProgramId} success`) ||\r\n line.startsWith(`Program ${percolatorProgramId} failed`)\r\n ) {\r\n insidePercolator = false;\r\n continue;\r\n }\r\n // Track nested CPI depth so we ignore sol_log_64 from inner programs.\r\n if (insidePercolator) {\r\n if (/^Program \\S+ invoke/.test(line)) {\r\n cpiDepth++;\r\n continue;\r\n }\r\n if (/^Program \\S+ (?:success|failed)$/.test(line)) {\r\n cpiDepth = Math.max(0, cpiDepth - 1);\r\n continue;\r\n }\r\n }\r\n // Skip log lines that are not inside Percolator or are from a CPI callee.\r\n if (!insidePercolator || cpiDepth > 0) continue;\r\n }\r\n\r\n // sol_log_64 emits: \"Program log: a b c d e\" (5 space-separated decimals)\r\n const match = line.match(\r\n /^Program log: (\\d+) (\\d+) (\\d+) (\\d+) (\\d+)$/,\r\n );\r\n if (!match) continue;\r\n\r\n let tag: bigint;\r\n try {\r\n tag = BigInt(match[1]);\r\n } catch {\r\n continue;\r\n }\r\n\r\n if (tag !== ADL_EVENT_TAG) continue;\r\n\r\n try {\r\n const targetIdx = Number(BigInt(match[2]));\r\n const price = BigInt(match[3]);\r\n const closedLo = BigInt(match[4]);\r\n const closedHi = BigInt(match[5]);\r\n // Reassemble i128 from lo/hi u64 parts (little-endian split).\r\n const closedAbs = (closedHi << 64n) | closedLo;\r\n return { tag, targetIdx, price, closedAbs };\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchAdlRankings — HTTP client for /api/adl/rankings (PERC-8312)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A single ranked position as returned by the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiRanking {\r\n /** 1-based rank (1 = highest PnL%, first to be deleveraged). */\r\n rank: number;\r\n /** Slab account index. Pass as `targetIdx` to `buildAdlInstruction`. */\r\n idx: number;\r\n /** Absolute PnL (lamports) as a decimal string. */\r\n pnlAbs: string;\r\n /** Capital at entry (lamports) as a decimal string. */\r\n capital: string;\r\n /** PnL as millionths of capital (pnl * 1_000_000 / capital). */\r\n pnlPctMillionths: string;\r\n}\r\n\r\n/**\r\n * Full result from the /api/adl/rankings endpoint.\r\n */\r\nexport interface AdlApiResult {\r\n slabAddress: string;\r\n /** pnl_pos_tot from slab engine state (decimal string). */\r\n pnlPosTot: string;\r\n /** max_pnl_cap from market config (decimal string, \"0\" if unconfigured). */\r\n maxPnlCap: string;\r\n /** Insurance fund balance (decimal string). */\r\n insuranceFundBalance: string;\r\n /** Insurance fund lifetime fee revenue (decimal string). */\r\n insuranceFundFeeRevenue: string;\r\n /** Insurance utilization in basis points (0–10000). */\r\n insuranceUtilizationBps: number;\r\n /** true if pnlPosTot > maxPnlCap. */\r\n capExceeded: boolean;\r\n /** true if insurance fund is fully depleted (balance == 0). */\r\n insuranceDepleted: boolean;\r\n /** true if utilization BPS exceeds the configured ADL threshold. */\r\n utilizationTriggered: boolean;\r\n /** true if ADL is needed (capExceeded or utilizationTriggered). */\r\n adlNeeded: boolean;\r\n /** Excess PnL above cap (decimal string). */\r\n excess: string;\r\n /** Ranked positions (empty if adlNeeded=false). */\r\n rankings: AdlApiRanking[];\r\n}\r\n\r\n/**\r\n * Fetch ADL rankings from the Percolator API.\r\n *\r\n * Calls `GET /api/adl/rankings?slab=
` and returns the\r\n * parsed result. Use this from the frontend or keeper to determine ADL\r\n * trigger status and pick the target index.\r\n *\r\n * @param apiBase - Base URL of the Percolator API (e.g. `https://api.percolator.io`).\r\n * @param slab - Slab (market) public key or base58 address string.\r\n * @param fetchFn - Optional custom fetch implementation (defaults to global `fetch`).\r\n * @returns Parsed `AdlApiResult`.\r\n * @throws On HTTP error or JSON parse failure.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await fetchAdlRankings(\"https://api.percolator.io\", slabKey);\r\n * if (result.adlNeeded && result.rankings.length > 0) {\r\n * const target = result.rankings[0]; // rank 1 = highest PnL%\r\n * const ix = buildAdlInstruction(caller, slabKey, oracleKey, PROGRAM_ID, target.idx);\r\n * }\r\n * ```\r\n */\r\nexport async function fetchAdlRankings(\r\n apiBase: string,\r\n slab: PublicKey | string,\r\n fetchFn: typeof fetch = fetch,\r\n): Promise {\r\n const slabStr = typeof slab === \"string\" ? slab : slab.toBase58();\r\n const base = apiBase.replace(/\\/$/, \"\");\r\n const url = `${base}/api/adl/rankings?slab=${encodeURIComponent(slabStr)}`;\r\n\r\n const res = await fetchFn(url);\r\n if (!res.ok) {\r\n let body = \"\";\r\n try { body = await res.text(); } catch { /* ignore */ }\r\n throw new Error(\r\n `fetchAdlRankings: HTTP ${res.status} from ${url}${body ? ` — ${body}` : \"\"}`,\r\n );\r\n }\r\n\r\n const json: unknown = await res.json();\r\n\r\n // Runtime validation — the API response shape is not guaranteed\r\n if (typeof json !== \"object\" || json === null) {\r\n throw new Error(\"fetchAdlRankings: API returned non-object response\");\r\n }\r\n const obj = json as Record;\r\n if (!Array.isArray(obj.rankings)) {\r\n throw new Error(\"fetchAdlRankings: API response missing rankings array\");\r\n }\r\n if (typeof obj.adlNeeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid adlNeeded field: ${obj.adlNeeded}`);\r\n }\r\n if (typeof obj.capExceeded !== \"boolean\") {\r\n throw new Error(`fetchAdlRankings: invalid capExceeded field: ${obj.capExceeded}`);\r\n }\r\n if (typeof obj.slabAddress !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid slabAddress field: ${obj.slabAddress}`);\r\n }\r\n if (typeof obj.pnlPosTot !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid pnlPosTot field: ${obj.pnlPosTot}`);\r\n }\r\n if (typeof obj.maxPnlCap !== \"string\") {\r\n throw new Error(`fetchAdlRankings: invalid maxPnlCap field: ${obj.maxPnlCap}`);\r\n }\r\n for (const entry of obj.rankings) {\r\n if (typeof entry !== \"object\" || entry === null) {\r\n throw new Error(\"fetchAdlRankings: invalid ranking entry (not an object)\");\r\n }\r\n const r = entry as Record;\r\n if (typeof r.idx !== \"number\" || !Number.isInteger(r.idx) || r.idx < 0) {\r\n throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);\r\n }\r\n }\r\n\r\n return json as AdlApiResult;\r\n}\r\n","/**\r\n * @module backing-bucket\r\n * v17 source-domain backing-bucket state: the read path behind `ExpireBackingBucket` (tag 89).\r\n *\r\n * ## Why this module exists\r\n *\r\n * The SDK could already *encode* tag 89 but had no way to tell whether a bucket had\r\n * actually lapsed. A keeper with an encoder and no detector has two bad options: crank\r\n * every domain every cycle (paying for a guaranteed revert on every healthy domain), or\r\n * never crank at all (leaving lapsed domains bricked). This module supplies the missing\r\n * predicate.\r\n *\r\n * ## Why lapsing is routine, not exceptional\r\n *\r\n * A bucket's `expiry_slot` is fixed when the bucket opens and is **never extended while\r\n * it stays `Fresh`** — the engine's `fresh_counterparty_backing_expiry_slot`\r\n * (`percolator/src/v16.rs:6303-6310`) returns the stored value unchanged on a live\r\n * bucket and only computes a fresh horizon once the bucket is no longer\r\n * `Fresh`-and-unexpired. **Every backed market therefore lapses eventually.** Seeding a\r\n * far-future expiry defers the lapse; it does not prevent it.\r\n *\r\n * Once lapsed, the domain is a dead end in every direction until tag 89 runs:\r\n *\r\n * | Attempt against a lapsed domain | Result |\r\n * |---|---|\r\n * | settle a **loss** | `EngineLockActive` Custom(21) |\r\n * | settle a **gain** | `EngineStale` Custom(19) |\r\n * | `TopUpBackingBucket` (tag 24) to re-fund it | `EngineLockActive` Custom(21) |\r\n *\r\n * The gain path is `validate_source_domain_ledger_current` (`v16.rs:6294-6301`), which\r\n * returns `Stale` for exactly `status == Fresh && expiry_slot <= current_slot`. It cannot\r\n * even be paid to come back. Scanning for lapsed domains and expiring them is a standing\r\n * keeper duty, alongside the fee crank.\r\n *\r\n * ## Layout provenance\r\n *\r\n * Every offset below was produced by `offset_of!` against the engine's own `#[repr(C)]`\r\n * account structs (`percolator/src/v16.rs`), not inferred from field order:\r\n *\r\n * ```\r\n * EngineAssetSlotV16Account size=1285 backing_long @ 947 backing_short @ 1044\r\n * BackingBucketV16Account size=97\r\n * 0 market_id 8 fresh_unliened_backing_num 24 valid_liened_backing_num\r\n * 40 consumed_liened... 56 impaired_liened... 72 utilization_fee_earnings\r\n * 88 expiry_slot 96 status\r\n * MarketGroupV16HeaderAccount config @ 32 current_slot @ 613 mode @ 626\r\n * V16ConfigAccount max_portfolio_assets @ 0 max_market_slots @ 2\r\n * ```\r\n *\r\n * Every `V16Pod*` field is an align-1 `[u8; N]` and every struct derives `bytemuck::Pod`\r\n * (which forbids implicit padding), so these are byte offsets with no alignment gaps.\r\n */\r\n\r\nimport {\r\n V17_MARKET_GROUP_OFF,\r\n V17_MARKET_GROUP_LEN,\r\n V17_MARKET_ASSET_SLOT_LEN,\r\n isV17MarketAccount,\r\n} from \"./slab.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Little-endian readers (module-local, matching slab.ts's private helpers)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction readU8At(data: Uint8Array, off: number): number {\r\n if (off + 1 > data.length) throw new Error(`readU8At: out of bounds at ${off}`);\r\n return data[off]!;\r\n}\r\n\r\nfunction readU32LEAt(data: Uint8Array, off: number): number {\r\n if (off + 4 > data.length) throw new Error(`readU32LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 4).getUint32(0, true);\r\n}\r\n\r\nfunction readU64LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 8 > data.length) throw new Error(`readU64LEAt: out of bounds at ${off}`);\r\n return new DataView(data.buffer, data.byteOffset + off, 8).getBigUint64(0, true);\r\n}\r\n\r\nfunction readU128LEAt(data: Uint8Array, off: number): bigint {\r\n if (off + 16 > data.length) throw new Error(`readU128LEAt: out of bounds at ${off}`);\r\n const dv = new DataView(data.buffer, data.byteOffset + off, 16);\r\n const lo = dv.getBigUint64(0, true);\r\n const hi = dv.getBigUint64(8, true);\r\n return (hi << 64n) | lo;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Layout constants — all verified with offset_of! (see module doc)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** `MarketGroupV16HeaderAccount::config` (V16ConfigAccount), relative to the group header. */\r\nexport const V17_GROUP_CONFIG_REL = 32;\r\n/** `MarketGroupV16HeaderAccount::current_slot` (u64), relative to the group header. */\r\nexport const V17_GROUP_CURRENT_SLOT_REL = 613;\r\n/** `MarketGroupV16HeaderAccount::mode` (u8), relative to the group header. 0=Live, 1=Resolved, 2=Recovery. */\r\nexport const V17_GROUP_MODE_REL = 626;\r\n/** `V16ConfigAccount::max_market_slots` (u32), relative to the config block. */\r\nexport const V17_CONFIG_MAX_MARKET_SLOTS_REL = 2;\r\n\r\n/** The 512-byte wrapper oracle-storage prefix that precedes `EngineAssetSlotV16Account` in `Market`. */\r\nexport const V17_ASSET_SLOT_WRAPPER_LEN = 512;\r\n/** `EngineAssetSlotV16Account::backing_long`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_LONG_REL = 947;\r\n/** `EngineAssetSlotV16Account::backing_short`, relative to the engine slot start. */\r\nexport const V17_ENGINE_BACKING_SHORT_REL = 1044;\r\n/** `size_of::()`. */\r\nexport const V17_BACKING_BUCKET_LEN = 97;\r\n\r\n// BackingBucketV16Account field offsets, relative to the bucket start.\r\nconst BB_MARKET_ID = 0;\r\nconst BB_FRESH_UNLIENED = 8;\r\nconst BB_VALID_LIENED = 24;\r\nconst BB_CONSUMED_LIENED = 40;\r\nconst BB_IMPAIRED_LIENED = 56;\r\nconst BB_UTILIZATION_FEE = 72;\r\nconst BB_EXPIRY_SLOT = 88;\r\nconst BB_STATUS = 96;\r\n\r\n/** Market mode discriminant (`MarketGroupV16HeaderAccount::mode`). */\r\nexport const V17_MARKET_MODE_LIVE = 0;\r\n\r\n/**\r\n * `BackingBucketStatusV16` (`percolator/src/v16.rs:1674-1679`), a fieldless Rust enum\r\n * serialized as a single `u8` in declaration order.\r\n *\r\n * Only `Fresh` is expirable — see {@link isBackingBucketExpirable}.\r\n */\r\nexport enum BackingBucketStatus {\r\n Empty = 0,\r\n Fresh = 1,\r\n Expired = 2,\r\n Impaired = 3,\r\n}\r\n\r\n/** Human-readable name for a {@link BackingBucketStatus}, or `Unknown(n)` for an unmapped byte. */\r\nexport function backingBucketStatusName(status: number): string {\r\n switch (status) {\r\n case BackingBucketStatus.Empty:\r\n return \"Empty\";\r\n case BackingBucketStatus.Fresh:\r\n return \"Fresh\";\r\n case BackingBucketStatus.Expired:\r\n return \"Expired\";\r\n case BackingBucketStatus.Impaired:\r\n return \"Impaired\";\r\n default:\r\n return `Unknown(${status})`;\r\n }\r\n}\r\n\r\n/** One source-domain backing bucket, decoded from a v17 market account. */\r\nexport interface BackingBucketV17 {\r\n /** Domain index. `domain = assetIndex * 2 + (side === \"short\" ? 1 : 0)`. */\r\n domain: number;\r\n /** `domain / 2` — the asset slot this domain belongs to. */\r\n assetIndex: number;\r\n /** `domain % 2` — even domains are LONG, odd domains are SHORT. */\r\n side: \"long\" | \"short\";\r\n /** `BackingBucketV16Account::market_id`. */\r\n marketId: bigint;\r\n /** Principal that is reserved but carries no lien. Forfeited to the junior pool on expiry. */\r\n freshUnlienedBackingNum: bigint;\r\n /** Principal under a live lien. Moves to `impairedLienedBackingNum` on expiry. */\r\n validLienedBackingNum: bigint;\r\n /** Principal already consumed by settlement. */\r\n consumedLienedBackingNum: bigint;\r\n /** Principal whose lien has been impaired. */\r\n impairedLienedBackingNum: bigint;\r\n /** Utilization fees accrued to this bucket. */\r\n utilizationFeeEarnings: bigint;\r\n /** Slot at which a `Fresh` bucket lapses. Fixed when the bucket opens; never extended. */\r\n expirySlot: bigint;\r\n /** Raw status byte. */\r\n status: number;\r\n /** `backingBucketStatusName(status)`. */\r\n statusName: string;\r\n /**\r\n * `status === Fresh && nowSlot >= expirySlot`.\r\n *\r\n * This is the *deadlock* condition — settlement against this domain fails in both\r\n * directions. It is necessary but NOT sufficient for tag 89; see {@link expirable},\r\n * which additionally applies the wrapper's mode and domain-bound gates.\r\n */\r\n lapsed: boolean;\r\n /**\r\n * `true` iff `ExpireBackingBucket` (tag 89) will be ACCEPTED for this domain right now.\r\n * See {@link isBackingBucketExpirable} for the full derivation.\r\n */\r\n expirable: boolean;\r\n}\r\n\r\n/** Whole-market backing-bucket snapshot, as returned by {@link parseBackingBucketsV17}. */\r\nexport interface BackingBucketMarketState {\r\n /** `header.mode` — 0 Live, 1 Resolved, 2 Recovery. Tag 89 requires 0. */\r\n mode: number;\r\n /** `header.current_slot` — the engine's own monotone slot counter. */\r\n headerCurrentSlot: bigint;\r\n /**\r\n * `max(chainSlot, header.current_slot)` — the slot the program itself will use.\r\n * Mirrors `authenticated_market_slot_or_fallback_view` (`v16_program.rs:6332-6339`).\r\n */\r\n nowSlot: bigint;\r\n /** `config.max_market_slots` — the wrapper's domain bound is `max_market_slots * 2`. */\r\n maxMarketSlots: number;\r\n /** Asset slots physically present in the account buffer. */\r\n physicalAssetSlots: number;\r\n /**\r\n * `min(maxMarketSlots, physicalAssetSlots) * 2` — the number of domains that are BOTH\r\n * within the wrapper's declared bound and actually backed by bytes. Domains at or above\r\n * this index are never expirable; see {@link isBackingBucketExpirable}.\r\n */\r\n addressableDomainCount: number;\r\n /** One entry per addressable domain, ascending by `domain`. */\r\n buckets: BackingBucketV17[];\r\n}\r\n\r\n/** Context needed to evaluate the tag-89 acceptance predicate for a single bucket. */\r\nexport interface BackingBucketExpiryContext {\r\n /** `header.mode`. */\r\n mode: number;\r\n /** `max(chainSlot, header.current_slot)`. */\r\n nowSlot: bigint;\r\n /** `min(config.max_market_slots, physicalAssetSlots) * 2`. */\r\n addressableDomainCount: number;\r\n}\r\n\r\n/**\r\n * Decide whether `ExpireBackingBucket` (tag 89) will be ACCEPTED for a domain.\r\n *\r\n * This predicate is the conjunction of every gate on the tag-89 path, read from the\r\n * program rather than from prose. In order of evaluation on chain:\r\n *\r\n * 1. **Live only.** `handle_expire_backing_bucket` (`v16_program.rs:10098-10100`):\r\n * `if group.header.mode != 0 { return Err(EngineLockActive) }` → Custom(21). A resolved\r\n * market reaches the same transition through the engine's own\r\n * `realize_source_backed_claims_for_resolved_close_not_atomic` sweep.\r\n * 2. **Wrapper domain bound.** `v16_program.rs:10102-10105`:\r\n * `if domain >= max_market_slots * 2 { return Err(InvalidInstruction) }` → Custom(9).\r\n * 3. **Engine domain bound.** `domain_asset_side` (`v16.rs:6043-6059`) rejects\r\n * `domain >= configured_domain_count` and, separately, `asset_index >= markets.len()`\r\n * → `InvalidLeg`. The second test is why `physicalAssetSlots` participates: a market\r\n * may be *configured* for more slots than its account was *sized* for.\r\n * 4. **The lapse itself.** `expire_source_backing_bucket_not_atomic` (`v16.rs:6434-6440`):\r\n * `if bucket.status != Fresh || now_slot < bucket.expiry_slot { return Err(Stale) }`\r\n * → Custom(19). Note `>=`, not `>`: at exactly `nowSlot === expirySlot` the bucket is\r\n * both deadlocked and expirable, and the two boundaries agree\r\n * (`validate_source_domain_ledger_current` uses `expiry_slot <= current_slot`).\r\n *\r\n * `now_slot` is never caller-supplied — the program computes\r\n * `max(Clock::get().slot, header.current_slot)` itself\r\n * (`authenticated_market_slot_or_fallback_view`, `v16_program.rs:6332-6339`). Callers must\r\n * pass the same `max` in `ctx.nowSlot`. Using the chain slot alone is a **false negative**\r\n * whenever the engine counter runs ahead, and a false negative here means a domain stays\r\n * bricked. It cannot produce a false positive, because the program recomputes the same\r\n * `max` and no caller can lower it.\r\n *\r\n * **Not modelled:** the engine's `CounterUnderflow` arm (`v16.rs:6444-6449`), which fires\r\n * only if the domain's `SourceCreditState` has drifted below its own bucket's totals. That\r\n * is a broken-invariant state, not a reachable steady state, and gating on it would need\r\n * two more u128 reads to defend against something that indicates corruption anyway.\r\n *\r\n * @param bucket - A decoded bucket from {@link parseBackingBucketsV17}.\r\n * @param ctx - Market-level gates: mode, resolved `nowSlot`, addressable domain count.\r\n * @returns `true` iff the program will accept tag 89 for `bucket.domain` right now.\r\n *\r\n * @example\r\n * ```ts\r\n * const state = parseBackingBucketsV17(marketData, { chainSlot: await conn.getSlot() });\r\n * for (const b of state.buckets) {\r\n * if (isBackingBucketExpirable(b, state)) {\r\n * await send(encodeExpireBackingBucket({ domain: b.domain }));\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isBackingBucketExpirable(\r\n bucket: Pick,\r\n ctx: BackingBucketExpiryContext,\r\n): boolean {\r\n // (1) Live-only mode gate.\r\n if (ctx.mode !== V17_MARKET_MODE_LIVE) return false;\r\n // (2)+(3) Wrapper bound AND engine bound, folded into one addressable count.\r\n if (bucket.domain < 0 || bucket.domain >= ctx.addressableDomainCount) return false;\r\n // (4) The lapse condition, exactly as the engine states it.\r\n if (bucket.status !== BackingBucketStatus.Fresh) return false;\r\n return ctx.nowSlot >= bucket.expirySlot;\r\n}\r\n\r\n/** Options for {@link parseBackingBucketsV17}. */\r\nexport interface ParseBackingBucketsOptions {\r\n /**\r\n * The current chain slot (`connection.getSlot()`).\r\n *\r\n * Omitting it is equivalent to the program's own fallback when `Clock::get()` fails:\r\n * `nowSlot` collapses to `header.current_slot`. That is safe (it can only under-report\r\n * lapses, never over-report them) but a keeper should always supply it — a market whose\r\n * `current_slot` lags produces false negatives, and a false negative leaves a domain\r\n * bricked.\r\n */\r\n chainSlot?: bigint | number;\r\n}\r\n\r\n/**\r\n * Decode every addressable source-domain backing bucket from a raw v17 market account.\r\n *\r\n * Reads `header.mode`, `header.current_slot` and `config.max_market_slots` once, then walks\r\n * the asset slots, emitting the LONG (`2i`) and SHORT (`2i+1`) bucket for each. Each bucket\r\n * carries both `lapsed` (the settlement deadlock condition) and `expirable` (whether tag 89\r\n * will actually be accepted) so a keeper never has to reconstruct the gates itself.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns The whole-market snapshot, including the resolved `nowSlot` used for the predicate.\r\n * @throws If the buffer is too short, or is not a v17 market account (bad magic/version/kind).\r\n *\r\n * @example\r\n * ```ts\r\n * const info = await connection.getAccountInfo(marketPk);\r\n * const state = parseBackingBucketsV17(new Uint8Array(info!.data), {\r\n * chainSlot: await connection.getSlot(),\r\n * });\r\n * console.log(`${state.buckets.filter((b) => b.expirable).length} domain(s) need tag 89`);\r\n * ```\r\n */\r\nexport function parseBackingBucketsV17(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): BackingBucketMarketState {\r\n const MIN_LEN = V17_MARKET_GROUP_OFF + V17_MARKET_GROUP_LEN;\r\n if (data.length < MIN_LEN) {\r\n throw new Error(\r\n `parseBackingBucketsV17: buffer too short — need >= ${MIN_LEN} bytes, got ${data.length}`,\r\n );\r\n }\r\n if (!isV17MarketAccount(data)) {\r\n throw new Error(\r\n \"parseBackingBucketsV17: not a v17 market account (bad magic, version, or kind)\",\r\n );\r\n }\r\n\r\n const groupOff = V17_MARKET_GROUP_OFF;\r\n const mode = readU8At(data, groupOff + V17_GROUP_MODE_REL);\r\n const headerCurrentSlot = readU64LEAt(data, groupOff + V17_GROUP_CURRENT_SLOT_REL);\r\n const maxMarketSlots = readU32LEAt(\r\n data,\r\n groupOff + V17_GROUP_CONFIG_REL + V17_CONFIG_MAX_MARKET_SLOTS_REL,\r\n );\r\n\r\n // `authenticated_market_slot_or_fallback_view`: max(Clock, header.current_slot).\r\n // No chainSlot => the program's Clock-unavailable fallback, i.e. header.current_slot.\r\n const chainSlot =\r\n opts.chainSlot === undefined ? 0n : BigInt(opts.chainSlot);\r\n if (chainSlot < 0n) {\r\n throw new Error(`parseBackingBucketsV17: chainSlot must be non-negative, got ${chainSlot}`);\r\n }\r\n const nowSlot = chainSlot > headerCurrentSlot ? chainSlot : headerCurrentSlot;\r\n\r\n const slotsBase = groupOff + V17_MARKET_GROUP_LEN;\r\n const physicalAssetSlots = Math.max(\r\n 0,\r\n Math.floor((data.length - slotsBase) / V17_MARKET_ASSET_SLOT_LEN),\r\n );\r\n const addressableAssetSlots = Math.min(maxMarketSlots, physicalAssetSlots);\r\n const addressableDomainCount = addressableAssetSlots * 2;\r\n\r\n const ctx: BackingBucketExpiryContext = { mode, nowSlot, addressableDomainCount };\r\n const buckets: BackingBucketV17[] = [];\r\n\r\n for (let assetIndex = 0; assetIndex < addressableAssetSlots; assetIndex++) {\r\n const engineBase =\r\n slotsBase + assetIndex * V17_MARKET_ASSET_SLOT_LEN + V17_ASSET_SLOT_WRAPPER_LEN;\r\n for (const side of [\"long\", \"short\"] as const) {\r\n const bucketOff =\r\n engineBase +\r\n (side === \"long\" ? V17_ENGINE_BACKING_LONG_REL : V17_ENGINE_BACKING_SHORT_REL);\r\n if (bucketOff + V17_BACKING_BUCKET_LEN > data.length) break;\r\n\r\n const domain = assetIndex * 2 + (side === \"short\" ? 1 : 0);\r\n const status = readU8At(data, bucketOff + BB_STATUS);\r\n const expirySlot = readU64LEAt(data, bucketOff + BB_EXPIRY_SLOT);\r\n const lapsed = status === BackingBucketStatus.Fresh && nowSlot >= expirySlot;\r\n\r\n const bucket: BackingBucketV17 = {\r\n domain,\r\n assetIndex,\r\n side,\r\n marketId: readU64LEAt(data, bucketOff + BB_MARKET_ID),\r\n freshUnlienedBackingNum: readU128LEAt(data, bucketOff + BB_FRESH_UNLIENED),\r\n validLienedBackingNum: readU128LEAt(data, bucketOff + BB_VALID_LIENED),\r\n consumedLienedBackingNum: readU128LEAt(data, bucketOff + BB_CONSUMED_LIENED),\r\n impairedLienedBackingNum: readU128LEAt(data, bucketOff + BB_IMPAIRED_LIENED),\r\n utilizationFeeEarnings: readU128LEAt(data, bucketOff + BB_UTILIZATION_FEE),\r\n expirySlot,\r\n status,\r\n statusName: backingBucketStatusName(status),\r\n lapsed,\r\n expirable: false,\r\n };\r\n bucket.expirable = isBackingBucketExpirable(bucket, ctx);\r\n buckets.push(bucket);\r\n }\r\n }\r\n\r\n return {\r\n mode,\r\n headerCurrentSlot,\r\n nowSlot,\r\n maxMarketSlots,\r\n physicalAssetSlots,\r\n addressableDomainCount,\r\n buckets,\r\n };\r\n}\r\n\r\n/**\r\n * Convenience wrapper over {@link parseBackingBucketsV17}: the domains that need tag 89 now.\r\n *\r\n * Returns domain indices in ascending order, ready to feed straight into\r\n * `encodeExpireBackingBucket({ domain })`. Returns `[]` when there is nothing to do — the\r\n * common case on a healthy market, and the case in which a keeper must send nothing.\r\n *\r\n * @param data - Raw bytes of the v17 market group account.\r\n * @param opts - See {@link ParseBackingBucketsOptions}.\r\n * @returns Ascending list of expirable domain indices; empty when none are due.\r\n *\r\n * @example\r\n * ```ts\r\n * const domains = findExpirableBackingDomains(marketData, { chainSlot: slot });\r\n * for (const domain of domains) {\r\n * tx.add(new TransactionInstruction({\r\n * programId: WRAPPER_ID,\r\n * keys: [{ pubkey: marketPk, isSigner: false, isWritable: true }],\r\n * data: Buffer.from(encodeExpireBackingBucket({ domain })),\r\n * }));\r\n * }\r\n * ```\r\n */\r\nexport function findExpirableBackingDomains(\r\n data: Uint8Array,\r\n opts: ParseBackingBucketsOptions = {},\r\n): number[] {\r\n return parseBackingBucketsV17(data, opts)\r\n .buckets.filter((b) => b.expirable)\r\n .map((b) => b.domain);\r\n}\r\n","import {\r\n Connection,\r\n type Commitment,\r\n type ConnectionConfig,\r\n} from \"@solana/web3.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Configuration for exponential-backoff retry on RPC calls.\r\n *\r\n * @example\r\n * ```ts\r\n * const retryConfig: RetryConfig = {\r\n * maxRetries: 3,\r\n * baseDelayMs: 500,\r\n * maxDelayMs: 10_000,\r\n * retryableStatusCodes: [429, 502, 503],\r\n * };\r\n * ```\r\n */\r\nexport interface RetryConfig {\r\n /**\r\n * Maximum number of retry attempts after the initial request fails.\r\n * @default 3\r\n */\r\n maxRetries?: number;\r\n\r\n /**\r\n * Base delay in ms for exponential backoff.\r\n * Delay for attempt N is: `min(baseDelayMs * 2^N, maxDelayMs) + jitter`.\r\n * @default 500\r\n */\r\n baseDelayMs?: number;\r\n\r\n /**\r\n * Maximum delay in ms (backoff cap).\r\n * @default 10_000\r\n */\r\n maxDelayMs?: number;\r\n\r\n /**\r\n * Jitter factor (0–1). When non-zero, equal-jitter is applied: the computed\r\n * delay `raw` is split at its midpoint and a random value `[half, raw]` is\r\n * returned, bounding variance to 50 % of the backoff. Set to `0` to disable\r\n * jitter entirely (deterministic backoff).\r\n * @default 0.25\r\n */\r\n jitterFactor?: number;\r\n\r\n /**\r\n * HTTP status codes considered retryable.\r\n * Errors matching these codes (or containing their string representation)\r\n * will be retried.\r\n * @default [429, 502, 503, 504]\r\n */\r\n retryableStatusCodes?: number[];\r\n}\r\n\r\n/**\r\n * Configuration for a single RPC endpoint in the pool.\r\n *\r\n * @example\r\n * ```ts\r\n * const endpoint: RpcEndpointConfig = {\r\n * url: \"https://mainnet.helius-rpc.com/?api-key=YOUR_KEY\",\r\n * weight: 10,\r\n * label: \"helius-primary\",\r\n * };\r\n * ```\r\n */\r\nexport interface RpcEndpointConfig {\r\n /** RPC endpoint URL. */\r\n url: string;\r\n\r\n /**\r\n * Relative weight for round-robin selection.\r\n * Higher weight = more requests routed here.\r\n * @default 1\r\n */\r\n weight?: number;\r\n\r\n /**\r\n * Human-readable label for logging / diagnostics.\r\n * @default url hostname\r\n */\r\n label?: string;\r\n\r\n /**\r\n * Extra `ConnectionConfig` options (commitment, confirmTransactionInitialTimeout, etc.)\r\n * merged into the Solana `Connection` constructor for this endpoint.\r\n */\r\n connectionConfig?: ConnectionConfig;\r\n}\r\n\r\n/**\r\n * Strategy for selecting the next RPC endpoint from the pool.\r\n *\r\n * - `\"round-robin\"` — weighted round-robin across healthy endpoints.\r\n * - `\"failover\"` — use the first healthy endpoint; only advance on failure.\r\n */\r\nexport type SelectionStrategy = \"round-robin\" | \"failover\";\r\n\r\n/**\r\n * Full configuration for the RPC connection pool.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3, baseDelayMs: 500 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Use like a Connection — same surface\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n * ```\r\n */\r\nexport interface RpcPoolConfig {\r\n /**\r\n * One or more RPC endpoints. At least one is required.\r\n * If a bare `string[]` is passed, each string is treated as `{ url: string }`.\r\n */\r\n endpoints: (RpcEndpointConfig | string)[];\r\n\r\n /**\r\n * How to pick the next endpoint.\r\n * @default \"failover\"\r\n */\r\n strategy?: SelectionStrategy;\r\n\r\n /**\r\n * Retry config applied to every `call()`.\r\n * Set to `false` to disable retries entirely.\r\n * @default { maxRetries: 3, baseDelayMs: 500 }\r\n */\r\n retry?: RetryConfig | false;\r\n\r\n /**\r\n * Per-request timeout in ms. Applies an `AbortSignal` timeout to `Connection`\r\n * calls where supported, and is used as a deadline for the health probe.\r\n * @default 30_000\r\n */\r\n requestTimeoutMs?: number;\r\n\r\n /**\r\n * Default Solana commitment level for connections.\r\n * @default \"confirmed\"\r\n */\r\n commitment?: Commitment;\r\n\r\n /**\r\n * If true, `console.warn` diagnostic messages on retries, failovers, etc.\r\n * @default true\r\n */\r\n verbose?: boolean;\r\n\r\n /**\r\n * Time in ms after which a continuously unhealthy endpoint is automatically\r\n * restored to healthy so it can be retried. Set to 0 to disable time-based\r\n * recovery (the pool will still recover via `maybeRecoverEndpoints` when all\r\n * endpoints are exhausted).\r\n * @default 60_000\r\n */\r\n recoveryAfterMs?: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Health Probe\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Result of an RPC health probe.\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const health = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\");\r\n * console.log(`Slot: ${health.slot}, Latency: ${health.latencyMs}ms`);\r\n * if (!health.healthy) console.warn(`Unhealthy: ${health.error}`);\r\n * ```\r\n */\r\nexport interface RpcHealthResult {\r\n /** The endpoint that was probed. */\r\n endpoint: string;\r\n /** Whether the probe succeeded (getSlot returned without error). */\r\n healthy: boolean;\r\n /** Round-trip latency in milliseconds (0 if unhealthy). */\r\n latencyMs: number;\r\n /** Current slot height (0 if unhealthy). */\r\n slot: number;\r\n /** Error message if the probe failed. */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Probe an RPC endpoint's health by calling `getSlot()` and measuring latency.\r\n *\r\n * @param endpoint - RPC URL to probe\r\n * @param timeoutMs - Timeout in ms for the probe request (default: 5000)\r\n * @returns Health result with latency and slot height\r\n *\r\n * @example\r\n * ```ts\r\n * import { checkRpcHealth } from \"@percolator/sdk\";\r\n *\r\n * const result = await checkRpcHealth(\"https://api.mainnet-beta.solana.com\", 3000);\r\n * if (result.healthy) {\r\n * console.log(`Slot ${result.slot} — ${result.latencyMs}ms`);\r\n * } else {\r\n * console.error(`RPC down: ${result.error}`);\r\n * }\r\n * ```\r\n */\r\nexport async function checkRpcHealth(\r\n endpoint: string,\r\n timeoutMs: number = 5_000,\r\n): Promise {\r\n // #252: probe via a raw JSON-RPC fetch instead of `new Connection(endpoint)`. Each\r\n // Connection instantiates a WebSocket RPC client; creating one per health probe (e.g.\r\n // in a polling loop) accumulated WS clients/sockets → file-descriptor exhaustion. A\r\n // plain fetch holds no persistent resources and is auto-aborted by AbortSignal.timeout.\r\n const start = performance.now();\r\n try {\r\n const res = await fetch(endpoint, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: 1,\r\n method: \"getSlot\",\r\n params: [{ commitment: \"processed\" }],\r\n }),\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n const latencyMs = Math.round(performance.now() - start);\r\n if (!res.ok) {\r\n return { endpoint, healthy: false, latencyMs, slot: 0, error: `HTTP ${res.status}` };\r\n }\r\n const json = (await res.json()) as { result?: unknown; error?: { message?: string } };\r\n if (json?.error || typeof json?.result !== \"number\") {\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: json?.error?.message ?? \"invalid getSlot response\",\r\n };\r\n }\r\n return { endpoint, healthy: true, latencyMs, slot: json.result };\r\n } catch (err) {\r\n const latencyMs = Math.round(performance.now() - start);\r\n return {\r\n endpoint,\r\n healthy: false,\r\n latencyMs,\r\n slot: 0,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved defaults for RetryConfig. */\r\ninterface ResolvedRetryConfig {\r\n maxRetries: number;\r\n baseDelayMs: number;\r\n maxDelayMs: number;\r\n jitterFactor: number;\r\n retryableStatusCodes: number[];\r\n}\r\n\r\nfunction resolveRetryConfig(cfg?: RetryConfig | false): ResolvedRetryConfig | null {\r\n if (cfg === false) return null;\r\n const c = cfg ?? {};\r\n return {\r\n maxRetries: c.maxRetries ?? 3,\r\n baseDelayMs: c.baseDelayMs ?? 500,\r\n maxDelayMs: c.maxDelayMs ?? 10_000,\r\n jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),\r\n retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504],\r\n };\r\n}\r\n\r\nfunction normalizeEndpoint(ep: RpcEndpointConfig | string): RpcEndpointConfig {\r\n if (typeof ep === \"string\") return { url: ep };\r\n return ep;\r\n}\r\n\r\nfunction endpointLabel(ep: RpcEndpointConfig): string {\r\n if (ep.label) return ep.label;\r\n try {\r\n return new URL(ep.url).hostname;\r\n } catch {\r\n return ep.url.slice(0, 40);\r\n }\r\n}\r\n\r\nfunction isRetryable(err: unknown, codes: number[]): boolean {\r\n if (!err) return false;\r\n // #248: a deliberately-aborted request (AbortSignal — caller cancellation OR a timeout\r\n // attached via AbortSignal.timeout) must NOT be retried; retrying ignores the\r\n // cancellation/timeout and can spin into an infinite retry loop. Detect the abort/timeout\r\n // error shapes by name BEFORE any substring match below.\r\n const errName = (err as { name?: unknown })?.name;\r\n if (errName === \"AbortError\" || errName === \"TimeoutError\") return false;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n for (const code of codes) {\r\n const pattern = new RegExp(`(?(ms: number, message: string): { promise: Promise; cancel: () => void } {\r\n let timer: ReturnType;\r\n const promise = new Promise((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(message)), ms);\r\n });\r\n return { promise, cancel: () => clearTimeout(timer!) };\r\n}\r\n\r\n/** Sleep utility. */\r\nfunction sleep(ms: number): Promise {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Redact sensitive query-string parameters (api-key, api_key, token, secret,\r\n * key, password) from a URL so it is safe for logging / status output.\r\n */\r\nfunction redactUrl(raw: string): string {\r\n try {\r\n const u = new URL(raw);\r\n const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;\r\n for (const k of [...u.searchParams.keys()]) {\r\n if (sensitive.test(k)) {\r\n u.searchParams.set(k, \"***\");\r\n }\r\n }\r\n return u.toString();\r\n } catch {\r\n // Not a valid URL — return as-is (unlikely for RPC endpoints).\r\n return raw;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// RpcPool\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-endpoint tracked state. */\r\ninterface EndpointState {\r\n config: RpcEndpointConfig;\r\n connection: Connection;\r\n label: string;\r\n weight: number;\r\n /** Consecutive failure count. Resets on success. */\r\n failures: number;\r\n /** Whether this endpoint is considered healthy. */\r\n healthy: boolean;\r\n /** Last probe latency (ms), -1 if never probed. */\r\n lastLatencyMs: number;\r\n /**\r\n * Timestamp (ms) when the endpoint was first marked unhealthy in this\r\n * failure streak. Cleared on success or manual recovery. Used by the\r\n * time-based auto-recovery logic in `selectEndpoint`.\r\n */\r\n unhealthySince?: number;\r\n}\r\n\r\n/**\r\n * RPC connection pool with retry, failover, and round-robin support.\r\n *\r\n * Wraps one or more Solana RPC endpoints behind a single `call()` interface\r\n * that automatically retries transient errors and fails over to alternate\r\n * endpoints when one goes down.\r\n *\r\n * @example\r\n * ```ts\r\n * import { RpcPool } from \"@percolator/sdk\";\r\n *\r\n * const pool = new RpcPool({\r\n * endpoints: [\r\n * { url: \"https://mainnet.helius-rpc.com/?api-key=KEY\", weight: 10, label: \"helius\" },\r\n * { url: \"https://api.mainnet-beta.solana.com\", weight: 1, label: \"public\" },\r\n * ],\r\n * strategy: \"failover\",\r\n * retry: { maxRetries: 3 },\r\n * requestTimeoutMs: 30_000,\r\n * });\r\n *\r\n * // Execute any Connection method through the pool\r\n * const slot = await pool.call(conn => conn.getSlot());\r\n *\r\n * // Or get a raw connection for one-off use\r\n * const conn = pool.getConnection();\r\n *\r\n * // Health check all endpoints\r\n * const results = await pool.healthCheck();\r\n * ```\r\n */\r\nexport class RpcPool {\r\n private readonly endpoints: EndpointState[];\r\n private readonly strategy: SelectionStrategy;\r\n private readonly retryConfig: ResolvedRetryConfig | null;\r\n private readonly requestTimeoutMs: number;\r\n private readonly verbose: boolean;\r\n /** Time-based recovery window in ms (0 = disabled). */\r\n private readonly recoveryAfterMs: number;\r\n\r\n /** Round-robin index tracker. */\r\n private rrIndex: number = 0;\r\n\r\n /** Consecutive failure threshold before marking an endpoint unhealthy. */\r\n private static readonly UNHEALTHY_THRESHOLD = 3;\r\n\r\n /** Minimum endpoints before auto-recovery is attempted. */\r\n private static readonly MIN_HEALTHY = 1;\r\n\r\n constructor(config: RpcPoolConfig) {\r\n if (!config.endpoints || config.endpoints.length === 0) {\r\n throw new Error(\"RpcPool: at least one endpoint is required\");\r\n }\r\n\r\n this.strategy = config.strategy ?? \"failover\";\r\n this.retryConfig = resolveRetryConfig(config.retry);\r\n this.requestTimeoutMs = config.requestTimeoutMs ?? 30_000;\r\n this.verbose = config.verbose ?? true;\r\n this.recoveryAfterMs = config.recoveryAfterMs ?? 60_000;\r\n\r\n const commitment = config.commitment ?? \"confirmed\";\r\n\r\n this.endpoints = config.endpoints.map(raw => {\r\n const ep = normalizeEndpoint(raw);\r\n const connConfig: ConnectionConfig = {\r\n commitment,\r\n ...ep.connectionConfig,\r\n };\r\n return {\r\n config: ep,\r\n connection: new Connection(ep.url, connConfig),\r\n label: endpointLabel(ep),\r\n weight: Math.max(1, ep.weight ?? 1),\r\n failures: 0,\r\n healthy: true,\r\n lastLatencyMs: -1,\r\n };\r\n });\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Public API\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Execute a function against a pooled connection with automatic retry\r\n * and failover.\r\n *\r\n * @param fn - Async function that receives a `Connection` and returns a result.\r\n * @returns The result of `fn`.\r\n * @throws The last error if all retries and failovers are exhausted.\r\n *\r\n * @example\r\n * ```ts\r\n * const balance = await pool.call(c => c.getBalance(pubkey));\r\n * const markets = await pool.call(c => discoverMarkets(c, programId, opts));\r\n * ```\r\n */\r\n async call(fn: (connection: Connection) => Promise): Promise {\r\n const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;\r\n let lastError: unknown;\r\n\r\n // Track which endpoints we have tried in this call to avoid infinite loops.\r\n const triedEndpoints = new Set();\r\n // Hard cap on total iterations to prevent amplification from attempt-- failovers\r\n const maxTotalIterations = maxAttempts + this.endpoints.length;\r\n let totalIterations = 0;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (++totalIterations > maxTotalIterations) break;\r\n const epIdx = this.selectEndpoint(triedEndpoints);\r\n if (epIdx === -1) {\r\n // All endpoints exhausted\r\n break;\r\n }\r\n const ep = this.endpoints[epIdx];\r\n\r\n const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);\r\n try {\r\n const result = await Promise.race([\r\n fn(ep.connection),\r\n timeout.promise,\r\n ]);\r\n\r\n // Success — reset failure count\r\n ep.failures = 0;\r\n ep.healthy = true;\r\n ep.unhealthySince = undefined;\r\n return result;\r\n } catch (err) {\r\n lastError = err;\r\n ep.failures++;\r\n\r\n if (ep.failures >= RpcPool.UNHEALTHY_THRESHOLD) {\r\n ep.healthy = false;\r\n ep.unhealthySince = ep.unhealthySince ?? Date.now();\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`,\r\n );\r\n }\r\n }\r\n\r\n const retryable = this.retryConfig\r\n ? isRetryable(err, this.retryConfig.retryableStatusCodes)\r\n : false;\r\n\r\n if (!retryable) {\r\n // For non-retryable errors in failover mode, try the next endpoint\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n // Don't count this as a retry attempt — just failover\r\n attempt--;\r\n if (triedEndpoints.size >= this.endpoints.length) break;\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Retryable error\r\n if (this.verbose) {\r\n console.warn(\r\n `[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,\r\n err instanceof Error ? err.message : err,\r\n );\r\n }\r\n\r\n // In failover mode, try next endpoint before retrying same one\r\n if (this.strategy === \"failover\" && this.endpoints.length > 1) {\r\n triedEndpoints.add(epIdx);\r\n }\r\n\r\n // Backoff before retry\r\n if (attempt < maxAttempts - 1 && this.retryConfig) {\r\n const delay = computeDelay(attempt, this.retryConfig);\r\n await sleep(delay);\r\n }\r\n } finally {\r\n timeout.cancel();\r\n }\r\n }\r\n\r\n // All attempts exhausted — try recovery before giving up\r\n this.maybeRecoverEndpoints();\r\n\r\n throw lastError ?? new Error(\"RpcPool: all endpoints exhausted\");\r\n }\r\n\r\n /**\r\n * Get a raw `Connection` from the current preferred endpoint.\r\n * Useful when you need to pass a Connection to external code.\r\n *\r\n * NOTE: This bypasses retry and failover logic. Prefer `call()`.\r\n *\r\n * @returns Solana Connection from the current preferred endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const conn = pool.getConnection();\r\n * const balance = await conn.getBalance(pubkey);\r\n * ```\r\n */\r\n getConnection(): Connection {\r\n const idx = this.selectEndpoint();\r\n if (idx === -1) {\r\n // All marked unhealthy — reset and use first\r\n this.maybeRecoverEndpoints();\r\n return this.endpoints[0].connection;\r\n }\r\n return this.endpoints[idx].connection;\r\n }\r\n\r\n /**\r\n * Run a health check against all endpoints in the pool.\r\n *\r\n * @param timeoutMs - Per-endpoint probe timeout (default: 5000)\r\n * @returns Array of health results, one per endpoint.\r\n *\r\n * @example\r\n * ```ts\r\n * const results = await pool.healthCheck();\r\n * for (const r of results) {\r\n * console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);\r\n * }\r\n * ```\r\n */\r\n async healthCheck(timeoutMs: number = 5_000): Promise {\r\n const results = await Promise.all(\r\n this.endpoints.map(async (ep) => {\r\n const result = await checkRpcHealth(ep.config.url, timeoutMs);\r\n ep.lastLatencyMs = result.latencyMs;\r\n ep.healthy = result.healthy;\r\n if (result.healthy) {\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n result.endpoint = redactUrl(result.endpoint);\r\n return result;\r\n }),\r\n );\r\n return results;\r\n }\r\n\r\n /**\r\n * Get the number of endpoints in the pool.\r\n */\r\n get size(): number {\r\n return this.endpoints.length;\r\n }\r\n\r\n /**\r\n * Get the number of currently healthy endpoints.\r\n */\r\n get healthyCount(): number {\r\n return this.endpoints.filter(ep => ep.healthy).length;\r\n }\r\n\r\n /**\r\n * Get endpoint labels and their current status.\r\n *\r\n * @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.\r\n */\r\n status(): Array<{\r\n label: string;\r\n url: string;\r\n healthy: boolean;\r\n failures: number;\r\n lastLatencyMs: number;\r\n }> {\r\n return this.endpoints.map(ep => ({\r\n label: ep.label,\r\n url: redactUrl(ep.config.url),\r\n healthy: ep.healthy,\r\n failures: ep.failures,\r\n lastLatencyMs: ep.lastLatencyMs,\r\n }));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Internals\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Select the next endpoint based on strategy.\r\n * Returns -1 if no endpoint is available.\r\n */\r\n private selectEndpoint(exclude?: Set): number {\r\n // Time-based auto-recovery: restore endpoints that have been unhealthy\r\n // for longer than recoveryAfterMs so they can be retried.\r\n if (this.recoveryAfterMs > 0) {\r\n const now = Date.now();\r\n for (const ep of this.endpoints) {\r\n if (!ep.healthy && ep.unhealthySince !== undefined && (now - ep.unhealthySince) >= this.recoveryAfterMs) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n if (this.verbose) {\r\n console.warn(`[RpcPool] Endpoint ${ep.label} restored after ${this.recoveryAfterMs}ms recovery window`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthy = this.endpoints\r\n .map((ep, i) => ({ ep, i }))\r\n .filter(({ ep, i }) => ep.healthy && !(exclude?.has(i)));\r\n\r\n if (healthy.length === 0) {\r\n // No healthy endpoints — try all non-excluded\r\n const remaining = this.endpoints\r\n .map((_, i) => i)\r\n .filter(i => !(exclude?.has(i)));\r\n return remaining.length > 0 ? remaining[0] : -1;\r\n }\r\n\r\n if (this.strategy === \"failover\") {\r\n // Return first healthy (by insertion order)\r\n return healthy[0].i;\r\n }\r\n\r\n // Weighted round-robin\r\n const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);\r\n this.rrIndex = (this.rrIndex + 1) % totalWeight;\r\n\r\n let cumulative = 0;\r\n for (const { ep, i } of healthy) {\r\n cumulative += ep.weight;\r\n if (this.rrIndex < cumulative) return i;\r\n }\r\n\r\n return healthy[healthy.length - 1].i;\r\n }\r\n\r\n /**\r\n * If all endpoints are unhealthy, reset them so we at least try again.\r\n */\r\n private maybeRecoverEndpoints(): void {\r\n const healthyCount = this.endpoints.filter(ep => ep.healthy).length;\r\n if (healthyCount < RpcPool.MIN_HEALTHY) {\r\n if (this.verbose) {\r\n console.warn(\"[RpcPool] All endpoints unhealthy — resetting for recovery\");\r\n }\r\n for (const ep of this.endpoints) {\r\n ep.healthy = true;\r\n ep.failures = 0;\r\n ep.unhealthySince = undefined;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone retry wrapper (for use without a full pool)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute an async function with exponential-backoff retry.\r\n *\r\n * Use this when you already have a `Connection` and just want retry logic\r\n * without a full pool.\r\n *\r\n * @param fn - Async function to execute\r\n * @param config - Retry configuration (default: 3 retries, 500ms base delay)\r\n * @returns Result of `fn`\r\n * @throws The last error if all retries are exhausted\r\n *\r\n * @example\r\n * ```ts\r\n * import { withRetry } from \"@percolator/sdk\";\r\n * import { Connection } from \"@solana/web3.js\";\r\n *\r\n * const conn = new Connection(\"https://api.mainnet-beta.solana.com\");\r\n * const slot = await withRetry(\r\n * () => conn.getSlot(),\r\n * { maxRetries: 3, baseDelayMs: 1000 },\r\n * );\r\n * ```\r\n */\r\nexport async function withRetry(\r\n fn: () => Promise,\r\n config?: RetryConfig,\r\n): Promise {\r\n const resolved = resolveRetryConfig(config) ?? {\r\n maxRetries: 3,\r\n baseDelayMs: 500,\r\n maxDelayMs: 10_000,\r\n jitterFactor: 0.25,\r\n retryableStatusCodes: [429, 502, 503, 504],\r\n };\r\n\r\n let lastError: unknown;\r\n const maxAttempts = resolved.maxRetries + 1;\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (err) {\r\n lastError = err;\r\n\r\n if (!isRetryable(err, resolved.retryableStatusCodes)) {\r\n throw err;\r\n }\r\n\r\n if (attempt < maxAttempts - 1) {\r\n const delay = computeDelay(attempt, resolved);\r\n await sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(\"withRetry: all attempts exhausted\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-export helpers for testing\r\n// ---------------------------------------------------------------------------\r\n\r\n/** @internal — exposed for unit tests only */\r\nexport const _internal = {\r\n isRetryable,\r\n computeDelay,\r\n resolveRetryConfig,\r\n normalizeEndpoint,\r\n endpointLabel,\r\n} as const;\r\n","import {\r\n Connection,\r\n PublicKey,\r\n TransactionInstruction,\r\n Transaction,\r\n Keypair,\r\n SendOptions,\r\n Commitment,\r\n AccountMeta,\r\n ComputeBudgetProgram,\r\n} from \"@solana/web3.js\";\r\nimport { parseErrorFromLogs } from \"../abi/errors.js\";\r\n\r\n/**\r\n * Rank of the three cluster confirmation levels the RPC reports in\r\n * `SignatureStatus.confirmationStatus`.\r\n */\r\nconst CONFIRMATION_RANK = {\r\n processed: 0,\r\n confirmed: 1,\r\n finalized: 2,\r\n} as const;\r\n\r\n/**\r\n * Minimum `confirmationStatus` rank that satisfies a requested `Commitment`.\r\n * The deprecated aliases map onto their modern equivalents exactly as\r\n * @solana/web3.js does: single/singleGossip -> confirmed, max/root -> finalized,\r\n * recent -> processed.\r\n */\r\nfunction requiredConfirmationRank(commitment: Commitment): number {\r\n // Grouping copied from @solana/web3.js itself, NOT guessed. Its confirmation\r\n // switch (lib/index.cjs.js:6602-6614 and :6799-6812) buckets the deprecated\r\n // aliases as:\r\n // 'confirmed' | 'single' | 'singleGossip' -> requires >= confirmed\r\n // 'finalized' | 'max' | 'root' -> requires finalized\r\n // everything else ('processed', 'recent') -> requires >= processed\r\n // An earlier revision put `single`/`singleGossip` in the processed bucket, which\r\n // meant a caller asking for `singleGossip` and observing only a `processed`\r\n // status was told the transaction had SETTLED — reintroducing exactly the\r\n // premature-settlement bug this function exists to prevent.\r\n switch (commitment) {\r\n case \"confirmed\":\r\n case \"single\":\r\n case \"singleGossip\":\r\n return CONFIRMATION_RANK.confirmed;\r\n case \"finalized\":\r\n case \"max\":\r\n case \"root\":\r\n return CONFIRMATION_RANK.finalized;\r\n case \"processed\":\r\n case \"recent\":\r\n default:\r\n return CONFIRMATION_RANK.processed;\r\n }\r\n}\r\n\r\n/**\r\n * True when an observed signature status is at least as strong as the level the\r\n * caller asked for. A merely \"processed\" transaction can still be dropped or\r\n * rolled back, so treating it as settled would reintroduce exactly the premature\r\n * -settlement bug that #311 fixed by defaulting sends to \"finalized\".\r\n */\r\nfunction meetsCommitment(\r\n observed: keyof typeof CONFIRMATION_RANK | undefined | null,\r\n required: Commitment\r\n): boolean {\r\n if (!observed) return false;\r\n return CONFIRMATION_RANK[observed] >= requiredConfirmationRank(required);\r\n}\r\n\r\nexport interface BuildIxParams {\r\n programId: PublicKey;\r\n keys: AccountMeta[];\r\n data: Uint8Array | Buffer;\r\n}\r\n\r\n/**\r\n * Build a transaction instruction.\r\n */\r\nexport function buildIx(params: BuildIxParams): TransactionInstruction {\r\n return new TransactionInstruction({\r\n programId: params.programId,\r\n keys: params.keys,\r\n // TransactionInstruction types expect Buffer, but Uint8Array works at runtime.\r\n // Cast to avoid Buffer polyfill issues in the browser.\r\n data: params.data as Buffer,\r\n });\r\n}\r\n\r\nexport interface TxResult {\r\n signature: string;\r\n slot: number;\r\n err: string | null;\r\n hint?: string;\r\n logs: string[];\r\n unitsConsumed?: number;\r\n}\r\n\r\nexport interface SimulateOrSendParams {\r\n connection: Connection;\r\n ix: TransactionInstruction;\r\n signers: Keypair[];\r\n simulate: boolean;\r\n commitment?: Commitment;\r\n computeUnitLimit?: number; // Custom compute unit limit (default: 200,000, max: 1,400,000)\r\n /**\r\n * Heap frame to request, in bytes (Compute Budget). The v17 wrapper installs a 128 KB\r\n * BumpAllocator and makes its FIRST heap allocation near heap_base+128KB on every\r\n * instruction, so EVERY transaction touching the wrapper MUST request a 128 KB heap frame\r\n * or it aborts on-chain with ProgramFailedToComplete / \"Access violation in heap section\"\r\n * (#176). Defaults to 128 KB so wrapper txs work out of the box; pass 0 to omit. Must be a\r\n * multiple of 1024 in [32768, 262144].\r\n */\r\n heapFrameBytes?: number;\r\n}\r\n\r\n/**\r\n * Simulate or send a transaction.\r\n * Returns consistent output for both modes.\r\n */\r\n/** Solana per-transaction compute unit ceiling (Compute Budget program). */\r\nconst MAX_COMPUTE_UNIT_LIMIT = 1_400_000;\r\n\r\n/**\r\n * The v17 wrapper's installed heap-frame size. EVERY transaction that touches the wrapper\r\n * MUST request this much heap or it aborts on-chain (#176). Default for `heapFrameBytes`.\r\n */\r\nexport const V17_WRAPPER_HEAP_FRAME_BYTES = 128 * 1024;\r\n/** Compute Budget heap-frame bounds: [32 KB, 256 KB], must be a multiple of 1024. */\r\nconst MIN_HEAP_FRAME_BYTES = 32 * 1024;\r\nconst MAX_HEAP_FRAME_BYTES = 256 * 1024;\r\n\r\nexport async function simulateOrSend(\r\n params: SimulateOrSendParams\r\n): Promise {\r\n const {\r\n connection,\r\n ix,\r\n signers,\r\n simulate,\r\n commitment,\r\n computeUnitLimit,\r\n heapFrameBytes = V17_WRAPPER_HEAP_FRAME_BYTES,\r\n } = params;\r\n // #311: default actual sends to \"finalized\" so callers don't treat a \"confirmed\" (but not\r\n // yet finalized) transaction as settled — a reorg within the ~13s finalization window can\r\n // reverse it. Simulation-only calls keep \"confirmed\" (no on-chain state mutated).\r\n const effectiveCommitment = commitment ?? (simulate ? \"confirmed\" : \"finalized\");\r\n\r\n if (typeof simulate !== \"boolean\") {\r\n throw new Error(\"simulateOrSend: simulate must be explicitly set to true or false\");\r\n }\r\n\r\n if (!signers.length) {\r\n throw new Error(\"simulateOrSend: at least one signer is required\");\r\n }\r\n\r\n if (computeUnitLimit !== undefined) {\r\n if (\r\n typeof computeUnitLimit !== \"number\" ||\r\n !Number.isInteger(computeUnitLimit) ||\r\n computeUnitLimit < 1 ||\r\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT\r\n ) {\r\n throw new Error(\r\n `computeUnitLimit must be an integer in [1, ${MAX_COMPUTE_UNIT_LIMIT}]`,\r\n );\r\n }\r\n }\r\n\r\n if (heapFrameBytes !== 0) {\r\n if (\r\n typeof heapFrameBytes !== \"number\" ||\r\n !Number.isInteger(heapFrameBytes) ||\r\n heapFrameBytes % 1024 !== 0 ||\r\n heapFrameBytes < MIN_HEAP_FRAME_BYTES ||\r\n heapFrameBytes > MAX_HEAP_FRAME_BYTES\r\n ) {\r\n throw new Error(\r\n `heapFrameBytes must be 0 or a multiple of 1024 in [${MIN_HEAP_FRAME_BYTES}, ${MAX_HEAP_FRAME_BYTES}]`,\r\n );\r\n }\r\n }\r\n\r\n const tx = new Transaction();\r\n\r\n // #176: the v17 wrapper needs a 128 KB heap frame on every tx (its BumpAllocator's first\r\n // allocation lands near heap_base+128KB). Request it by default so wrapper calls don't\r\n // abort on-chain; callers send `heapFrameBytes: 0` to opt out for non-wrapper txs.\r\n if (heapFrameBytes !== 0) {\r\n tx.add(ComputeBudgetProgram.requestHeapFrame({ bytes: heapFrameBytes }));\r\n }\r\n\r\n // Add compute budget instruction if custom limit is specified\r\n if (computeUnitLimit !== undefined) {\r\n tx.add(\r\n ComputeBudgetProgram.setComputeUnitLimit({\r\n units: computeUnitLimit,\r\n })\r\n );\r\n }\r\n\r\n tx.add(ix);\r\n const latestBlockhash = await connection.getLatestBlockhash(effectiveCommitment);\r\n tx.recentBlockhash = latestBlockhash.blockhash;\r\n tx.feePayer = signers[0].publicKey;\r\n\r\n if (simulate) {\r\n try {\r\n tx.sign(...signers);\r\n const result = await connection.simulateTransaction(tx, signers);\r\n const logs = result.value.logs ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (result.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(result.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature: \"(simulated)\",\r\n slot: result.context.slot,\r\n err,\r\n hint,\r\n logs,\r\n unitsConsumed: result.value.unitsConsumed ?? undefined,\r\n };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"(simulated)\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n }\r\n\r\n // Send\r\n const options: SendOptions = {\r\n skipPreflight: false,\r\n preflightCommitment: effectiveCommitment,\r\n };\r\n\r\n // sendTransaction is its own try/catch: only here is it true that no\r\n // signature was ever produced, so signature: \"\" is the correct result.\r\n let signature: string;\r\n try {\r\n signature = await connection.sendTransaction(tx, signers, options);\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n return {\r\n signature: \"\",\r\n slot: 0,\r\n err: message,\r\n logs: [],\r\n };\r\n }\r\n\r\n // Fetch logs at the same finality level used for confirmation.\r\n // getTransaction only accepts Finality (\"confirmed\" | \"finalized\"); map anything\r\n // weaker than \"finalized\" to \"confirmed\" — the safest valid fallback.\r\n const txFinality = effectiveCommitment === \"finalized\" ? \"finalized\" : \"confirmed\";\r\n\r\n try {\r\n const confirmation = await connection.confirmTransaction(\r\n {\r\n signature,\r\n blockhash: latestBlockhash.blockhash,\r\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\r\n },\r\n effectiveCommitment\r\n );\r\n\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n\r\n if (confirmation.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(confirmation.value.err);\r\n }\r\n }\r\n\r\n return {\r\n signature,\r\n slot: txInfo?.slot ?? 0,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n } catch (e: unknown) {\r\n // confirmTransaction/getTransaction threw (e.g. TransactionExpiredBlockheightExceededError\r\n // on an ordinary RPC timeout) — this does NOT mean the transaction failed to land,\r\n // only that we didn't observe confirmation in time. Previously this branch discarded\r\n // the real signature obtained above and returned signature: \"\", which left the caller\r\n // with no way to check whether it's safe to retry — for a non-idempotent operation\r\n // (deposit/withdraw/trade) a naive retry-on-error could then double-submit a\r\n // transaction that had actually already landed. Check the real on-chain status before\r\n // reporting failure, and always return the real signature so the caller can verify\r\n // it themselves even if this fallback check also fails.\r\n const message = e instanceof Error ? e.message : String(e);\r\n try {\r\n const status = await connection.getSignatureStatus(signature, {\r\n searchTransactionHistory: true,\r\n });\r\n // Only treat the fallback lookup as authoritative when the observed level\r\n // actually satisfies the commitment the caller asked for. `status.value`\r\n // being non-null merely means the cluster has SEEN the transaction — at\r\n // \"processed\" it can still be dropped or rolled back, and reporting that\r\n // as a settled success would be the same premature-settlement bug #311 fixed.\r\n if (status.value && meetsCommitment(status.value.confirmationStatus, effectiveCommitment)) {\r\n const txInfo = await connection.getTransaction(signature, {\r\n commitment: txFinality,\r\n maxSupportedTransactionVersion: 0,\r\n });\r\n const logs = txInfo?.meta?.logMessages ?? [];\r\n let err: string | null = null;\r\n let hint: string | undefined;\r\n if (status.value.err) {\r\n const parsed = parseErrorFromLogs(logs);\r\n if (parsed) {\r\n err = `${parsed.name} (0x${parsed.code.toString(16)})`;\r\n hint = parsed.hint;\r\n } else {\r\n err = JSON.stringify(status.value.err);\r\n }\r\n }\r\n return {\r\n signature,\r\n // `SignatureStatus.slot` is the slot the transaction was PROCESSED in.\r\n // `status.context.slot` is the RPC's head slot at query time — a\r\n // different, much later number — so it must not be used as the tx slot.\r\n slot: txInfo?.slot ?? status.value.slot,\r\n err,\r\n hint,\r\n logs,\r\n };\r\n }\r\n if (status.value) {\r\n // Seen, but weaker than requested. Report it as unresolved rather than\r\n // settled, while still handing back the signature and the real landing slot.\r\n const observed = status.value.confirmationStatus ?? \"unknown\";\r\n return {\r\n signature,\r\n slot: status.value.slot,\r\n err:\r\n `confirmation status unknown (${message}) — transaction is only \"${observed}\" ` +\r\n `but \"${effectiveCommitment}\" was required; it may still be dropped or may settle. ` +\r\n `Check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n } catch {\r\n // Status lookup itself failed too — fall through to the ambiguous result below,\r\n // which still carries the real signature instead of discarding it.\r\n }\r\n return {\r\n signature,\r\n slot: 0,\r\n err: `confirmation status unknown (${message}) — the transaction may have already landed; check signature ${signature} before retrying`,\r\n logs: [],\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Format transaction result for output.\r\n */\r\nexport function formatResult(result: TxResult, jsonMode: boolean): string {\r\n if (jsonMode) {\r\n return JSON.stringify(result, null, 2);\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n if (result.err) {\r\n lines.push(`Error: ${result.err}`);\r\n if (result.hint) {\r\n lines.push(`Hint: ${result.hint}`);\r\n }\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.logs.length > 0) {\r\n lines.push(\"Logs:\");\r\n result.logs.forEach((log) => lines.push(` ${log}`));\r\n }\r\n } else {\r\n lines.push(`Signature: ${result.signature}`);\r\n lines.push(`Slot: ${result.slot}`);\r\n if (result.unitsConsumed !== undefined) {\r\n lines.push(`Compute Units: ${result.unitsConsumed.toLocaleString()}`);\r\n }\r\n if (result.signature !== \"(simulated)\") {\r\n lines.push(`Explorer: https://explorer.solana.com/tx/${result.signature}`);\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","/**\r\n * @module lighthouse\r\n * Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.\r\n *\r\n * Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based\r\n * wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction\r\n * scanning service. It adds assertion instructions to transactions that verify account\r\n * state expectations (e.g., \"this account should be empty\" or \"this account should have\r\n * X lamports\").\r\n *\r\n * **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab\r\n * (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects\r\n * an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).\r\n * The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress\r\n * = 6400 decimal). This causes the transaction to revert even though the Percolator program\r\n * logic is correct.\r\n *\r\n * **Solution:** The SDK provides utilities to:\r\n * 1. Detect Lighthouse instructions in a transaction\r\n * 2. Strip them before sending\r\n * 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors\r\n * 4. Provide clear, actionable error messages for end users\r\n *\r\n * @example\r\n * ```ts\r\n * import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from \"@percolator/sdk\";\r\n *\r\n * // Before sending: strip injected Lighthouse IXs\r\n * const cleanIxs = stripLighthouseInstructions(instructions);\r\n *\r\n * // After error: classify and give user-friendly message\r\n * if (isLighthouseError(error)) {\r\n * console.warn(\"Wallet middleware blocked the transaction\");\r\n * }\r\n * ```\r\n */\r\n\r\nimport { PublicKey, TransactionInstruction, Transaction } from \"@solana/web3.js\";\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/**\r\n * Lighthouse v2 program ID (Blowfish/Phantom wallet guard).\r\n *\r\n * This is an immutable Anchor program deployed at slot 294,179,293.\r\n * Wallets like Phantom inject instructions from this program into user\r\n * transactions to enforce Blowfish security assertions.\r\n */\r\nexport const LIGHTHOUSE_PROGRAM_ID = new PublicKey(\r\n \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\",\r\n);\r\n\r\n/** Base58 string form for fast comparison without PublicKey instantiation. */\r\nexport const LIGHTHOUSE_PROGRAM_ID_STR = \"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95\";\r\n\r\n/**\r\n * Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).\r\n * This is NOT a Percolator error — it comes from Lighthouse's Anchor framework\r\n * when an account constraint check fails.\r\n */\r\nexport const LIGHTHOUSE_CONSTRAINT_ADDRESS = 0x1900;\r\n\r\n/**\r\n * Known Lighthouse/Anchor error codes that may appear in transaction logs.\r\n * All are in the Anchor error range (0x1770–0x1900+).\r\n */\r\nexport const LIGHTHOUSE_ERROR_CODES = new Set([\r\n 0x1770, // InstructionMissing\r\n 0x1771, // InstructionFallbackNotFound\r\n 0x1772, // InstructionDidNotDeserialize\r\n 0x1773, // InstructionDidNotSerialize\r\n 0x1780, // IdlInstructionStub\r\n 0x1790, // ConstraintMut\r\n 0x1791, // ConstraintHasOne\r\n 0x1792, // ConstraintSigner\r\n 0x1793, // ConstraintRaw\r\n 0x1794, // ConstraintOwner\r\n 0x1795, // ConstraintRentExempt\r\n 0x1796, // ConstraintSeeds\r\n 0x1797, // ConstraintExecutable\r\n 0x1798, // ConstraintState\r\n 0x1799, // ConstraintAssociated\r\n 0x179a, // ConstraintAssociatedInit\r\n 0x179b, // ConstraintClose\r\n 0x1900, // ConstraintAddress (the one we hit most often)\r\n] as const);\r\n\r\n// ============================================================================\r\n// Detection\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a TransactionInstruction is from the Lighthouse program.\r\n *\r\n * @param ix - A Solana transaction instruction.\r\n * @returns `true` if the instruction's programId is Lighthouse.\r\n *\r\n * @example\r\n * ```ts\r\n * const hasLighthouse = instructions.some(isLighthouseInstruction);\r\n * ```\r\n */\r\nexport function isLighthouseInstruction(ix: TransactionInstruction): boolean {\r\n return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);\r\n}\r\n\r\n/**\r\n * Check if an error message or error object indicates a Lighthouse assertion failure.\r\n *\r\n * Detects:\r\n * - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)\r\n * - References to the Lighthouse program ID in error text\r\n * - `\"Custom\": 6400` in JSON-encoded InstructionError\r\n * - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the\r\n * failing program is Lighthouse (identified by program ID in logs)\r\n *\r\n * @param error - An Error object, error message string, or transaction logs array.\r\n * @returns `true` if the error appears to originate from Lighthouse, not Percolator.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await sendTransaction(tx);\r\n * } catch (e) {\r\n * if (isLighthouseError(e)) {\r\n * // Retry with skipPreflight or notify user about wallet middleware\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isLighthouseError(error: unknown): boolean {\r\n const msg = extractErrorMessage(error);\r\n if (!msg) return false;\r\n\r\n // Direct program ID reference\r\n if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR)) return true;\r\n\r\n // 0x1900 hex error code (case-insensitive)\r\n if (/custom\\s+program\\s+error:\\s*0x1900\\b/i.test(msg)) return true;\r\n\r\n // JSON InstructionError format: {\"Custom\": 6400}\r\n if (/\"Custom\"\\s*:\\s*6400\\b/.test(msg) && /InstructionError/i.test(msg)) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if transaction logs contain evidence of a Lighthouse failure.\r\n *\r\n * More precise than `isLighthouseError` on a string — examines the program\r\n * invocation chain to confirm the error originates from Lighthouse, not from\r\n * a Percolator instruction that happens to return a similar code.\r\n *\r\n * @param logs - Array of transaction log lines from `getTransaction()`.\r\n * @returns `true` if logs show a Lighthouse program failure.\r\n */\r\nexport function isLighthouseFailureInLogs(logs: string[]): boolean {\r\n if (!Array.isArray(logs)) return false;\r\n\r\n let lighthouseDepth = 0;\r\n\r\n for (const line of logs) {\r\n if (typeof line !== \"string\") continue;\r\n\r\n // Track Lighthouse program invocation depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} invoke`)) {\r\n lighthouseDepth++;\r\n continue;\r\n }\r\n\r\n // Lighthouse program returned success — decrement depth\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} success`)) {\r\n if (lighthouseDepth > 0) lighthouseDepth--;\r\n continue;\r\n }\r\n\r\n // Only report failure when the Lighthouse program itself explicitly fails\r\n if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR} failed`)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n}\r\n\r\n// ============================================================================\r\n// Stripping / Mitigation\r\n// ============================================================================\r\n\r\n/**\r\n * Remove all Lighthouse assertion instructions from an instruction array.\r\n *\r\n * Call this before building a Transaction to prevent Lighthouse assertion\r\n * failures. Safe to call even if no Lighthouse instructions are present.\r\n *\r\n * @param instructions - Array of transaction instructions.\r\n * @returns Filtered array with Lighthouse instructions removed.\r\n *\r\n * @example\r\n * ```ts\r\n * import { stripLighthouseInstructions } from \"@percolator/sdk\";\r\n *\r\n * const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in\r\n * const clean = stripLighthouseInstructions(instructions);\r\n * const tx = new Transaction().add(...clean);\r\n * ```\r\n */\r\nexport function stripLighthouseInstructions(\r\n instructions: TransactionInstruction[],\r\n percolatorProgramId?: PublicKey,\r\n): TransactionInstruction[] {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions — prevents misuse on\r\n // arbitrary transactions where Lighthouse guards are legitimate protection.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) {\r\n return instructions; // no Percolator instructions — leave guards intact\r\n }\r\n }\r\n return instructions.filter((ix) => !isLighthouseInstruction(ix));\r\n}\r\n\r\n/**\r\n * Strip Lighthouse instructions from an already-built Transaction.\r\n *\r\n * Creates a new Transaction with the same recentBlockhash and feePayer\r\n * but without any Lighthouse instructions. The returned transaction is\r\n * unsigned and must be re-signed.\r\n *\r\n * @param transaction - A Transaction (signed or unsigned).\r\n * @returns A new Transaction without Lighthouse instructions, or the same\r\n * transaction if no Lighthouse instructions were found.\r\n *\r\n * @example\r\n * ```ts\r\n * const signed = await wallet.signTransaction(tx);\r\n * if (hasLighthouseInstructions(signed)) {\r\n * const clean = stripLighthouseFromTransaction(signed);\r\n * const reSigned = await wallet.signTransaction(clean);\r\n * await connection.sendRawTransaction(reSigned.serialize());\r\n * }\r\n * ```\r\n */\r\nexport function stripLighthouseFromTransaction(\r\n transaction: Transaction,\r\n percolatorProgramId?: PublicKey,\r\n): Transaction {\r\n // When a programId is provided, refuse to strip guards from transactions\r\n // that don't contain any Percolator instructions.\r\n if (percolatorProgramId) {\r\n const hasPercolatorIx = transaction.instructions.some(\r\n (ix) => ix.programId.equals(percolatorProgramId),\r\n );\r\n if (!hasPercolatorIx) return transaction;\r\n }\r\n\r\n const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);\r\n if (!hasLighthouse) return transaction;\r\n\r\n const clean = new Transaction();\r\n clean.recentBlockhash = transaction.recentBlockhash;\r\n clean.feePayer = transaction.feePayer;\r\n\r\n for (const ix of transaction.instructions) {\r\n if (!isLighthouseInstruction(ix)) {\r\n clean.add(ix);\r\n }\r\n }\r\n\r\n return clean;\r\n}\r\n\r\n/**\r\n * Count Lighthouse instructions in an instruction array or transaction.\r\n *\r\n * @param ixsOrTx - Array of instructions or a Transaction.\r\n * @returns Number of Lighthouse instructions found.\r\n */\r\nexport function countLighthouseInstructions(\r\n ixsOrTx: TransactionInstruction[] | Transaction,\r\n): number {\r\n const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;\r\n return instructions.filter(isLighthouseInstruction).length;\r\n}\r\n\r\n// ============================================================================\r\n// User-facing error messages\r\n// ============================================================================\r\n\r\n/**\r\n * User-friendly error message for Lighthouse assertion failures.\r\n *\r\n * Suitable for display in UI toast/modal when `isLighthouseError()` returns true.\r\n */\r\nexport const LIGHTHOUSE_USER_MESSAGE =\r\n \"Your wallet's transaction guard (Blowfish/Lighthouse) is blocking this transaction. \" +\r\n \"This is a known compatibility issue — the transaction itself is valid. \" +\r\n \"Try one of these workarounds:\\n\" +\r\n \"1. Disable transaction simulation in your wallet settings\\n\" +\r\n \"2. Use a wallet without Blowfish protection (e.g., Backpack, Solflare)\\n\" +\r\n \"3. The SDK will automatically retry without the guard\";\r\n\r\n/**\r\n * Classify an error and return an appropriate user-facing message.\r\n *\r\n * If the error is from Lighthouse, returns the Lighthouse-specific message.\r\n * Otherwise returns `null` (callers should use their own error display).\r\n *\r\n * @param error - An Error, string, or logs array.\r\n * @returns User-facing message string, or `null` if not a Lighthouse error.\r\n */\r\nexport function classifyLighthouseError(error: unknown): string | null {\r\n if (isLighthouseError(error)) {\r\n return LIGHTHOUSE_USER_MESSAGE;\r\n }\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Internal helpers\r\n// ============================================================================\r\n\r\nfunction extractErrorMessage(error: unknown): string | null {\r\n if (!error) return null;\r\n if (typeof error === \"string\") return error;\r\n if (error instanceof Error) return error.message;\r\n if (typeof error === \"object\" && \"message\" in error) {\r\n return String((error as { message: unknown }).message);\r\n }\r\n try {\r\n return JSON.stringify(error);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Coin-margined perpetual trade math utilities.\r\n *\r\n * On-chain PnL formula:\r\n * mark_pnl = (oracle - entry) * abs_pos / oracle (longs)\r\n * mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)\r\n *\r\n * All prices are in e6 format (1 USD = 1_000_000).\r\n * All token amounts are in native units (e.g. lamports).\r\n */\r\n\r\n/**\r\n * Compute mark-to-market PnL for an open position.\r\n */\r\nexport function computeMarkPnl(\r\n positionSize: bigint,\r\n entryPrice: bigint,\r\n oraclePrice: bigint,\r\n): bigint {\r\n if (positionSize === 0n || oraclePrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n const diff =\r\n positionSize > 0n\r\n ? oraclePrice - entryPrice\r\n : entryPrice - oraclePrice;\r\n return (diff * absPos) / oraclePrice;\r\n}\r\n\r\n/**\r\n * Compute liquidation price given entry, capital, position and maintenance margin.\r\n * Uses pure BigInt arithmetic for precision (no Number() truncation).\r\n */\r\nexport function computeLiqPrice(\r\n entryPrice: bigint,\r\n capital: bigint,\r\n positionSize: bigint,\r\n maintenanceMarginBps: bigint,\r\n): bigint {\r\n if (positionSize === 0n || entryPrice === 0n) return 0n;\r\n const absPos = positionSize < 0n ? -positionSize : positionSize;\r\n // capitalPerUnit scaled by 1e6 for precision\r\n const capitalPerUnitE6 = (capital * 1_000_000n) / absPos;\r\n\r\n if (positionSize > 0n) {\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n + maintenanceMarginBps);\r\n const liq = entryPrice - adjusted;\r\n return liq > 0n ? liq : 0n;\r\n } else {\r\n // Guard: short positions liquidate when price rises above liq price.\r\n // With >= 100% maintenance margin the denominator (10000 - maint) would be <= 0,\r\n // meaning the position can never be liquidated. Return max u64 to signal this.\r\n if (maintenanceMarginBps >= 10000n) return 18446744073709551615n; // max u64 — unliquidatable\r\n const adjusted = (capitalPerUnitE6 * 10000n) / (10000n - maintenanceMarginBps);\r\n return entryPrice + adjusted;\r\n }\r\n}\r\n\r\n/**\r\n * Compute estimated liquidation price BEFORE opening a trade.\r\n * Accounts for trading fees reducing effective capital.\r\n */\r\nexport function computePreTradeLiqPrice(\r\n oracleE6: bigint,\r\n margin: bigint,\r\n posSize: bigint,\r\n maintBps: bigint,\r\n feeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n || margin === 0n || posSize === 0n) return 0n;\r\n const absPos = posSize < 0n ? -posSize : posSize;\r\n const signedPos = direction === \"long\" ? absPos : -absPos;\r\n // Fee adjusts the effective entry price, not the capital.\r\n // For longs: you pay more (oracle + fee) → worse entry → closer liquidation.\r\n // For shorts: you receive less (oracle - fee) → worse entry → closer liquidation.\r\n const feeAdjust = (oracleE6 * feeBps) / 10000n;\r\n let adjustedEntry: bigint;\r\n if (direction === \"long\") {\r\n adjustedEntry = oracleE6 + feeAdjust;\r\n } else {\r\n // Clamp short entry to 1n — a zero or negative entry price is nonsensical\r\n // and causes computeLiqPrice to return 0n (\"no liquidation risk\") when\r\n // feeBps >= 10000, misleading the UI into showing the position is safe.\r\n const shortEntry = oracleE6 - feeAdjust;\r\n adjustedEntry = shortEntry > 0n ? shortEntry : 1n;\r\n }\r\n return computeLiqPrice(adjustedEntry, margin, signedPos, maintBps);\r\n}\r\n\r\n/**\r\n * Compute trading fee from notional value and fee rate in bps.\r\n */\r\nexport function computeTradingFee(\r\n notional: bigint,\r\n tradingFeeBps: bigint,\r\n): bigint {\r\n return (notional * tradingFeeBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Dynamic fee tier configuration.\r\n */\r\nexport interface FeeTierConfig {\r\n /** Base trading fee (Tier 1) in bps */\r\n baseBps: bigint;\r\n /** Tier 2 fee in bps (0 = disabled) */\r\n tier2Bps: bigint;\r\n /** Tier 3 fee in bps (0 = disabled) */\r\n tier3Bps: bigint;\r\n /** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */\r\n tier2Threshold: bigint;\r\n /** Notional threshold to enter Tier 3 */\r\n tier3Threshold: bigint;\r\n}\r\n\r\n/**\r\n * Compute the effective fee rate in bps using the tiered fee schedule.\r\n *\r\n * Mirrors on-chain `compute_dynamic_fee_bps` logic:\r\n * - notional < tier2Threshold → baseBps (Tier 1)\r\n * - notional < tier3Threshold → tier2Bps (Tier 2)\r\n * - notional >= tier3Threshold → tier3Bps (Tier 3)\r\n *\r\n * If tier2Threshold == 0, tiered fees are disabled (flat baseBps).\r\n */\r\nexport function computeDynamicFeeBps(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n if (config.tier2Threshold === 0n) return config.baseBps;\r\n if (config.tier3Threshold > 0n && notional >= config.tier3Threshold) return config.tier3Bps;\r\n if (notional >= config.tier2Threshold) return config.tier2Bps;\r\n return config.baseBps;\r\n}\r\n\r\n/**\r\n * Compute the dynamic trading fee for a given notional and tier config.\r\n *\r\n * Uses ceiling division to match on-chain behavior (prevents fee evasion\r\n * via micro-trades).\r\n */\r\nexport function computeDynamicTradingFee(\r\n notional: bigint,\r\n config: FeeTierConfig,\r\n): bigint {\r\n const feeBps = computeDynamicFeeBps(notional, config);\r\n if (notional <= 0n || feeBps <= 0n) return 0n;\r\n return (notional * feeBps + 9999n) / 10000n;\r\n}\r\n\r\n/**\r\n * Fee split configuration.\r\n */\r\nexport interface FeeSplitConfig {\r\n /** LP vault share in bps (0–10_000) */\r\n lpBps: bigint;\r\n /** Protocol treasury share in bps */\r\n protocolBps: bigint;\r\n /** Market creator share in bps */\r\n creatorBps: bigint;\r\n}\r\n\r\n/**\r\n * Compute fee split for a total fee amount.\r\n *\r\n * Returns [lpShare, protocolShare, creatorShare].\r\n * If all split params are 0, 100% goes to LP (legacy behavior).\r\n * Creator gets the rounding remainder to ensure total is preserved.\r\n */\r\nexport function computeFeeSplit(\r\n totalFee: bigint,\r\n config: FeeSplitConfig,\r\n): [bigint, bigint, bigint] {\r\n if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {\r\n return [totalFee, 0n, 0n];\r\n }\r\n const totalBps = config.lpBps + config.protocolBps + config.creatorBps;\r\n if (config.lpBps < 0n || config.protocolBps < 0n || config.creatorBps < 0n) {\r\n throw new Error(\"computeFeeSplit: bps values must be non-negative\");\r\n }\r\n if (totalBps !== 10000n) {\r\n throw new Error(`computeFeeSplit: bps values must sum to 10000, got ${totalBps}`);\r\n }\r\n\r\n const lp = (totalFee * config.lpBps) / 10000n;\r\n const protocol = (totalFee * config.protocolBps) / 10000n;\r\n const creator = totalFee - lp - protocol;\r\n return [lp, protocol, creator];\r\n}\r\n\r\n/**\r\n * Compute PnL as a percentage of capital.\r\n *\r\n * Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.\r\n * Number(bigint) silently truncates values above 2^53, which can produce\r\n * incorrect percentages for large positions (e.g., tokens with 9 decimals\r\n * where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).\r\n */\r\nexport function computePnlPercent(\r\n pnlTokens: bigint,\r\n capital: bigint,\r\n): number {\r\n if (capital === 0n) return 0;\r\n const scaledPct = (pnlTokens * 10_000n) / capital;\r\n // Clamp rather than throw: values outside MAX_SAFE_INTEGER represent effectively\r\n // infinite gain/loss for display purposes; returning a clamped sentinel prevents\r\n // unhandled exceptions from crashing the UI on large positions.\r\n const MAX_DISPLAY = BigInt(Number.MAX_SAFE_INTEGER);\r\n if (scaledPct > MAX_DISPLAY) return Number.MAX_SAFE_INTEGER / 100;\r\n if (scaledPct < -MAX_DISPLAY) return -(Number.MAX_SAFE_INTEGER / 100);\r\n return Number(scaledPct) / 100;\r\n}\r\n\r\n/**\r\n * Estimate entry price including fee impact (slippage approximation).\r\n */\r\nexport function computeEstimatedEntryPrice(\r\n oracleE6: bigint,\r\n tradingFeeBps: bigint,\r\n direction: \"long\" | \"short\",\r\n): bigint {\r\n if (oracleE6 === 0n) return 0n;\r\n const feeImpact = (oracleE6 * tradingFeeBps) / 10000n;\r\n if (direction === \"long\") return oracleE6 + feeImpact;\r\n // Clamp to 1 to prevent underflow — a zero or negative entry price is nonsensical\r\n // and would cause computePreTradeLiqPrice to report \"no liquidation risk\" (liqPrice=0)\r\n // when fee >= 100%, misleading the UI.\r\n const shortEntry = oracleE6 - feeImpact;\r\n return shortEntry > 0n ? shortEntry : 1n;\r\n}\r\n\r\nconst MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);\r\nconst MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);\r\n\r\n/**\r\n * Convert per-slot funding rate (bps) to annualized percentage.\r\n */\r\nexport function computeFundingRateAnnualized(\r\n fundingRateBpsPerSlot: bigint,\r\n): number {\r\n // Clamp rather than throw: extreme funding rates are display-only values;\r\n // returning +/-Infinity is correct JS behaviour and prevents uncaught exceptions.\r\n if (fundingRateBpsPerSlot > MAX_SAFE_BIGINT) return Infinity;\r\n if (fundingRateBpsPerSlot < MIN_SAFE_BIGINT) return -Infinity;\r\n const bpsPerSlot = Number(fundingRateBpsPerSlot);\r\n const slotsPerYear = 2.5 * 60 * 60 * 24 * 365; // ~400ms slots\r\n return (bpsPerSlot * slotsPerYear) / 100;\r\n}\r\n\r\n/**\r\n * Compute margin required for a given notional and initial margin bps.\r\n */\r\nexport function computeRequiredMargin(\r\n notional: bigint,\r\n initialMarginBps: bigint,\r\n): bigint {\r\n return (notional * initialMarginBps) / 10000n;\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, as an exact ratio.\r\n *\r\n * DISPLAY value: the result is fractional and therefore NOT safe to pass to\r\n * `BigInt()`. Any caller doing integer/native-unit arithmetic must use\r\n * {@link computeMaxLeverageFloor} instead.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverage(initialMarginBps: bigint): number {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverage: initialMarginBps must be positive\");\r\n }\r\n // Use floating-point division so fractional leverage is preserved.\r\n // BigInt floor division (10000n / initialMarginBps) silently truncates:\r\n // e.g. 3000 bps (33.3% margin) -> 3x instead of 3.33x, a 10% UI error.\r\n return 10000 / Number(initialMarginBps);\r\n}\r\n\r\n/**\r\n * Compute maximum leverage from initial margin bps, floored to a whole\r\n * multiplier — the conservative integer form used by risk/sizing math.\r\n *\r\n * Kept separate from {@link computeMaxLeverage} because that one is a display\r\n * value and may be fractional: `BigInt(3.3333)` throws `RangeError`. Rounding\r\n * DOWN also keeps client-side caps at or below what the program enforces, so a\r\n * caller can never build a position the chain would reject on leverage.\r\n *\r\n * @throws Error if initialMarginBps is zero (infinite leverage is undefined)\r\n */\r\nexport function computeMaxLeverageFloor(initialMarginBps: bigint): bigint {\r\n if (initialMarginBps <= 0n) {\r\n throw new Error(\"computeMaxLeverageFloor: initialMarginBps must be positive\");\r\n }\r\n return 10000n / initialMarginBps;\r\n}\r\n","/**\r\n * Warmup leverage cap utilities.\r\n *\r\n * During the market warmup period, capital is released linearly over\r\n * `warmupPeriodSlots` slots, which constrains the effective leverage\r\n * and maximum position size available to traders.\r\n */\r\n\r\nimport { computeMaxLeverageFloor } from \"./trading.js\";\r\n\r\n// =============================================================================\r\n// Warmup leverage cap utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Compute unlocked capital during the warmup period.\r\n *\r\n * Capital is released linearly over `warmupPeriodSlots` slots starting from\r\n * `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the\r\n * warmup period is 0, all capital is considered unlocked.\r\n *\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The amount of capital currently unlocked.\r\n */\r\nexport function computeWarmupUnlockedCapital(\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n // No warmup configured or not started → all capital available\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return totalCapital;\r\n if (totalCapital <= 0n) return 0n;\r\n\r\n const elapsed = currentSlot > warmupStartSlot\r\n ? currentSlot - warmupStartSlot\r\n : 0n;\r\n\r\n // Warmup complete\r\n if (elapsed >= warmupPeriodSlots) return totalCapital;\r\n\r\n // Linear unlock: totalCapital * elapsed / warmupPeriodSlots\r\n return (totalCapital * elapsed) / warmupPeriodSlots;\r\n}\r\n\r\n/**\r\n * Compute the effective maximum leverage during the warmup period.\r\n *\r\n * During warmup, only unlocked capital can be used as margin. The effective\r\n * leverage relative to *total* capital is therefore capped at:\r\n *\r\n * effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)\r\n *\r\n * This returns a floored integer value (leverage is always a whole number\r\n * in the UI), with a minimum of 1x if any capital is unlocked.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns The effective maximum leverage (integer, ≥ 1).\r\n */\r\nexport function computeWarmupLeverageCap(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): number {\r\n // Integer form: this is risk/sizing math, and the fractional\r\n // computeMaxLeverage() is a display value that cannot be used in BigInt\r\n // arithmetic. Flooring also keeps the client cap at or below the program's.\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n\r\n // No warmup or warmup not started → full leverage\r\n if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return Number(maxLev);\r\n if (totalCapital <= 0n) return 1;\r\n\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n\r\n if (unlocked <= 0n) return 1; // At least 1x if nothing unlocked yet (slot 0 edge)\r\n\r\n // Effective leverage = maxLev * (unlocked / total), floored, min 1\r\n const effectiveLev = Number((maxLev * unlocked) / totalCapital);\r\n return Math.max(1, effectiveLev);\r\n}\r\n\r\n/**\r\n * Compute the maximum position size allowed during warmup.\r\n *\r\n * This is the unlocked capital multiplied by the base max leverage.\r\n * Unlike `computeWarmupLeverageCap` (which gives effective leverage\r\n * relative to total capital), this gives the absolute notional cap.\r\n *\r\n * @param initialMarginBps - Initial margin requirement in basis points.\r\n * @param totalCapital - Total deposited capital (native units).\r\n * @param currentSlot - The current on-chain slot.\r\n * @param warmupStartSlot - Slot at which warmup started (0 = not started).\r\n * @param warmupPeriodSlots - Total slots in the warmup period.\r\n * @returns Maximum position size in native units.\r\n */\r\nexport function computeWarmupMaxPositionSize(\r\n initialMarginBps: bigint,\r\n totalCapital: bigint,\r\n currentSlot: bigint,\r\n warmupStartSlot: bigint,\r\n warmupPeriodSlots: bigint,\r\n): bigint {\r\n const maxLev = computeMaxLeverageFloor(initialMarginBps);\r\n const unlocked = computeWarmupUnlockedCapital(\r\n totalCapital,\r\n currentSlot,\r\n warmupStartSlot,\r\n warmupPeriodSlots,\r\n );\r\n return unlocked * maxLev;\r\n}\r\n","/**\r\n * Input validation utilities for CLI commands.\r\n * Provides descriptive error messages for invalid input.\r\n */\r\n\r\nimport { PublicKey } from \"@solana/web3.js\";\r\n\r\n// Constants for numeric limits\r\nconst U16_MAX = 65535;\r\nconst U64_MAX = BigInt(\"18446744073709551615\");\r\nconst I64_MIN = BigInt(\"-9223372036854775808\");\r\nconst I64_MAX = BigInt(\"9223372036854775807\");\r\nconst U128_MAX = (1n << 128n) - 1n;\r\nconst I128_MIN = -(1n << 127n);\r\nconst I128_MAX = (1n << 127n) - 1n;\r\n\r\nexport class ValidationError extends Error {\r\n constructor(\r\n public readonly field: string,\r\n message: string\r\n ) {\r\n super(`Invalid ${field}: ${message}`);\r\n this.name = \"ValidationError\";\r\n }\r\n}\r\n\r\n/**\r\n * Regex that accepts a non-negative decimal integer string: `\"0\"` or `[1-9]\\d*`.\r\n * Rejects fractions, scientific notation, hex prefixes, leading zeros, and trailing junk.\r\n */\r\nconst DECIMAL_UINT_RE = /^(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Regex that accepts a decimal integer string (optionally negative): `-?(0|[1-9]\\d*)`.\r\n * Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n */\r\nconst DECIMAL_INT_RE = /^-?(0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * Non-empty trimmed string of decimal digits only: `\"0\"` or `[1-9]\\\\d*` (no leading zeros\r\n * except a single zero). Rejects fractions, scientific notation, hex prefixes, and trailing junk.\r\n *\r\n * @param value - The string to validate.\r\n * @param field - The field name used in error messages.\r\n * @returns The trimmed, validated decimal string.\r\n */\r\nexport function requireDecimalUIntString(value: string, field: string): string {\r\n const t = value.trim();\r\n if (t === \"\") {\r\n throw new ValidationError(field, `\"${value}\" is not a valid number`);\r\n }\r\n if (!DECIMAL_UINT_RE.test(t)) {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid non-negative integer (use decimal digits only, e.g. 123).`\r\n );\r\n }\r\n return t;\r\n}\r\n\r\n/**\r\n * Parse a decimal integer string into a BigInt, rejecting any non-decimal representation\r\n * (hex, scientific notation, underscores, fractions, leading zeros).\r\n *\r\n * Use this instead of the bare `BigInt(val)` cast when the input is user-supplied or\r\n * externally-sourced, to prevent silent acceptance of `\"0x1\"`, `\"1e5\"`, `\"1_000\"` etc.\r\n *\r\n * @param val - The string to parse. May be negative (e.g. `\"-42\"`).\r\n * @param caller - The calling function name, used in the error message.\r\n * @returns The parsed BigInt value.\r\n * @throws {Error} When `val` does not match the strict decimal integer format.\r\n *\r\n * @example\r\n * safeBigInt(\"123\", \"encU64\") // 123n\r\n * safeBigInt(\"-9223372036854775808\", \"encI64\") // i64 min\r\n * safeBigInt(\"0x1\", \"encU64\") // throws\r\n * safeBigInt(\"1e5\", \"encU128\") // throws\r\n */\r\nexport function safeBigInt(val: string, caller: string): bigint {\r\n const t = val.trim();\r\n if (!DECIMAL_INT_RE.test(t)) {\r\n throw new Error(\r\n `${caller}: \"${val}\" is not a valid decimal integer ` +\r\n `(use plain decimal digits, e.g. 123 or -42; no hex, scientific notation, or underscores).`\r\n );\r\n }\r\n return BigInt(t);\r\n}\r\n\r\n/**\r\n * Validate a public key string.\r\n */\r\nexport function validatePublicKey(value: string, field: string): PublicKey {\r\n try {\r\n return new PublicKey(value);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid base58 public key. ` +\r\n `Example: \"11111111111111111111111111111111\"`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validate a non-negative integer index (u16 range for accounts).\r\n */\r\nexport function validateIndex(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a non-negative amount (u64 range).\r\n */\r\nexport function validateAmount(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U64_MAX} (u64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a u128 value.\r\n */\r\nexport function validateU128(value: string, field: string): bigint {\r\n const t = requireDecimalUIntString(value, field);\r\n const num = BigInt(t);\r\n\r\n if (num < 0n) {\r\n throw new ValidationError(field, `must be non-negative, got ${num}`);\r\n }\r\n\r\n if (num > U128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U128_MAX} (u128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i64 value.\r\n */\r\nexport function validateI64(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I64_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I64_MIN} (i64 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I64_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I64_MAX} (i64 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate an i128 value (trade sizes).\r\n */\r\nexport function validateI128(value: string, field: string): bigint {\r\n let num: bigint;\r\n\r\n try {\r\n num = safeBigInt(value, field);\r\n } catch {\r\n throw new ValidationError(\r\n field,\r\n `\"${value}\" is not a valid number. Use decimal digits only, with optional leading minus.`\r\n );\r\n }\r\n\r\n if (num < I128_MIN) {\r\n throw new ValidationError(\r\n field,\r\n `must be >= ${I128_MIN} (i128 min), got ${num}`\r\n );\r\n }\r\n\r\n if (num > I128_MAX) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${I128_MAX} (i128 max), got ${num}`\r\n );\r\n }\r\n\r\n return num;\r\n}\r\n\r\n/**\r\n * Validate a basis points value (0-10000).\r\n */\r\nexport function validateBps(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > 10000n) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= 10000 (100%), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n\r\n/**\r\n * Validate a u64 value.\r\n */\r\nexport function validateU64(value: string, field: string): bigint {\r\n return validateAmount(value, field);\r\n}\r\n\r\n/**\r\n * Validate a u16 value.\r\n */\r\nexport function validateU16(value: string, field: string): number {\r\n const t = requireDecimalUIntString(value, field);\r\n const bi = BigInt(t);\r\n if (bi > BigInt(U16_MAX)) {\r\n throw new ValidationError(\r\n field,\r\n `must be <= ${U16_MAX} (u16 max), got ${t}`\r\n );\r\n }\r\n return Number(bi);\r\n}\r\n","/**\r\n * Smart Price Router — automatic oracle selection for any token.\r\n *\r\n * Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),\r\n * ranks them by liquidity/reliability, and returns the best oracle config.\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type PriceSourceType = \"pyth\" | \"dex\" | \"jupiter\";\r\n\r\nexport interface PriceSource {\r\n type: PriceSourceType;\r\n /** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */\r\n address: string;\r\n /** DEX id for dex sources */\r\n dexId?: string;\r\n /** Pair label e.g. \"SOL / USDC\" */\r\n pairLabel?: string;\r\n /** USD liquidity depth — higher is better */\r\n liquidity: number;\r\n /** Latest spot price in USD */\r\n price: number;\r\n /** Confidence score 0-100 (composite of liquidity, staleness, reliability) */\r\n confidence: number;\r\n}\r\n\r\nexport interface PriceRouterResult {\r\n mint: string;\r\n bestSource: PriceSource | null;\r\n allSources: PriceSource[];\r\n /** ISO timestamp of resolution */\r\n resolvedAt: string;\r\n}\r\n\r\n/** Options for {@link resolvePrice}. */\r\nexport interface ResolvePriceOptions {\r\n timeoutMs?: number;\r\n}\r\n\r\nconst DEFAULT_RESOLVE_TIMEOUT_MS = 15_000;\r\n\r\nfunction isRecord(v: unknown): v is Record {\r\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\r\n}\r\n\r\nfunction combineAbortSignals(signals: AbortSignal[]): AbortSignal {\r\n const already = signals.find((s) => s.aborted);\r\n if (already) {\r\n const c = new AbortController();\r\n c.abort(already.reason);\r\n return c.signal;\r\n }\r\n const active = signals.filter((s) => !s.aborted);\r\n if (active.length === 0) {\r\n const c = new AbortController();\r\n c.abort();\r\n return c.signal;\r\n }\r\n if (active.length === 1) return active[0];\r\n const ctrl = new AbortController();\r\n for (const s of active) {\r\n s.addEventListener(\"abort\", () => ctrl.abort(s.reason), { once: true });\r\n }\r\n return ctrl.signal;\r\n}\r\n\r\nconst SUPPORTED_DEX_IDS = new Set([\"pumpswap\", \"raydium\", \"meteora\"]);\r\n\r\nfunction parseDexScreenerPairs(json: unknown): PriceSource[] {\r\n if (!isRecord(json)) return [];\r\n const rawPairs = json.pairs;\r\n if (!Array.isArray(rawPairs)) return [];\r\n const sources: PriceSource[] = [];\r\n\r\n for (const pair of rawPairs) {\r\n if (!isRecord(pair)) continue;\r\n if (pair.chainId !== \"solana\") continue;\r\n const dexId = String(pair.dexId || \"\").toLowerCase();\r\n if (!SUPPORTED_DEX_IDS.has(dexId)) continue;\r\n\r\n let liquidity = 0;\r\n if (isRecord(pair.liquidity) && typeof pair.liquidity.usd === \"number\") {\r\n liquidity = pair.liquidity.usd;\r\n }\r\n if (liquidity < 100) continue;\r\n\r\n let confidence = 30;\r\n if (liquidity > 1_000_000) confidence = 90;\r\n else if (liquidity > 100_000) confidence = 75;\r\n else if (liquidity > 10_000) confidence = 60;\r\n else if (liquidity > 1_000) confidence = 45;\r\n\r\n const priceUsd = pair.priceUsd;\r\n const price =\r\n typeof priceUsd === \"string\" || typeof priceUsd === \"number\"\r\n ? parseFloat(String(priceUsd)) || 0\r\n : 0;\r\n\r\n // #222: priceUsd of \"0\" / non-numeric / missing parses to 0. Confidence derives\r\n // from liquidity, so a high-liquidity zero-price pair would sort to the top and\r\n // become bestSource with price 0, outranking a valid Jupiter/Pyth fallback. Skip\r\n // any source without a usable positive price.\r\n if (!(price > 0)) continue;\r\n\r\n let baseSym = \"?\";\r\n let quoteSym = \"?\";\r\n if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === \"string\") {\r\n baseSym = pair.baseToken.symbol;\r\n }\r\n if (isRecord(pair.quoteToken) && typeof pair.quoteToken.symbol === \"string\") {\r\n quoteSym = pair.quoteToken.symbol;\r\n }\r\n\r\n const addr = pair.pairAddress;\r\n sources.push({\r\n type: \"dex\",\r\n address: typeof addr === \"string\" ? addr : \"\",\r\n dexId,\r\n pairLabel: `${baseSym} / ${quoteSym}`,\r\n liquidity,\r\n price,\r\n confidence,\r\n });\r\n }\r\n\r\n sources.sort((a, b) => b.liquidity - a.liquidity);\r\n return sources.slice(0, 10);\r\n}\r\n\r\n/**\r\n * Parse a Jupiter price row.\r\n *\r\n * Handles BOTH shapes:\r\n * v3 (current): { \"\": { usdPrice, liquidity, decimals, ... } }\r\n * v2 (retired): { data: { \"\": { price, mintSymbol } } }\r\n *\r\n * v2 was retired — `https://api.jup.ag/price/v2` returns HTTP 404 — which meant\r\n * `fetchJupiterSource` returned null on every real call and EVERY Jupiter\r\n * cross-validation in this module was silently inert, including the #227/#315\r\n * Pyth enrichment guard. The v2 branch is kept only so a caller pinning an old\r\n * mock or a proxy that still speaks v2 keeps working.\r\n */\r\nfunction parseJupiterMintEntry(\r\n json: unknown,\r\n mint: string,\r\n): { price: number; mintSymbol: string; liquidity: number } | null {\r\n if (!isRecord(json)) return null;\r\n\r\n // v3: the mint is a top-level key.\r\n const v3Row = json[mint];\r\n if (isRecord(v3Row) && v3Row.usdPrice !== undefined && v3Row.usdPrice !== null) {\r\n const price = parseFloat(String(v3Row.usdPrice)) || 0;\r\n if (price <= 0) return null;\r\n const liquidity =\r\n typeof v3Row.liquidity === \"number\" && Number.isFinite(v3Row.liquidity)\r\n ? v3Row.liquidity\r\n : 0;\r\n return { price, mintSymbol: \"?\", liquidity };\r\n }\r\n\r\n // v2 (retired): rows live under `data`.\r\n const data = json.data;\r\n if (!isRecord(data)) return null;\r\n const row = data[mint];\r\n if (!isRecord(row)) return null;\r\n const rawPrice = row.price;\r\n if (rawPrice === undefined || rawPrice === null) return null;\r\n const price = parseFloat(String(rawPrice)) || 0;\r\n if (price <= 0) return null;\r\n let mintSymbol = \"?\";\r\n if (typeof row.mintSymbol === \"string\") mintSymbol = row.mintSymbol;\r\n return { price, mintSymbol, liquidity: 0 };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Top Solana tokens with known Pyth feeds (feed ID → symbol)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const PYTH_SOLANA_FEEDS: Record = {\r\n // SOL\r\n \"ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d\": { symbol: \"SOL\", mint: \"So11111111111111111111111111111111111111112\" },\r\n // BTC\r\n \"e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43\": { symbol: \"BTC\", mint: \"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E\" },\r\n // ETH\r\n \"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace\": { symbol: \"ETH\", mint: \"7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs\" },\r\n // USDC\r\n \"eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a\": { symbol: \"USDC\", mint: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\" },\r\n // USDT\r\n \"2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b\": { symbol: \"USDT\", mint: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\" },\r\n // BONK\r\n \"72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419\": { symbol: \"BONK\", mint: \"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263\" },\r\n // JTO\r\n \"b43660a5f790c69354b0729a5ef9d50d68f1df92107540210b9cccba1f947cc2\": { symbol: \"JTO\", mint: \"jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL\" },\r\n // JUP\r\n \"0a0408d619e9380abad35060f9192039ed5042fa6f82301d0e48bb52be830996\": { symbol: \"JUP\", mint: \"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN\" },\r\n // PYTH\r\n \"0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff\": { symbol: \"PYTH\", mint: \"HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3\" },\r\n // RAY\r\n \"91568bae053f70f0c3fbf32eb55df25ec609fb8a21cfb1a0e3b34fc3caa1eab0\": { symbol: \"RAY\", mint: \"4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R\" },\r\n // ORCA\r\n \"37505261e557e251f40c2c721e52c4c8bfb2e54a12f450d0e24078276ad51b95\": { symbol: \"ORCA\", mint: \"orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE\" },\r\n // MNGO\r\n \"f9abf5eb70a2e68e21b72b68cc6e0a4d25e1d77e1ec16eae5b93068a2cb81f90\": { symbol: \"MNGO\", mint: \"MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac\" },\r\n // MSOL\r\n \"c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4\": { symbol: \"MSOL\", mint: \"mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So\" },\r\n // JITOSOL\r\n \"67be9f519b95cf24338801051f9a808eff0a578ccb388db73b7f6fe1de019ffb\": { symbol: \"JITOSOL\", mint: \"J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn\" },\r\n // WIF\r\n \"4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54e6c5c4b03\": { symbol: \"WIF\", mint: \"EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm\" },\r\n // RENDER\r\n \"3573eb14b04aa0e4f7cf1e7ae1c2a0e3bc6100b2e476876ca079e10e2c42d7c6\": { symbol: \"RENDER\", mint: \"rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof\" },\r\n // W\r\n \"eff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389\": { symbol: \"W\", mint: \"85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ\" },\r\n // TNSR\r\n \"05ecd4597cd48fe13d6cc3596c62af4f9675aee06e2e0ca164a73be4b0813f3b\": { symbol: \"TNSR\", mint: \"TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6\" },\r\n // HNT\r\n \"649fdd7ec08e8e2a20f425729854e90293dcbe2376abc47197a14da6ff339756\": { symbol: \"HNT\", mint: \"hntyVP6YFm1Hg25TN9WGLqM12b8TQmcknKrdu1oxWux\" },\r\n // MOBILE\r\n \"ff4c53361e36a9b1caa490f1e46e07e3c472d54d2a4856a1e4609bd4db36bff0\": { symbol: \"MOBILE\", mint: \"mb1eu7TzEc71KxDpsmsKoucSSuuoGLv1drys1oP2jh6\" },\r\n // IOT\r\n \"8bdd20f0c68bf7370a19389bbb3d17c1db7956c38efa08b2f3dd0e5db9b8c1ef\": { symbol: \"IOT\", mint: \"iotEVVZLEywoTn1QdwNPddxPWszn3zFhEot3MfL9fns\" },\r\n};\r\nObject.freeze(PYTH_SOLANA_FEEDS);\r\n\r\n// Reverse lookup: mint → feed ID\r\nconst MINT_TO_PYTH_FEED = new Map();\r\nfor (const [feedId, info] of Object.entries(PYTH_SOLANA_FEEDS)) {\r\n MINT_TO_PYTH_FEED.set(info.mint, { feedId, symbol: info.symbol });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// DexScreener fetcher\r\n// ---------------------------------------------------------------------------\r\n\r\nconst DEFAULT_FETCH_TIMEOUT_MS = 10_000;\r\n\r\nfunction effectiveSignal(signal?: AbortSignal): AbortSignal {\r\n return signal ?? AbortSignal.timeout(DEFAULT_FETCH_TIMEOUT_MS);\r\n}\r\n\r\nasync function fetchDexSources(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.dexscreener.com/latest/dex/tokens/${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return [];\r\n const json: unknown = await resp.json();\r\n return parseDexScreenerPairs(json);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Pyth lookup\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction lookupPythSource(mint: string): PriceSource | null {\r\n const entry = MINT_TO_PYTH_FEED.get(mint);\r\n if (!entry) return null;\r\n return {\r\n type: \"pyth\",\r\n address: entry.feedId,\r\n pairLabel: `${entry.symbol} / USD (Pyth)`,\r\n liquidity: Infinity, // Pyth is considered deep liquidity\r\n price: 0, // We don't fetch live price here; caller can enrich\r\n confidence: 95, // Pyth is highest reliability for supported tokens\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Jupiter price fallback\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchJupiterSource(mint: string, signal?: AbortSignal): Promise {\r\n try {\r\n const resp = await fetch(\r\n `https://api.jup.ag/price/v3?ids=${encodeURIComponent(mint)}`,\r\n {\r\n signal: effectiveSignal(signal),\r\n headers: { \"User-Agent\": \"percolator/1.0\" },\r\n },\r\n );\r\n if (!resp.ok) return null;\r\n const json: unknown = await resp.json();\r\n const row = parseJupiterMintEntry(json, mint);\r\n if (!row) return null;\r\n return {\r\n type: \"jupiter\",\r\n address: mint,\r\n pairLabel: `${row.mintSymbol} / USD (Jupiter)`,\r\n // v3 reports aggregate routable liquidity; v2 did not (falls back to 0).\r\n // Used below to decide whether Jupiter is a credible enough reference to\r\n // demote a disagreeing pool.\r\n liquidity: row.liquidity,\r\n price: row.price,\r\n confidence: 40, // Fallback — lower confidence\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main resolver\r\n// ---------------------------------------------------------------------------\r\n\r\nexport async function resolvePrice(\r\n mint: string,\r\n signal?: AbortSignal,\r\n options?: ResolvePriceOptions,\r\n): Promise {\r\n const timeoutMs = options?.timeoutMs ?? DEFAULT_RESOLVE_TIMEOUT_MS;\r\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\r\n const combinedSignal = signal\r\n ? combineAbortSignals([signal, timeoutSignal])\r\n : timeoutSignal;\r\n\r\n const [dexSources, jupiterSource] = await Promise.all([\r\n fetchDexSources(mint, combinedSignal),\r\n fetchJupiterSource(mint, combinedSignal),\r\n ]);\r\n\r\n // #227: cross-validate a manipulable DEX source against an independent Jupiter\r\n // reference. Originally this threshold (now tightened to 5% by #315) only gated\r\n // whether a Pyth source got enriched (see below), so a token with NO Pyth feed —\r\n // the common case for permissionless markets — had its top DEX source ranked\r\n // purely on self-reported liquidity, with no check against an independent price\r\n // at all. A single high-liquidity-labeled pool (manipulable via flash loan, per\r\n // the SECURITY NOTE in dex-oracle.ts) could win bestSource outright even when\r\n // Jupiter's aggregated price disagreed by an arbitrary amount. Cap the top DEX\r\n // source's confidence to Jupiter's when they diverge beyond the same tightened\r\n // threshold used for Pyth enrichment, so it can no longer outrank a disagreeing\r\n // independent reference purely on liquidity. The source stays in allSources for\r\n // transparency; only its ranking weight is reduced.\r\n const MAX_ENRICHMENT_DEVIATION = 0.05; // 5% (#315)\r\n // How far below Jupiter's own confidence a distrusted DEX source is placed. It\r\n // must be STRICTLY below, not equal: allSources is [...dexSources, jupiterSource]\r\n // and Array.prototype.sort is stable, so an equal score leaves the DEX source\r\n // ahead and bestSource unchanged.\r\n const DISTRUST_CONFIDENCE_MARGIN = 1;\r\n if (jupiterSource && jupiterSource.price > 0) {\r\n // SCOPE: this runs before the Pyth branch and therefore also reorders sources\r\n // for Pyth-listed mints. That is intentional and harmless to the Pyth price\r\n // itself — enrichment reads dexSources[0].price, which is untouched; only\r\n // ranking weight changes, and Pyth's own confidence (95) still outranks\r\n // everything here.\r\n //\r\n // CREDIBILITY GATE: only demote when Jupiter reports real routable liquidity.\r\n // Jupiter is an aggregate across venues, so it is normally the better\r\n // reference — but with v2 retired a malformed/empty response used to yield a\r\n // liquidity-0 row, and demoting a deep honest pool in favour of that would\r\n // make the resolved price WORSE. If Jupiter reports no depth we leave the\r\n // ranking alone rather than trust it.\r\n const jupiterIsCredible = jupiterSource.liquidity > 0;\r\n const distrusted = Math.max(0, jupiterSource.confidence - DISTRUST_CONFIDENCE_MARGIN);\r\n if (jupiterIsCredible) {\r\n // Demote EVERY divergent DEX source, not just dexSources[0]: fetchDexSources\r\n // returns up to 10 pools and confidence is a step function of liquidity, so a\r\n // second pool in the same tier would otherwise keep its score and win\r\n // bestSource at the divergent price.\r\n for (const dex of dexSources) {\r\n const nonPythMid = (dex.price + jupiterSource.price) / 2;\r\n const nonPythDeviation = Math.abs(dex.price - jupiterSource.price) / nonPythMid;\r\n if (nonPythDeviation > MAX_ENRICHMENT_DEVIATION) {\r\n dex.confidence = Math.min(dex.confidence, distrusted);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const pythSource = lookupPythSource(mint);\r\n\r\n const allSources: PriceSource[] = [];\r\n\r\n // Add Pyth if available (highest priority for supported tokens)\r\n if (pythSource) {\r\n // Enrich Pyth price from Jupiter or DEX if available.\r\n // Guard: only push a Pyth source when we have at least one live price\r\n // reference — pushing price=0 would cause encodePushOraclePrice to throw\r\n // at crank time on devnet/mainnet.\r\n const dexPrice = dexSources[0]?.price ?? 0;\r\n const jupPrice = jupiterSource?.price ?? 0;\r\n // #227: cross-validate the enrichment reference so a single manipulable DEX\r\n // source cannot poison the Pyth price. When BOTH DEX and Jupiter are present,\r\n // require agreement within 5% and use the mid; if they diverge, skip enrichment\r\n // entirely (don't push a Pyth source). With exactly one source, use it at reduced\r\n // confidence. Never push price=0 — encodePushOraclePrice throws on it at crank time.\r\n //\r\n // The original 50% tolerance allowed a pool operator to manipulate a low-TVL\r\n // DEX pool to +49% of true price while Jupiter remained at true price — a deviation\r\n // of ~39% passes the 50% gate — causing the enriched Pyth price to be 24.5% above\r\n // true, which can trigger mass incorrect liquidations on markets using EWMA oracle mode.\r\n let enrichedPrice = 0;\r\n let singleSource = false;\r\n if (dexPrice > 0 && jupPrice > 0) {\r\n const mid = (dexPrice + jupPrice) / 2;\r\n const deviation = Math.abs(dexPrice - jupPrice) / mid;\r\n if (deviation <= MAX_ENRICHMENT_DEVIATION) {\r\n enrichedPrice = mid;\r\n } else {\r\n // Sources disagree beyond 5% — refuse to enrich the Pyth source.\r\n // DEX and Jupiter are still added below at their own confidence levels.\r\n console.warn(\r\n `[percolator-sdk] resolvePrice: DEX (${dexPrice}) and Jupiter (${jupPrice}) ` +\r\n `diverge by ${(deviation * 100).toFixed(1)}% > ${MAX_ENRICHMENT_DEVIATION * 100}% ` +\r\n `— Pyth enrichment skipped to prevent oracle manipulation.`,\r\n );\r\n }\r\n } else if (dexPrice > 0 || jupPrice > 0) {\r\n enrichedPrice = dexPrice > 0 ? dexPrice : jupPrice;\r\n singleSource = true;\r\n }\r\n if (enrichedPrice > 0) {\r\n pythSource.price = enrichedPrice;\r\n if (singleSource) {\r\n pythSource.confidence = Math.min(pythSource.confidence, 50);\r\n }\r\n allSources.push(pythSource);\r\n }\r\n }\r\n\r\n // Add DEX sources\r\n allSources.push(...dexSources);\r\n\r\n // Add Jupiter as fallback\r\n if (jupiterSource) {\r\n allSources.push(jupiterSource);\r\n }\r\n\r\n // Sort by confidence descending (already accounts for liquidity/reliability)\r\n allSources.sort((a, b) => b.confidence - a.confidence);\r\n\r\n return {\r\n mint,\r\n bestSource: allSources[0] || null,\r\n allSources,\r\n resolvedAt: new Date().toISOString(),\r\n };\r\n}\r\n"],"mappings":"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AAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA,EAEA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA,EAGA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AACA,WAAW,KAAK,OAAO,OAAO,iBAAiB,EAAG,QAAO,OAAO,CAAC;AACjE,OAAO,OAAO,iBAAiB;AAQxB,SAAS,YAAY,MAAqC;AAC/D,SAAO,kBAAkB,IAAI;AAC/B;AAQO,SAAS,aAAa,MAAsB;AACjD,SAAO,kBAAkB,IAAI,GAAG,QAAQ,WAAW,IAAI;AACzD;AAQO,SAAS,aAAa,MAAkC;AAC7D,SAAO,kBAAkB,IAAI,GAAG;AAClC;AAGA,IAAM,2BAA2B;AAiB1B,SAAS,mBAAmB,MAI1B;AACP,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,KAAK,IAAI;AAAA,IACb,0CAA0C,wBAAwB;AAAA,IAClE;AAAA,EACF;AACA,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,UAAU;AAC3B;AAAA,IACF;AACA,UAAM,QAAQ,IAAI,MAAM,EAAE;AAC1B,QAAI,OAAO;AACT,YAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAClC,UAAI,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,KAAK,OAAO,YAAa;AAC5D;AAAA,MACF;AACA,YAAM,OAAO,YAAY,IAAI;AAC7B,aAAO;AAAA,QACL;AAAA,QACA,MAAM,MAAM,QAAQ,WAAW,IAAI;AAAA,QACnC,MAAM,MAAM;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AC/ZA,SAAS,aAAAC,kBAAiB;;;ACvB1B,SAAS,aAAAC,kBAAiB;AAOnB,SAAS,QAAQ,KAAiC;AACvD,MAAI;AACF,WAAO,OAAO,YAAY,eAAe,SAAS,MAC9C,QAAQ,IAAI,GAAG,IACf;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA;AAAA;AAAA;AAAA,IAIN,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACF;AACA,OAAO,OAAO,YAAY,MAAM;AAChC,OAAO,OAAO,YAAY,OAAO;AACjC,OAAO,OAAO,WAAW;AAelB,IAAM,kBAAkB;AAAA;AAAA,EAE7B,YAAY;AAAA;AAAA,EAEZ,SAAS;AAAA;AAAA,EAET,KAAK;AAAA;AAAA,EAEL,OAAO;AACT;AACA,OAAO,OAAO,eAAe;AAGtB,IAAM,iBAAiB,IAAIA,WAAU,gBAAgB,UAAU;AAKtE,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC,YAAY,OAAO;AAAA,EACnB,YAAY,QAAQ;AAAA,EACpB,gBAAgB;AAClB,CAAC;AAGD,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC,YAAY,OAAO;AAAA,EACnB,YAAY,QAAQ;AACtB,CAAC;AASD,SAAS,uBAAgC;AACvC,SAAO,QAAQ,uCAAuC,MAAM;AAC9D;AAUO,SAAS,aAAa,SAA8B;AAKzD,MAAI,YAAY,QAAW;AACzB,UAAM,WAAW,QAAQ,YAAY;AACrC,QAAI,UAAU;AACZ,UAAI,CAAC,kBAAkB,IAAI,QAAQ,KAAK,CAAC,qBAAqB,GAAG;AAC/D,cAAM,IAAI;AAAA,UACR,wCAAwC,QAAQ,qDAC7B,CAAC,GAAG,iBAAiB,EAAE,KAAK,IAAI,CAAC;AAAA,QAGtD;AAAA,MACF;AACA,cAAQ,KAAK,oDAAoD,QAAQ,EAAE;AAC3E,aAAO,IAAIA,WAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,kBAAkB,kBAAkB;AAC1C,QAAM,gBAAgB,WAAW;AACjC,QAAM,YAAY,YAAY,aAAa,EAAE;AAE7C,SAAO,IAAIA,WAAU,SAAS;AAChC;AAKO,SAAS,oBAAoB,SAA8B;AAEhE,MAAI,YAAY,QAAW;AACzB,UAAM,WAAW,QAAQ,oBAAoB;AAC7C,QAAI,UAAU;AACZ,UAAI,CAAC,kBAAkB,IAAI,QAAQ,KAAK,CAAC,qBAAqB,GAAG;AAC/D,cAAM,IAAI;AAAA,UACR,gDAAgD,QAAQ,6DACrC,CAAC,GAAG,iBAAiB,EAAE,KAAK,IAAI,CAAC;AAAA,QAGtD;AAAA,MACF;AACA,cAAQ,KAAK,4DAA4D,QAAQ,EAAE;AACnF,aAAO,IAAIA,WAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,kBAAkB,kBAAkB;AAC1C,QAAM,gBAAgB,WAAW;AACjC,QAAM,YAAY,YAAY,aAAa,EAAE;AAE7C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,mCAAmC,aAAa,EAAE;AAAA,EACpE;AAEA,SAAO,IAAIA,WAAU,SAAS;AAChC;AAcO,SAAS,oBAA6B;AAC3C,QAAM,UAAU,QAAQ,SAAS,GAAG,YAAY;AAChD,MAAI,YAAY,aAAa,YAAY,gBAAgB;AACvD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ADxJA,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA;AAAA,EACA,gBAAgB;AAAA;AAClB,CAAC;AAED,IAAM,uBAAuB,QAAQ,gBAAgB;AACrD,IAAI,yBAAyB,UAAa,CAAC,sBAAsB,IAAI,oBAAoB,GAAG;AAC1F,QAAM,IAAI;AAAA,IACR,4CAA4C,oBAAoB,yDAC7C,CAAC,GAAG,qBAAqB,EAAE,KAAK,IAAI,CAAC;AAAA,EAE1D;AACF;AAYO,IAAM,iBAAiB,IAAIC,WAAU,wBAAwB,gBAAgB,GAAG;AAEhF,SAAS,kBAA6B;AAC3C,SAAO;AACT;AAMO,IAAM,aAAa;AAAA,EACxB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,oBAAoB;AACtB;AAOO,SAAS,cAAc,YAAgC;AAC5D,QAAM,gBAAgB,OAAO,YAAY,YAAY;AACrD,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,CAAC,IAAI,WAAW;AACpB,MAAI,IAAI,eAAe,CAAC;AACxB,SAAO;AACT;AAGO,SAAS,gBAA4B;AAC1C,SAAO,IAAI,WAAW,CAAC,WAAW,eAAe,CAAC;AACpD;AAGO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,WAAW,aAAa,CAAC;AAClD;AAGO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,WAAW,aAAa,CAAC;AAClD;AAOO,SAAS,qBAAiC;AAC/C,SAAO,IAAI,WAAW,CAAC,WAAW,kBAAkB,CAAC;AACvD;AA8BO,SAAS,qBACd,MACA,MACiE;AACjE,MAAI,KAAK,WAAW,KAAK,QAAQ;AAC/B,UAAM,IAAI;AAAA,MACR,0DAA0D,KAAK,MAAM,SAAS,KAAK,MAAM;AAAA,IAC3F;AAAA,EACF;AACA,SAAO,KAAK,IAAI,CAAC,MAAM,OAAO;AAAA,IAC5B,QAAQ,KAAK,CAAC;AAAA,IACd,UAAU,SAAS,OAAO,SAAS;AAAA,IACnC,YAAY,SAAS,OAAO,SAAS;AAAA,EACvC,EAAE;AACJ;AAsBO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,EAAM;AAAA,EAAK;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC3D;AAoBO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAChD;AAgBO,IAAM,8BAA6C;AAAA,EACxD;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAChD;AA4BO,IAAM,yBAAwC;AAAA,EACnD;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC1C;AAMA,IAAM,OAAO,IAAI,YAAY;AAE7B,SAAS,OAAO,OAAe,OAA2B;AACxD,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,OAAQ;AAC3D,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB;AAAA,EAC1C;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AACjD,SAAO;AACT;AAEA,SAAS,OAAO,OAAwB,OAA2B;AACjE,QAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC1D,MAAI,IAAI,MAAM,IAAI,qBAAwB;AACxC,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB;AAAA,EAC1C;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,aAAa,GAAG,GAAG,IAAI;AAChD,SAAO;AACT;AAaO,SAAS,aACd,kBACA,UACA,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,cAAc,GAAG,iBAAiB,QAAQ,GAAG,OAAO,UAAU,UAAU,CAAC;AAAA,IACtF;AAAA,EACF;AACF;AAUO,SAAS,cACd,mBACA,aACA,aAAwB,gBACH;AACrB,QAAM,IAAI,MAAM,kEAAkE;AACpF;AAMO,SAAS,oBACd,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,gBAAgB,CAAC;AAAA,IAC9B;AAAA,EACF;AACF;AAQO,SAAS,wBACd,SACA,YAAuB,gBACF;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,KAAK,OAAO,qBAAqB,GAAG,QAAQ,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AA8BO,IAAM,yBAAyB;AACtC,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AA8C7B,SAAS,iBAAiB,MAAgB,QAAwB;AAChE,QAAM,KAAK,KAAK,aAAa,QAAQ,IAAI;AACzC,QAAM,KAAK,KAAK,aAAa,SAAS,GAAG,IAAI;AAC7C,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,UAAU;AACxB,WAAO,YAAY,MAAM;AAAA,EAC3B;AACA,SAAO;AACT;AAMO,SAAS,wBAAwB,MAAoC;AAC1E,MAAI,KAAK,SAAS,wBAAwB;AACxC,UAAM,IAAI;AAAA,MACR,kCAAkC,KAAK,MAAM,MAAM,sBAAsB;AAAA,IAC3E;AAAA,EACF;AAEA,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,QAAM,QAAQ,KAAK,aAAa,GAAG,IAAI;AACvC,MAAI,UAAU,oBAAoB;AAChC,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,KAAK,CAAC,MAAM,sBAAsB;AACpC,UAAM,IAAI,MAAM,4CAA4C,KAAK,CAAC,CAAC,EAAE;AAAA,EACvE;AAEA,QAAM,sBAAsB,IAAIA,WAAU,KAAK,SAAS,KAAK,GAAG,CAAC;AAEjE,SAAO;AAAA,IACL,SAAS,KAAK,CAAC;AAAA,IACf,MAAM,KAAK,CAAC;AAAA,IACZ,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IACrD,SAAS,IAAIA,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IAC5C,YAAY,KAAK,UAAU,IAAI,IAAI;AAAA,IACnC,YAAY,KAAK,EAAE;AAAA,IACnB,iBAAiB,iBAAiB,MAAM,EAAE;AAAA,IAC1C,aAAa,iBAAiB,MAAM,EAAE;AAAA,IACtC,gBAAgB,KAAK,aAAa,KAAK,IAAI;AAAA,IAC3C,iBAAiB,KAAK,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,IACA,eAAe;AAAA,IACf,UAAU,KAAK,YAAY,KAAK,IAAI;AAAA,IACpC,YAAY,IAAIA,WAAU,KAAK,SAAS,KAAK,GAAG,CAAC;AAAA,EACnD;AACF;;;AErdA,SAAqB,aAAAC,kBAAiB;AAQtC,SAAS,GAAG,MAA4B;AACtC,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACnE;AAEA,SAAS,OAAO,MAAkB,KAAqB;AACrD,MAAI,OAAO,KAAK,QAAQ;AACtB,UAAM,IAAI,WAAW,kBAAkB,GAAG,0BAA0B,KAAK,MAAM,GAAG;AAAA,EACpF;AACA,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,aAAa,KAAK,IAAI;AACxC;AAEA,SAAS,UAAU,MAAkB,KAAqB;AACxD,SAAO,GAAG,IAAI,EAAE,YAAY,KAAK,IAAI;AACvC;AAUA,SAAS,WAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAK,UAAU,KAAK,MAAM;AAChC,QAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AACpC,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,UAAU;AACxB,WAAO,YAAY,MAAM;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,SAAS,WAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAK,UAAU,KAAK,MAAM;AAChC,QAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AACpC,SAAQ,MAAM,MAAO;AACvB;AAsBA,IAAM,QAAgB;AAGf,IAAM,aAAa;AAG1B,IAAM,gBAAgB,KAAK;AAmE3B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAIxB,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAM7B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AAGtB,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAIxB,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AACvC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,kCAAkC;AACxC,IAAM,uBAAuB;AAK7B,IAAM,qCAAqC;AAC3C,IAAM,2BAA2B;AAUjC,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAIzB,IAAM,2BAA2B;AACjC,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB;AACxB,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,mCAAmC;AACzC,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAElC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,uCAAuC;AAC7C,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAElC,IAAM,wBAAwB;AAU9B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;AAG7B,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;AACpC,IAAM,kCAAkC;AACxC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC;AAC5C,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iCAAiC;AAkBvC,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAKzB,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAEhC,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAGhC,IAAM,oBAAoB;AAI1B,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,oCAAoC;AAG1C,IAAM,8BAA8B;AAEpC,IAAM,mCAAmC;AACzC,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,+BAA+B;AAErC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AAEnC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAC7C,IAAM,gCAAgC;AACtC,IAAM,mCAAmC;AAEzC,IAAM,yCAAyC;AAC/C,IAAM,yCAAyC;AAO/C,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,oCAAoC;AAE1C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAK3C,IAAM,0BAA0B;AAIhC,IAAM,gCAAgC;AACtC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AAmBrC,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAGhC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AAErC,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAE1B,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AACvC,IAAM,oCAAoC;AAC1C,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,sCAAsC;AAG5C,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,8BAA8B;AAWpC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,mCAAmC;AACzC,IAAM,uCAAuC;AAC7C,IAAM,yBAAyB;AAC/B,IAAM,+BAA+B;AACrC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AACnC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAC7C,IAAM,gCAAgC;AACtC,IAAM,mCAAmC;AACzC,IAAM,yCAAyC;AAE/C,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,oCAAoC;AAC1C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAC3C,IAAM,yCAAyC;AAI/C,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,+BAA+B;AACrC,IAAM,6BAA6B;AASnC,IAAM,4BAA4B;AAClC,IAAM,gCAAgC;AACtC,IAAM,oCAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,0BAA0B;AAChC,IAAM,gCAAgC;AACtC,IAAM,kCAAkC;AAkBxC,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AAC5B,IAAM,4BAA4B;AAIlC,IAAM,6BAAiC;AACvC,IAAM,0BAAiC;AACvC,IAAM,uBAAiC;AACvC,IAAM,sBAAiC;AACvC,IAAM,+BAAiC;AACvC,IAAM,mCAAmC;AAIzC,IAAM,8BAAiC;AACvC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,wBAAiC;AACvC,IAAM,8BAAiC;AACvC,IAAM,oCAAoC;AAE1C,IAAM,wCAAwC;AAC9C,IAAM,qCAAqC;AAC3C,IAAM,iCAAiC;AACvC,IAAM,yCAAyC;AAC/C,IAAM,kCAAkC;AACxC,IAAM,0CAA0C;AAIhD,IAAM,qBAAqB;AAC3B,IAAM,iCAAkC;AACxC,IAAM,oCAAoC;AAC1C,IAAM,0BAAkC;AACxC,IAAM,0BAAkC;AAIxC,IAAM,2BAAkC;AACxC,IAAM,iCAAkC;AAExC,IAAM,oCAAoC;AAG1C,IAAM,0BAAkC;AACxC,IAAM,gCAAkC;AACxC,IAAM,wCAAwC;AAG9C,IAAM,2BAAkC;AAGxC,IAAM,eAAe,oBAAI,IAAoB;AAyB7C,IAAM,oBAA8B;AACpC,IAAM,sBAA8B;AACpC,IAAM,2BAA8B;AAEpC,IAAM,sBAA8B;AAGpC,IAAM,yBAA8B;AAGpC,IAAM,wBAA8B;AACpC,IAAM,0BAA8B;AACpC,IAAM,+BAA+B;AAGrC,IAAM,0BAAkC;AACxC,IAAM,uBAAkC;AACxC,IAAM,sBAAkC;AACxC,IAAM,+BAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,8BAAkC;AACxC,IAAM,6BAAkC;AACxC,IAAM,yBAAkC;AACxC,IAAM,iCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,wBAAkC;AACxC,IAAM,8BAAkC;AACxC,IAAM,gCAAkC;AACxC,IAAM,oCAAoC;AAC1C,IAAM,iCAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,gCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,sCAAsC;AAC5C,IAAM,kCAAkC;AACxC,IAAM,uCAAuC;AAG7C,IAAM,2BAAoC;AAC1C,IAAM,iCAAoC;AAC1C,IAAM,gCAAoC;AAE1C,IAAM,oCAAoC;AAC1C,IAAM,qCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,oCAAoC;AAC1C,IAAM,0BAAmC;AACzC,IAAM,gCAAmC;AACzC,IAAM,wCAAwC;AAC9C,IAAM,8BAAmC;AACzC,IAAM,gCAAmC;AACzC,IAAM,iCAAmC;AACzC,IAAM,kCAAmC;AACzC,IAAM,sCAAsC;AAC5C,IAAM,iCAAmC;AACzC,IAAM,+BAAmC;AACzC,IAAM,gCAAmC;AAKzC,IAAM,qCAAqC;AAC3C,IAAM,oCAAqC;AAC3C,IAAM,wCAAwC;AAC9C,IAAM,8BAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,4CAA4C;AAClD,IAAM,kCAAoC;AAC1C,IAAM,oCAAoC;AAC1C,IAAM,qCAAqC;AAC3C,IAAM,sCAAsC;AAC5C,IAAM,0CAA0C;AAChD,IAAM,qCAAqC;AAC3C,IAAM,mCAAoC;AAC1C,IAAM,oCAAoC;AAG1C,IAAM,eAAe,oBAAI,IAAoB;AAO7C,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAEzB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAM/B,IAAM,kBAAkB;AAGxB,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AACrC,IAAM,mCAAmC;AACzC,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAElC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,uBAAuB;AAC7B,IAAM,6BAA6B;AACnC,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AACjC,IAAM,kCAAkC;AACxC,IAAM,qCAAqC;AAC3C,IAAM,8BAA8B;AACpC,IAAM,iCAAiC;AACvC,IAAM,uCAAuC;AAC7C,IAAM,uCAAuC;AAC7C,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAClC,IAAM,kCAAkC;AACxC,IAAM,mCAAmC;AACzC,IAAM,sCAAsC;AAC5C,IAAM,mCAAmC;AAKzC,IAAM,wBAAwB;AAc9B,IAAM,oBAAoB;AAI1B,IAAM,yBAAyB;AAIxB,IAAM,aAAa;AACnB,IAAM,wBAAwB;AAQrC,SAAS,gBACP,WACA,WACA,aACA,aAIA,aAAa,IACL;AACR,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,YAAY,cAAc,cAAc;AACjD;AAEA,IAAM,QAAQ,CAAC,IAAI,KAAK,MAAM,IAAI;AAGlC,IAAM,WAAW,oBAAI,IAAoB;AACzC,IAAM,WAAW,oBAAI,IAAoB;AAEzC,IAAM,kBAAkB,oBAAI,IAAoB;AAEhD,IAAM,YAAY,oBAAI,IAAoB;AAO1C,IAAM,WAAW,oBAAI,IAAoB;AAEzC,IAAM,YAAY,oBAAI,IAAoB;AAE1C,IAAM,cAAc,oBAAI,IAAoB;AAM5C,IAAM,aAAa,oBAAI,IAAoB;AAI3C,IAAM,qBAAqB,oBAAI,IAAoB;AAInD,IAAM,cAAc,oBAAI,IAAoB;AAC5C,IAAM,mBAAmB,oBAAI,IAAoB;AACjD,WAAW,KAAK,OAAO;AACrB,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AACxF,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AACxF,kBAAgB,IAAI,gBAAgB,sBAAsB,sBAAsB,iBAAiB,CAAC,GAAG,CAAC;AAGtG,YAAU,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,CAAC,GAAG,CAAC;AAE/F,mBAAiB,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE,GAAG,CAAC;AAGvG,WAAS,IAAI,gBAAgB,eAAe,sBAAsB,iBAAiB,GAAG,EAAE,GAAG,CAAC;AAG5F,YAAU,IAAI,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE,GAAG,CAAC;AAGhG,cAAY,IAAI,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAGxG,aAAW,IAAI,gBAAgB,iBAAiB,wBAAwB,mBAAmB,GAAG,EAAE,GAAG,CAAC;AAGpG,qBAAmB,IAAI,gBAAgB,yBAAyB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAItH,cAAY,IAAI,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE,GAAG,CAAC;AAExG,eAAa,IAAI,gBAAgB,mBAAmB,0BAA0B,qBAAqB,GAAG,EAAE,GAAG,CAAC;AAC9G;AAEA,aAAa,IAAI,gBAAgB,mBAAmB,0BAA0B,qBAAqB,MAAM,EAAE,GAAG,IAAI;AAElH,aAAa,IAAI,QAAQ,GAAG;AAO5B,IAAM,eAAe,CAAC,KAAK,MAAM,IAAI;AACrC,WAAW,KAAK,cAAc;AAC5B,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE;AACpC,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,IAAI;AAG1B,QAAM,eAAe,2BAA2B,cAAc,aAAa;AAC3E,QAAM,oBAAoB,KAAK,KAAK,eAAe,EAAE,IAAI;AACzD,QAAM,aAAa,oBAAoB,oBAAoB,IAAI,sBAAsB,sBAAsB,IAAI;AAC/G,eAAa,IAAI,YAAY,CAAC;AAG9B,QAAM,YAAY,+BAA+B,cAAc,aAAa;AAC5E,QAAM,iBAAiB,KAAK,KAAK,YAAY,CAAC,IAAI;AAClD,QAAM,UAAU,wBAAwB,iBAAiB,IAAI,0BAA0B,sBAAsB,IAAI;AACjH,eAAa,IAAI,SAAS,CAAC;AAC7B;AAeA,IAAM,wBAA6B;AACnC,IAAM,oBAA6B;AACnC,IAAM,wBAA6B;AACnC,IAAM,0BAA6B;AAOnC,IAAM,+BAAsC;AAS5C,IAAM,gCAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,oCAA4C;AAElD,IAAM,4CAA4C;AAClD,IAAM,8BAA4C;AAClD,IAAM,oCAA4C;AAClD,IAAM,4CAA4C;AAClD,IAAM,oCAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,sCAA4C;AAClD,IAAM,kCAA4C;AAClD,IAAM,0CAA4C;AAClD,IAAM,qCAA4C;AAClD,IAAM,yCAA4C;AAClD,IAAM,mCAA4C;AAClD,IAAM,oCAA4C;AAsBlD,IAAM,eAAe,oBAAI,IAAoB;AAAA,EAC3C,CAAC,OAAO,EAAE;AAAA;AAAA,EACV,CAAC,OAAO,GAAG;AAAA;AAAA,EACX,CAAC,QAAQ,IAAI;AAAA;AAAA,EACb,CAAC,SAAS,IAAI;AAAA;AAChB,CAAC;AAeD,SAAS,kBAAkB,aAAqB,UAA8B;AAE5E,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa,+BAA+B;AAClD,QAAM,cAAc,aAAa;AACjC,QAAM,cAAc,cAAc;AAClC,QAAM,cAAc,cAAc,cAAc;AAChD,QAAM,iBAAiB,cAAc,cAAc;AACnD,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACvD,QAAM,cAAc,wBAAwB;AAK5C,QAAM,OAAO;AAAA,IAAkB;AAAA;AAAA,IAA6C;AAAA,EAAK;AAEjF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,iBAAiB;AAAA;AAAA,IAEjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAElB,wBAAwB;AAAA;AAAA,IAExB,mBAAmB;AAAA,EACrB;AACF;AAMA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC/F,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,YAAY,uBAAuB,cAAc,KAAK,IAAI;AAChE,QAAM,cAAc,KAAK,KAAK,YAAY,CAAC,IAAI;AAC/C,QAAM,QAAQ,uBAAuB,cAAc,IAAI;AACvD,cAAY,IAAI,OAAO,CAAC;AAC1B;AAEA,IAAM,iBAAiB,oBAAI,IAAoB;AAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC/F,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,YAAY,uBAAuB,cAAc,KAAK,IAAI;AAChE,QAAM,cAAc,KAAK,KAAK,YAAY,CAAC,IAAI;AAC/C,QAAM,QAAQ,uBAAuB,cAAc,IAAI;AACvD,iBAAe,IAAI,OAAO,CAAC;AAC7B;AAOO,IAAM,gBAAgB,OAAO,OAAO;AAAA,EACzC,OAAO,EAAE,aAAa,KAAM,UAAU,OAAW,OAAO,SAAU,aAAa,kCAAkC;AAAA,EACjH,OAAO,EAAE,aAAa,MAAM,UAAU,SAAW,OAAO,SAAU,aAAa,oCAAoC;AACrH,CAAU;AAQH,IAAM,iBAAgH,CAAC;AAC9H,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,gBAAgB,uBAAuB,kBAAkB,GAAG,EAAE;AAC3F,iBAAe,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,uBAAuB;AACzH;AACA,OAAO,OAAO,cAAc;AAQrB,IAAM,kBAAiH,CAAC;AAC/H,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,iBAAiB,wBAAwB,mBAAmB,GAAG,EAAE;AAC9F,kBAAgB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,iCAAiC;AACpI;AACA,OAAO,OAAO,eAAe;AAQtB,IAAM,mBAAkH,CAAC;AAChI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE;AACjG,mBAAiB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,2BAA2B;AAC/H;AACA,OAAO,OAAO,gBAAgB;AAM9B,SAAS,YAAY,SAAgB,aAAqB,mBAAwC;AAChG,QAAM,OAAO,YAAY;AACzB,QAAM,YAAY,sBAAsB,OAAO,gBAAgB;AAC/D,QAAM,aAAa,CAAC,QAAQ,sBAAsB;AAKlD,QAAM,YAAY,OAAO,uBAAuB;AAChD,QAAM,kBAAkB,aAAa,qCAChC,OAAO,uBAAuB;AACnC,QAAM,cAAc,OAAO,kBAAkB;AAC7C,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AAEpC,QAAM,iBAAiB,kBAAkB,cAAc,aAAa;AACpE,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL;AAAA,IACA,WAAW,OAAO,gBAAgB;AAAA,IAClC,cAAc,OAAO,gBAAgB;AAAA,IACrC,WAAW,OAAO,gBAAgB;AAAA,IAClC,aAAa,OAAO,kBAAkB;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB,OAAO,uBAAuB;AAAA,IAC/C,YAAY,OAAO,iBAAiB;AAAA,IACpC,sBAAsB,OAAO,6BAA6B;AAAA,IAC1D,uBAAuB,OAAO,8BAA8B;AAAA,IAC5D,0BAA0B,OAAO,kCAAkC;AAAA,IACnE,yBAAyB,OAAO,iCAAiC;AAAA,IACjE,oBAAoB,OAAO,KAAK;AAAA,IAChC,wBAAwB,OAAO,gCAAgC;AAAA,IAC/D,4BAA4B,OAAO,oCAAoC;AAAA,IACvE,kBAAkB,OAAO,yBAAyB;AAAA,IAClD,iBAAiB,OAAO,KAAK;AAAA,IAC7B,kBAAkB,OAAO,KAAK;AAAA,IAC9B,eAAe,OAAO,sBAAsB;AAAA,IAC5C,oBAAoB,OAAO,4BAA4B;AAAA,IACvD,oBAAoB,OAAO,2BAA2B;AAAA,IACtD,mBAAmB,OAAO,0BAA0B;AAAA,IACpD,yBAAyB,OAAO,iCAAiC;AAAA,IACjE,4BAA4B,OAAO,oCAAoC;AAAA,IACvE,sBAAsB,OAAO,6BAA6B;AAAA,IAC1D,wBAAwB,OAAO,gCAAgC;AAAA,IAC/D,+BAA+B,OAAO,sCAAsC;AAAA,IAC5E,8BAA8B,OAAO,sCAAsC;AAAA,IAC3E,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,mBAAmB,OAAO,2BAA2B;AAAA,IACrD,wBAAwB,OAAO,iCAAiC;AAAA,IAChE,0BAA0B,OAAO,KAAK;AAAA,IACtC,6BAA6B,OAAO,KAAK;AAAA,IACzC,0BAA0B,OAAO,KAAK;AAAA,IACtC,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc,aAAa,2BAA2B;AAAA,IAEtD,uBAAuB,CAAC;AAAA,IACxB,4BAA4B,OAAO,KAAK;AAAA,IACxC,gCAAgC,OAAO,KAAK;AAAA,EAC9C;AACF;AAgBA,SAAS,eAAe,aAAqB,aAAa,GAAe;AACvE,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA,IACjB;AAAA,IACA,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA;AAAA,IAC5B,gCAAgC;AAAA;AAAA,EAClC;AACF;AAOA,SAAS,cAAc,aAAiC;AACtD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAQA,SAAS,eAAe,aAAiC;AACvD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAUA,SAAS,gBAAgB,aAAiC;AACxD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA;AAAA,IAEZ,sBAAsB;AAAA;AAAA,IACtB,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA;AAAA,IACf,oBAAoB;AAAA;AAAA,IACpB,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAWA,SAAS,gBAAgB,aAAiC;AACxD,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA,IACZ,sBAAsB;AAAA;AAAA,IACtB,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe;AAAA;AAAA,IACf,oBAAoB;AAAA;AAAA,IACpB,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAOO,IAAM,0BAAyH,CAAC;AACvI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,yBAAyB,yBAAyB,oBAAoB,GAAG,EAAE;AACxG,0BAAwB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,wCAAwC;AACnJ;AACA,OAAO,OAAO,uBAAuB;AAO9B,IAAM,mBAAkH,CAAC;AAChI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACpG,QAAM,OAAO,gBAAgB,kBAAkB,yBAAyB,oBAAoB,GAAG,EAAE;AACjG,mBAAiB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,iBAAiB;AACrH;AACA,OAAO,OAAO,gBAAgB;AAQvB,IAAM,oBAAmH,CAAC;AACjI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AAC1H,QAAM,OAAO,gBAAgB,mBAAmB,0BAA0B,qBAAqB,GAAG,EAAE;AACpG,oBAAkB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,kBAAkB;AACvH;AACA,OAAO,OAAO,iBAAiB;AASxB,IAAM,oBAAmH,CAAC;AACjI,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAY;AACrF,QAAM,cAAc,KAAK,KAAK,IAAI,EAAE,IAAI;AACxC,QAAM,SAAS,+BAA+B,cAAc,IAAI,IAAI;AACpE,QAAM,cAAc,KAAK,KAAK,SAAS,CAAC,IAAI;AAC5C,QAAM,OAAO,wBAAwB,cAAc,IAAI,0BAA0B,sBAAsB,IAAI;AAC3G,oBAAkB,MAAM,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,MAAM,OAAO,aAAa,GAAG,CAAC,kBAAkB;AACvH;AACA,OAAO,OAAO,iBAAiB;AAaxB,IAAM,oBAAmH,OAAO,OAAO;AAAA,EAC5I,OAAQ,EAAE,aAAa,IAAO,UAAU,OAAW,OAAO,SAAU,aAAa,sCAAsC;AAAA,EACvH,OAAQ,EAAE,aAAa,KAAO,UAAU,OAAW,OAAO,SAAU,aAAa,0EAAqE;AAAA,EACtJ,QAAQ,EAAE,aAAa,MAAO,UAAU,QAAW,OAAO,UAAU,aAAa,yCAAyC;AAAA,EAC1H,OAAQ,EAAE,aAAa,MAAO,UAAU,SAAW,OAAO,SAAU,aAAa,wCAAwC;AAC3H,CAAC;AAOD,SAAS,uBAAuB,aAAiC;AAC/D,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAEA,SAAS,iBAAiB,aAAqB,SAA8B;AAK3E,QAAM,WAAW,gBAAgB,kBAAkB,yBAAyB,oBAAoB,aAAa,EAAE;AAC/G,QAAM,QAAQ,YAAY,UAAa,YAAY;AACnD,QAAM,YAAY,QAAQ,uBAAuB;AACjD,QAAM,YAAY,QAAQ,uBAAuB;AACjD,QAAM,cAAc,QAAQ,yBAAyB;AACrD,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW,QAAQ,MAAM;AAAA,IACzB,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB,QAAQ,8BAA8B;AAAA,IACvD,YAAY,QAAQ,wBAAwB;AAAA;AAAA;AAAA,IAG5C,sBAAsB,QAAQ,6BAA6B;AAAA,IAC3D,uBAAuB,QAAQ,KAAK;AAAA;AAAA,IACpC,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,yBAAyB,QAAQ,6BAA6B;AAAA,IAC9D,oBAAoB,QAAQ,8BAA8B;AAAA,IAC1D,wBAAwB,QAAQ,gCAAgC;AAAA,IAChE,4BAA4B,QAAQ,oCAAoC;AAAA,IACxE,kBAAkB,QAAQ,yBAAyB;AAAA,IACnD,iBAAiB,QAAQ,wBAAwB;AAAA,IACjD,kBAAkB,QAAQ,yBAAyB;AAAA,IACnD,eAAe,QAAQ,sBAAsB;AAAA,IAC7C,oBAAoB,QAAQ,4BAA4B;AAAA,IACxD,oBAAoB,QAAQ,2BAA2B;AAAA,IACvD,mBAAmB,QAAQ,0BAA0B;AAAA,IACrD,yBAAyB,QAAQ,iCAAiC;AAAA,IAClE,4BAA4B,QAAQ,oCAAoC;AAAA,IACxE,sBAAsB,QAAQ,6BAA6B;AAAA,IAC3D,wBAAwB,QAAQ,gCAAgC;AAAA,IAChE,+BAA+B,QAAQ,sCAAsC;AAAA,IAC7E,8BAA8B,QAAQ,KAAK;AAAA;AAAA,IAC3C,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,mBAAmB,QAAQ,KAAK;AAAA;AAAA,IAChC,wBAAwB,QAAQ,KAAK;AAAA;AAAA,IACrC,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,6BAA6B,QAAQ,KAAK;AAAA;AAAA,IAC1C,0BAA0B,QAAQ,KAAK;AAAA;AAAA,IACvC,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,cAAc;AAAA;AAAA;AAAA,IAId,uBAAuB,CAAC;AAAA,IACxB,4BAA4B,QAAQ,KAAK;AAAA,IACzC,gCAAgC,QAAQ,KAAK;AAAA,EAC/C;AACF;AAMA,SAAS,mBAAmB,aAAiC;AAC3D,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY;AAAA;AAAA;AAAA,IAEZ,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,oBAAoB;AAAA,IACpB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,YAAY;AAAA;AAAA,IAEZ,cAAc;AAAA;AAAA,IACd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AAUA,SAAS,kBAAkB,aAAqB,SAA8B;AAE5E,QAAM,QAAQ,YAAY;AAC1B,QAAM,cAAc,QAAQ,4BAA4B;AACxD,QAAM,YAAY,QAAQ,wBAAwB;AAClD,QAAM,YAAY;AAElB,QAAM,qBAAqB,QAAQ,MAAM;AACzC,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,qBAAqB,cAAc,aAAa;AACvE,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,CAAC,IAAI;AAEvD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA,IACd,WAAW;AAAA;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY,QAAQ,MAAM;AAAA;AAAA,IAC1B,sBAAsB,QAAQ,MAAM;AAAA;AAAA,IACpC,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA;AAAA,IAC1B,yBAAyB,QAAQ,MAAM;AAAA;AAAA,IACvC,oBAAoB;AAAA;AAAA,IACpB,wBAAwB;AAAA;AAAA,IACxB,4BAA4B;AAAA;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,IAClB,eAAe,QAAQ,MAAM;AAAA;AAAA,IAC7B,oBAAoB,QAAQ,MAAM;AAAA;AAAA,IAClC,oBAAoB;AAAA;AAAA,IACpB,mBAAmB;AAAA;AAAA,IACnB,yBAAyB;AAAA;AAAA,IACzB,4BAA4B;AAAA;AAAA,IAC5B,sBAAsB;AAAA;AAAA,IACtB,wBAAwB;AAAA;AAAA,IACxB,+BAA+B;AAAA;AAAA,IAC/B,8BAA8B;AAAA;AAAA,IAC9B,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,mBAAmB;AAAA;AAAA,IACnB,wBAAwB;AAAA;AAAA,IACxB,0BAA0B;AAAA;AAAA,IAC1B,6BAA6B;AAAA;AAAA,IAC7B,0BAA0B;AAAA;AAAA,IAC1B,iBAAiB;AAAA;AAAA,IACjB;AAAA,IACA,cAAc;AAAA;AAAA,IAEd,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA,EAClC;AACF;AASA,SAAS,kBAAkB,aAAqB,SAA6B;AAG3E,QAAM,SAAS,MAAM;AAEnB,UAAMC,eAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,UAAM,eAAe,2BAA2BA,eAAc,IAAI,cAAc;AAChF,UAAM,oBAAoB,KAAK,KAAK,eAAe,EAAE,IAAI;AACzD,UAAM,aAAa,oBAAoB,oBAAoB,cAAc,sBAAsB,sBAAsB,cAAc;AACnI,WAAO,YAAY;AAAA,EACrB,GAAG;AAEH,QAAM,YAAY,QAAQ,wBAAwB;AAClD,QAAM,cAAc,QAAQ,0BAA0B;AACtD,QAAM,YAAY,QAAQ,+BAA+B;AACzD,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,cAAc,cAAc;AAClC,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,YAAY,cAAc,aAAa;AAC9D,QAAM,YAAY,QAAQ,IAAI;AAC9B,QAAM,iBAAiB,KAAK,KAAK,iBAAiB,SAAS,IAAI;AAE/D,SAAO;AAAA,IACL,SAAS;AAAA,IACT,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMd,WAAW;AAAA,IACX,aAAa;AAAA;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,YAAY;AAAA,IAEzB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA;AAAA,IACjB,YAAY,QAAQ,MAAM;AAAA,IAC1B,sBAAsB,QAAQ,qCAAqC;AAAA,IACnE,uBAAuB;AAAA;AAAA,IACvB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA;AAAA,IACzB,oBAAoB;AAAA;AAAA,IACpB,wBAAwB,QAAQ,wCAAwC;AAAA,IACxE,4BAA4B;AAAA,IAC5B,kBAAkB;AAAA;AAAA,IAClB,iBAAiB,QAAQ,oCAAoC;AAAA,IAC7D,kBAAkB,QAAQ,qCAAqC;AAAA,IAC/D,eAAe,QAAQ,8BAA8B;AAAA,IACrD,oBAAoB,QAAQ,oCAAoC;AAAA,IAChE,oBAAoB;AAAA;AAAA,IACpB,mBAAmB,QAAQ,kCAAkC;AAAA,IAC7D,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,IAC5B,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,8BAA8B;AAAA,IAC9B,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB;AAAA,IACA,cAAc,QAAQ,MAAM;AAAA;AAAA,IAE5B,uBAAuB;AAAA,IACvB,4BAA4B;AAAA,IAC5B,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOhC,mBAAmB,gBAAgB;AAAA,EACrC;AACF;AAuBA,SAAS,eAAe,QAAoB,SAA6B;AACvE,MAAI,OAAO,cAAc,SAAS;AAChC,UAAM,IAAI;AAAA,MACR,gCAAgC,OAAO,WAAW,0BAA0B,OAAO,mBAClE,OAAO,SAAS,gBAAgB,OAAO,WAAW,gBAAgB,OAAO,WAAW;AAAA,IACvG;AAAA,EACF;AACA,QAAM,YAAY,OAAO,YAAY,OAAO,kBAAkB,OAAO,cAAc;AACnF,MAAI,YAAY,SAAS;AACvB,UAAM,IAAI;AAAA,MACR,sCAAsC,SAAS,0BAA0B,OAAO;AAAA,IAClF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAiB,MAAsC;AAMtF,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,WAAW,OAAW,QAAO,eAAe,kBAAkB,QAAQ,OAAO,GAAG,OAAO;AAI3F,QAAM,UAAU,eAAe,IAAI,OAAO;AAC1C,MAAI,YAAY,OAAW,QAAO,eAAe,mBAAmB,OAAO,GAAG,OAAO;AAGrF,QAAM,QAAQ,YAAY,IAAI,OAAO;AACrC,MAAI,UAAU,OAAW,QAAO,eAAe,iBAAiB,OAAO,OAAO,GAAG,OAAO;AAIxF,QAAM,QAAQ,mBAAmB,IAAI,OAAO;AAC5C,MAAI,UAAU,OAAW,QAAO,eAAe,uBAAuB,KAAK,GAAG,OAAO;AAOrF,QAAM,QAAQ,WAAW,IAAI,OAAO;AACpC,MAAI,UAAU,OAAW,QAAO,eAAe,gBAAgB,KAAK,GAAG,OAAO;AAG9E,QAAM,QAAQ,YAAY,IAAI,OAAO;AACrC,MAAI,UAAU,OAAW,QAAO,eAAe,gBAAgB,KAAK,GAAG,OAAO;AAI9E,QAAM,OAAO,UAAU,IAAI,OAAO;AAClC,MAAI,SAAS,OAAW,QAAO,eAAe,eAAe,IAAI,GAAG,OAAO;AAG3E,QAAM,MAAM,SAAS,IAAI,OAAO;AAChC,MAAI,QAAQ,OAAW,QAAO,eAAe,YAAY,GAAG,GAAG,GAAG,OAAO;AAKzE,QAAM,OAAO,UAAU,IAAI,OAAO;AAClC,MAAI,SAAS,QAAW;AACtB,QAAI,QAAQ,KAAK,UAAU,IAAI;AAC7B,YAAM,UAAU,UAAU,MAAM,CAAC;AACjC,UAAI,YAAY,EAAG,QAAO,eAAe,cAAc,IAAI,GAAG,OAAO;AAAA,IACvE;AACA,WAAO,eAAe,eAAe,MAAM,CAAC,GAAG,OAAO;AAAA,EACxD;AAKA,QAAM,QAAQ,iBAAiB,IAAI,OAAO;AAC1C,MAAI,UAAU,OAAW,QAAO,eAAe,eAAe,OAAO,EAAE,GAAG,OAAO;AAGjF,QAAM,MAAM,SAAS,IAAI,OAAO;AAChC,MAAI,QAAQ,OAAW,QAAO,eAAe,YAAY,GAAG,GAAG,GAAG,OAAO;AAGzE,QAAM,OAAO,gBAAgB,IAAI,OAAO;AAIxC,MAAI,SAAS,OAAW,QAAO,eAAe,YAAY,GAAG,MAAM,oBAAoB,GAAG,OAAO;AAEjG,SAAO;AACT;AAUO,SAAS,aAAa,SAAiB;AAC5C,QAAM,SAAS,iBAAiB,OAAO;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,EAAE,aAAa,OAAO,aAAa,aAAa,OAAO,aAAa,aAAa,OAAO,YAAY;AAC7G;AAKA,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAChC,IAAM,6BAA6B;AAGnC,IAAM,4BAA4B;AAClC,IAAM,6BAA6B;AACnC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,6BAA6B;AAMnC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,+BAA+B;AACrC,IAAM,+BAA+B;AACrC,IAAM,2BAA2B;AACjC,IAAM,mCAAmC;AACzC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAKnC,IAAM,uCAAuC;AAC7C,IAAM,mCAAmC;AACzC,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AACvC,IAAM,gCAAgC;AACtC,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,8BAA8B;AACpC,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AAChC,IAAM,4CAA4C;AAClD,IAAM,mCAAmC;AAOzC,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AACrB,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,2BAA2B;AACjC,IAAM,iBAAiB;AACvB,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;AAsLxB,IAAK,cAAL,kBAAKC,iBAAL;AACL,EAAAA,0BAAA,UAAO,KAAP;AACA,EAAAA,0BAAA,QAAK,KAAL;AAFU,SAAAA;AAAA,GAAA;AAqFZ,eAAsB,UACpB,YACA,YACA,eACqB;AACrB,QAAM,OAAO,MAAM,WAAW,eAAe,UAAU;AACvD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,2BAA2B,WAAW,SAAS,CAAC,EAAE;AAAA,EACpE;AACA,MAAI,iBAAiB,CAAC,KAAK,MAAM,OAAO,aAAa,GAAG;AACtD,UAAM,IAAI;AAAA,MACR,sBAAsB,WAAW,SAAS,CAAC,gBAAgB,KAAK,MAAM,SAAS,CAAC,iBAAiB,cAAc,SAAS,CAAC;AAAA,IAC3H;AAAA,EACF;AACA,SAAO,IAAI,WAAW,KAAK,IAAI;AACjC;AAMO,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAE9B,SAAS,yBAAyB,QAAsB,aAA6B;AAC1F,QAAM,SAAS,OAAO;AACtB,MAAI,WAAW,GAAI,QAAO;AAC1B,MAAI,OAAO,gBAAgB,GAAI,QAAO;AACtC,MAAI,UAAU,eAAgB,QAAO;AACrC,QAAM,UAAU,cAAc,OAAO,oBACjC,cAAc,OAAO,oBACrB;AACJ,MAAI,WAAW,OAAO,YAAa,QAAO;AAC1C,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAW,QAAQ,UAAW,OAAO;AAC3C,QAAM,SAAS,iBAAiB;AAChC,SAAO,SAAS,SAAS,SAAS;AACpC;AAMO,SAAS,UAAU,MAA0B;AAClD,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM,EAAE;AAAA,EAC3E;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,KAAK,SAAS,OAAO,EAAG,OAAM,IAAI,MAAM,+BAA+B;AAC3E,SAAO,UAAU,MAAM,IAAI;AAC7B;AAEO,SAAS,sBAAsB,MAA0B;AAC9D,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,wDAAwD,KAAK,MAAM,EAAE;AAAA,EACvF;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,KAAK,SAAS,OAAO,GAAI,OAAM,IAAI,MAAM,2CAA2C;AACxF,SAAO,UAAU,MAAM,OAAO,CAAC;AACjC;AASO,SAAS,YAAY,MAA8B;AACxD,MAAI,KAAK,SAAS,eAAe;AAC/B,UAAM,IAAI,MAAM,mCAAmC,KAAK,MAAM,MAAM,aAAa,EAAE;AAAA,EACrF;AAEA,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,MAAI,UAAU,OAAO;AACnB,UAAM,IAAI,MAAM,gCAAgC,MAAM,SAAS,EAAE,CAAC,SAAS,MAAM,SAAS,EAAE,CAAC,EAAE;AAAA,EACjG;AAEA,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,QAAM,OAAO,OAAO,MAAM,EAAE;AAC5B,QAAM,QAAQ,OAAO,MAAM,EAAE;AAC7B,QAAM,QAAQ,IAAIC,WAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAGjD,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,QAAM,OAAO,SAAS,OAAO,cAAc;AAC3C,QAAM,QAAQ,UAAU,MAAM,IAAI;AAClC,QAAM,oBAAoB,UAAU,MAAM,OAAO,CAAC;AAElD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAQ,mBAAmB;AAAA,IACtC,SAAS,QAAQ,OAAU;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA2DA,SAAS,kBAAkB,MAAkB,WAAiC;AAC5E,QAAM,mBAAmB;AACzB,MAAI,KAAK,SAAS,YAAY,kBAAkB;AAC9C,UAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,MAAM,YAAY,gBAAgB,EAAE;AAAA,EAC3G;AAEA,QAAM,IAAI;AACV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AACjE,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,oBAAoB,UAAU,MAAM,IAAI,EAAE;AAChD,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,qBAAqB,OAAO,MAAM,IAAI,GAAG;AAC/C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AACnC,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AACrE,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAKpD,QAAM,eAAe,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG;AACnD,QAAM,UAAU,aAAa,KAAK,OAAK,MAAM,CAAC,IAAI,IAAIA,WAAU,YAAY,IAAI;AAEhF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,2BAA2B;AAAA;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,aAAa;AAAA;AAAA,IACb,eAAe;AAAA,IACf,2BAA2B;AAAA,IAC3B,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C,WAAW,UAAU,MAAM,IAAI,GAAG;AAAA,IAClC,wBAAwB;AAAA;AAAA,IACxB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;AAyDA,SAAS,kBAAkB,MAAkB,WAAiC;AAC5E,QAAM,mBAAmB;AACzB,MAAI,KAAK,SAAS,YAAY,kBAAkB;AAC9C,UAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,MAAM,YAAY,gBAAgB,EAAE;AAAA,EAC3G;AAEA,QAAM,IAAI;AACV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AACjE,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC/D,QAAM,oBAAoB,UAAU,MAAM,IAAI,EAAE;AAChD,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,qBAAqB,OAAO,MAAM,IAAI,GAAG;AAC/C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AACnC,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AACrE,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AAEnD,QAAM,eAAe,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG;AACnD,QAAM,UAAU,aAAa,KAAK,OAAK,MAAM,CAAC,IAAI,IAAIA,WAAU,YAAY,IAAI;AAEhF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,2BAA2B;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,eAAe;AAAA,IACf,2BAA2B;AAAA,IAC3B,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C,WAAW,UAAU,MAAM,IAAI,GAAG;AAAA,IAClC,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;AAEO,SAAS,YAAY,MAAkB,YAA8C;AAC1F,MAAI,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,MAAM,OAAO;AACpD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,QAAM,SAAS,eAAe,SAAY,aAAa,iBAAiB,KAAK,QAAQ,IAAI;AACzF,QAAM,YAAY,SAAS,OAAO,eAAe;AACjD,QAAM,YAAY,SAAS,OAAO,YAAY;AAI9C,QAAM,WAAW,UAAU,OAAO,gBAAgB;AAClD,MAAI,UAAU;AACZ,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAKA,QAAM,WAAW,WAAW,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACjG,MAAI,UAAU;AACZ,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAIA,QAAM,mBAAmB;AACzB,QAAM,SAAS,YAAY,KAAK,IAAI,WAAW,gBAAgB;AAC/D,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,IAAI,MAAM,mCAAmC,KAAK,MAAM,MAAM,MAAM,EAAE;AAAA,EAC9E;AAEA,MAAI,MAAM;AAEV,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AACjE,SAAO;AAEP,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAC9D,SAAO;AAEP,QAAM,cAAc,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAC9D,SAAO;AAEP,QAAM,oBAAoB,UAAU,MAAM,GAAG;AAC7C,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,qBAAqB,OAAO,MAAM,GAAG;AAC3C,SAAO;AAEP,QAAM,SAAS,OAAO,MAAM,GAAG;AAC/B,SAAO;AAEP,QAAM,YAAY,UAAU,MAAM,GAAG;AACrC,SAAO;AAGP,QAAM,sBAAsB,UAAU,MAAM,GAAG;AAC/C,SAAO;AAEP,QAAM,cAAc,UAAU,MAAM,GAAG;AACvC,SAAO;AAEP,QAAM,4BAA4B,WAAW,MAAM,GAAG;AACtD,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAQP,QAAM,cAAc,WAAW,MAAM,GAAG;AACxC,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,4BAA4B,UAAU,MAAM,GAAG;AACrD,SAAO;AAEP,QAAM,gBAAgB,UAAU,MAAM,GAAG;AACzC,SAAO;AAEP,QAAM,iBAAiB,UAAU,MAAM,GAAG;AAC1C,SAAO;AAEP,QAAM,YAAY,WAAW,MAAM,GAAG;AACtC,SAAO;AAEP,QAAM,YAAY,WAAW,MAAM,GAAG;AACtC,SAAO;AAEP,QAAM,gBAAgB,WAAW,MAAM,GAAG;AAC1C,SAAO;AAGP,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC;AAClE,SAAO;AAEP,QAAM,mBAAmB,UAAU,MAAM,GAAG;AAC5C,SAAO;AAEP,QAAM,qBAAqB,UAAU,MAAM,GAAG;AAC9C,SAAO;AAGP,QAAM,sBAAsB,UAAU,MAAM,GAAG;AAC/C,SAAO;AAEP,QAAM,uBAAuB,UAAU,MAAM,GAAG;AAChD,SAAO;AAGP,QAAM,qBAAqB,UAAU,MAAM,GAAG;AAC9C,SAAO;AAEP,QAAM,YAAY,UAAU,MAAM,GAAG;AACrC,SAAO;AAGP,QAAM,YAAY,YAAY,YAAY;AAE1C,MAAI,yBAAyB;AAC7B,MAAI,mBAAmB;AACvB,MAAI,wBAAwB;AAC5B,MAAI,oBAAoB;AACxB,MAAI,cAAc;AAClB,MAAI,eAAe;AACnB,MAAI,wBAAwB;AAC5B,MAAI,cAAc;AAClB,MAAI,qBAAqB;AACzB,MAAI,mBAAmB;AAEvB,MAAI,aAAa,IAAI;AAMnB,wBAAoB,UAAU,MAAM,GAAG;AACvC,WAAO;AAEP,kBAAc,UAAU,MAAM,GAAG;AACjC,WAAO;AAEP,6BAAyB,OAAO,MAAM,GAAG,MAAM;AAC/C,WAAO;AACP,WAAO;AACP,uBAAmB,UAAU,MAAM,GAAG;AACtC,WAAO;AACP,WAAO;AACP,4BAAwB,UAAU,MAAM,GAAG;AAC3C,WAAO;AAEP,QAAI,aAAa,IAAI;AACnB,8BAAwB,UAAU,MAAM,GAAG;AAI3C,UAAI,aAAa,IAAI;AACnB,cAAM,SAAS,MAAM;AACrB,sBAAc,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC,GAAG,CAAC;AAClD,6BAAqB,UAAU,MAAM,SAAS,CAAC;AAE/C,2BAAmB,KAAK,SAAS,EAAE,IAAK,KAAK,SAAS,EAAE,KAAK,IAAM,KAAK,SAAS,EAAE,KAAK;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AAKA,MAAI,UAA4B;AAChC,QAAM,mBAAmB;AACzB,MAAI,aAAa,mBAAmB,MAAM,KAAK,UAAU,YAAY,mBAAmB,IAAI;AAC1F,UAAM,eAAe,KAAK,SAAS,YAAY,kBAAkB,YAAY,mBAAmB,EAAE;AAElG,QAAI,aAAa,KAAK,OAAK,MAAM,CAAC,GAAG;AACnC,gBAAU,IAAIA,WAAU,YAAY;AAAA,IACtC;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUO,SAAS,YAAY,MAAkB,YAA4C;AACxF,QAAM,SAAS,eAAe,SAAY,aAAa,iBAAiB,KAAK,QAAQ,IAAI;AACzF,QAAM,YAAY,SAAS,OAAO,YAAY;AAC9C,QAAM,YAAY,SAAS,OAAO,kBAAkB;AACpD,QAAM,aAAa,SAAS,OAAO,aAAa;AAChD,QAAM,OAAO,YAAY;AAIzB,QAAM,mBAAmB,cAAc,MAAM,MAAM;AACnD,MAAI,KAAK,SAAS,OAAO,kBAAkB;AACzC,UAAM,IAAI,MAAM,uCAAuC,KAAK,MAAM,MAAM,OAAO,gBAAgB,EAAE;AAAA,EACnG;AAIA,QAAM,iBAAiB,eAAe,sBAAsB,eAAe;AAC3E,QAAM,iBAAiB,WAAW,QAAQ,WAAW,UACnD,OAAO,cAAc,yBACrB,eAAe;AAKjB,QAAM,aAAa,CAAC,kBAAkB,WAAW,QAAQ,WAAW,UACjE,OAAO,cAAc,wBAAyB,eAAe;AAGhE,QAAM,SAAqB;AAAA,IACzB,mBAAmB,iBACf,UAAU,MAAM,OAAO,uBAAuB,IAC9C,iBACA,UAAU,MAAM,OAAO,uBAAuB,IAC9C,UAAU,MAAM,OAAO,wBAAwB;AAAA,IACnD,sBAAsB,iBAClB,UAAU,MAAM,OAAO,oCAAoC,IAC3D,iBACA,UAAU,MAAM,OAAO,CAAC,IACxB,UAAU,MAAM,OAAO,6BAA6B;AAAA,IACxD,kBAAkB,iBACd,UAAU,MAAM,OAAO,gCAAgC,IACvD,iBACA,UAAU,MAAM,OAAO,CAAC,IACxB,UAAU,MAAM,OAAO,yBAAyB;AAAA,IACpD,eAAe,iBACX,UAAU,MAAM,OAAO,6BAA6B,IACpD,iBACA,UAAU,MAAM,OAAO,EAAE,IACzB,UAAU,MAAM,OAAO,sBAAsB;AAAA,IACjD,aAAa,iBACT,UAAU,MAAM,OAAO,8BAA8B,IACrD,iBACA,UAAU,MAAM,OAAO,8BAA8B,IACrD,UAAU,MAAM,OAAO,uBAAuB;AAAA,IAClD,eAAe,iBACX,KACA,iBACA,WAAW,MAAM,OAAO,EAAE,IAC1B,WAAW,MAAM,OAAO,0BAA0B;AAAA;AAAA,IAEtD,wBAAwB;AAAA,IACxB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,sBAAsB;AAAA,IACtB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAEA,MAAI,gBAAgB;AAGlB,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,yBAAyB;AAChC,WAAO,wBAAwB;AAC/B,WAAO,yBAAyB,UAAU,MAAM,OAAO,gCAAgC;AACvF,WAAO,oBAAoB,UAAU,MAAM,OAAO,6BAA6B;AAC/E,WAAO,oBAAoB,WAAW,MAAM,OAAO,6BAA6B;AAChF,WAAO,uBAAuB,UAAU,MAAM,OAAO,yCAAyC;AAC9F,WAAO,oBAAoB,WAAW,MAAM,OAAO,yBAAyB;AAC5E,WAAO,oBAAoB;AAC3B,WAAO,kBAAkB,WAAW,MAAM,OAAO,2BAA2B;AAC5E,WAAO,kBAAkB,WAAW,MAAM,OAAO,2BAA2B;AAC5E,WAAO,iBAAiB;AAAA,EAC1B,WAAW,gBAAgB;AAEzB,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAC5D,WAAO,iBAAiB,WAAW,MAAM,OAAO,iCAAiC;AAGjF,WAAO,yBAAyB;AAChC,WAAO,wBAAyB;AAEhC,WAAO,yBAAyB,UAAU,MAAM,OAAO,EAAE;AACzD,WAAO,oBAAyB,UAAU,MAAM,OAAO,EAAE;AACzD,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,uBAAyB;AAChC,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,oBAAyB,WAAW,MAAM,OAAO,EAAE;AAC1D,WAAO,kBAAyB,WAAW,MAAM,OAAO,GAAG;AAC3D,WAAO,kBAAyB,WAAW,MAAM,OAAO,GAAG;AAAA,EAC7D,WAAW,YAAY;AAErB,WAAO,wBAAwB,WAAW,MAAM,OAAO,0BAA0B;AACjF,WAAO,yBAAyB,UAAU,MAAM,OAAO,0BAA0B;AACjF,WAAO,oBAAoB,UAAU,MAAM,OAAO,4BAA4B;AAC9E,WAAO,oBAAoB,WAAW,MAAM,OAAO,4BAA4B;AAC/E,WAAO,oBAAoB,WAAW,MAAM,OAAO,wBAAwB;AAC3E,WAAO,oBAAoB,WAAW,MAAM,OAAO,gCAAgC;AACnF,WAAO,kBAAkB,WAAW,MAAM,OAAO,0BAA0B;AAC3E,WAAO,kBAAkB,WAAW,MAAM,OAAO,0BAA0B;AAC3E,WAAO,iBAAiB,WAAW,MAAM,OAAO,0BAA0B;AAE1E,WAAO,OAAO,OAAO;AACrB,WAAO,OAAO,OAAO;AAAA,EACvB,WAAW,cAAc,KAAK;AAE5B,WAAO,yBAAyB,WAAW,MAAM,OAAO,yBAAyB;AACjF,WAAO,wBAAwB,WAAW,MAAM,OAAO,0BAA0B;AACjF,WAAO,yBAAyB,UAAU,MAAM,OAAO,8BAA8B;AACrF,WAAO,oBAAoB,UAAU,MAAM,OAAO,8BAA8B;AAChF,WAAO,oBAAoB,WAAW,MAAM,OAAO,8BAA8B;AACjF,WAAO,uBAAuB,UAAU,MAAM,OAAO,6BAA6B;AAClF,WAAO,oBAAoB,WAAW,MAAM,OAAO,0BAA0B;AAE7E,WAAO,OAAO,OAAO;AACrB,WAAO,OAAO,OAAO;AAAA,EACvB;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,MAA+B;AACzD,MAAI,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,MAAM,OAAO;AACpD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACA,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,oCAAoC;AAAA,EACnG;AACA,MAAI,KAAK,SAAS,OAAO,aAAa;AACpC,UAAM,IAAI,MAAM,gDAAgD,KAAK,MAAM,MAAM,OAAO,WAAW,GAAG;AAAA,EACxG;AAEA,QAAM,OAAO,OAAO;AAGpB,QAAM,WAAW,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACtF,QAAM,WAAW,CAAC,aAAa,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB,+BAA+B,OAAO,cAAc,qBAAqB,OAAO,cAAc;AAKlM,QAAM,WAAW,OAAO,gBAAgB;AACxC,MAAI,YAAY,UAAU;AACxB,UAAM,QAAQ,OAAO,cAAc,yBAAyB;AAE5D,UAAM,iBAAiB,WAAW,qCACV,QAAQ,qCAAqC;AACrE,UAAM,gBAAgB,WAAW,oCACT,QAAQ,oCAAoC;AACpE,UAAM,UAAU,WAAW,8BACT,QAAQ,8BAA8B;AACxD,UAAM,eAAe,WAAW,oCACR,QAAQ,oCAAoC;AACpE,UAAM,gBAAgB,WAAW,4CACT,QAAQ,4CAA4C;AAC5E,UAAM,YAAY,WAAW,sCACL,QAAQ,sCAAsC;AACtE,UAAM,iBAAiB,WAAW,0CACV,QAAQ,0CAA0C;AAC1E,UAAM,gBAAgB,WAAW,qCACT,QAAQ,qCAAqC;AACrE,UAAM,cAAc,WAAW,mCACP,QAAQ,mCAAmC;AACnE,UAAM,eAAe,WAAW,oCACR,QAAQ,oCAAoC;AAGpE,UAAM,mBAAmB,WAAW,MACR,QAAQ,MAAM;AAC1C,UAAM,oBAAoB,WAAW,MACT,QAAQ,MAAM;AAC1C,UAAM,uBAAuB,WAAW,4CACZ,QAAQ,MAAM;AAE1C,UAAM,mBAAmB,WAAW,yCACR,QAAQ,wCAAwC;AAC5E,UAAM,cAAc,WAAW,kCACH,QAAQ,kCAAkC;AACtE,UAAM,eAAe,WAAW,oCACJ,QAAQ,oCAAoC;AACxE,UAAM,gBAAgB,WAAW,qCACL,QAAQ,qCAAqC;AAEzE,UAAM,SAAS,WAAW,MAAM,OAAO,YAAY;AACnD,UAAM,UAAU,WAAW,MAAM,OAAO,aAAa;AAGrD,UAAM,YAAY,OAAO,kBAAkB,OAAO,cAAc;AAEhE,WAAO;AAAA,MACL,OAAO,WAAW,MAAM,IAAI;AAAA,MAC5B,eAAe;AAAA,QACb,SAAS,WAAW,MAAM,OAAO,EAAE;AAAA,QACnC,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,cAAc;AAAA,MAChB;AAAA,MACA,aAAa,UAAU,MAAM,OAAO,cAAc;AAAA,MAClD,mBAAmB;AAAA;AAAA,MACnB,iBAAiB;AAAA,MACjB,2BAA2B;AAAA;AAAA,MAC3B,eAAe;AAAA;AAAA,MACf,YAAY,OAAO,MAAM,OAAO,aAAa,MAAM,IAAI,IAAI;AAAA,MAC3D,eAAe,UAAU,MAAM,OAAO,gBAAgB;AAAA,MACtD,wBAAwB;AAAA,MACxB,mBAAmB,SAAS;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,MAAM,WAAW,MAAM,OAAO,OAAO;AAAA,MACrC,WAAW,WAAW,MAAM,OAAO,YAAY;AAAA,MAC/C,kBAAkB,WAAW,MAAM,OAAO,aAAa;AAAA,MACvD,WAAW;AAAA,MACX,UAAU,UAAU,MAAM,OAAO,WAAW;AAAA,MAC5C,oBAAoB;AAAA,MACpB,uBAAuB;AAAA,MACvB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,sBAAsB;AAAA,MACtB,qBAAqB;AAAA,MACrB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,eAAe,UAAU,MAAM,OAAO,cAAc;AAAA,MACpD,iBAAiB,UAAU,MAAM,OAAO,SAAS;AAAA,MACjD,eAAe;AAAA;AAAA;AAAA,MAGf,UAAU,WAAW,MAAM,OAAO,WAAW;AAAA,MAC7C,WAAW,WAAW,MAAM,OAAO,YAAY;AAAA,MAC/C,oBAAoB,UAAU,MAAM,OAAO,SAAS;AAAA,MACpD,YAAY,UAAU,MAAM,OAAO,aAAa;AAAA,MAChD,4BAA4B,WAAW,MAAM,OAAO,gBAAgB;AAAA,MACpE,6BAA6B,WAAW,MAAM,OAAO,iBAAiB;AAAA,MACtE,mBAAmB,UAAU,MAAM,OAAO,oBAAoB;AAAA,IAChE;AAAA,EACF;AAIA,QAAM,4BAA4B,WAC9B,WAAW,MAAM,OAAO,OAAO,uBAAuB,IACtD,UAAU,MAAM,OAAO,OAAO,uBAAuB;AAEzD,SAAO;AAAA,IACL,OAAO,WAAW,MAAM,IAAI;AAAA,IAC5B,eAAe;AAAA,MACb,SAAS,WAAW,MAAM,OAAO,OAAO,kBAAkB;AAAA;AAAA,MAE1D,YAAY,OAAO,wBACf,WAAW,MAAM,OAAO,OAAO,qBAAqB,EAAE,IACtD;AAAA,MACJ,iBAAiB,OAAO,wBACpB,WAAW,MAAM,OAAO,OAAO,0BAA0B,IACzD;AAAA,MACJ,cAAc,OAAO,wBACjB,UAAU,MAAM,OAAO,OAAO,8BAA8B,IAC5D;AAAA,IACN;AAAA,IACA,aAAa,UAAU,MAAM,OAAO,OAAO,oBAAoB;AAAA,IAC/D,mBAAmB,OAAO,yBAAyB,IAC7C,OAAO,4BAA4B,KAAK,OAAO,2BAA2B,OAAO,0BAA0B,IACzG,OAAO,UAAU,MAAM,OAAO,OAAO,qBAAqB,CAAC,IAC3D,WAAW,MAAM,OAAO,OAAO,qBAAqB,IACxD;AAAA,IACJ,iBAAiB,OAAO,4BAA4B,IAChD,UAAU,MAAM,OAAO,OAAO,wBAAwB,IAAI;AAAA,IAC9D;AAAA,IACA,eAAe,WACX,WAAW,MAAM,OAAO,OAAO,uBAAuB,IACtD;AAAA,IACJ,YAAY,WACP,OAAO,MAAM,OAAO,OAAO,0BAA0B,EAAE,MAAM,IAAI,IAAI,IACtE;AAAA,IACJ,eAAe,OAAO,0BAA0B,IAC5C,UAAU,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC5D,wBAAwB,OAAO,8BAA8B,IACzD,UAAU,MAAM,OAAO,OAAO,0BAA0B,IAAI;AAAA,IAChE,mBAAmB,OAAO,oBAAoB,IAC1C,WAAW,MAAM,OAAO,OAAO,gBAAgB,IAAI;AAAA,IACvD,QAAQ,OAAO,mBAAmB,IAC9B,WAAW,MAAM,OAAO,OAAO,eAAe,IAAI;AAAA,IACtD,SAAS,OAAO,oBAAoB,IAChC,WAAW,MAAM,OAAO,OAAO,gBAAgB,IAAI;AAAA,IACvD,MAAM,WAAW,MAAM,OAAO,OAAO,aAAa;AAAA,IAClD,WAAW,WAAW,MAAM,OAAO,OAAO,kBAAkB;AAAA,IAC5D,kBAAkB,WACd,WAAW,MAAM,OAAO,qCAAqC,IAC7D;AAAA,IACJ,WAAW,OAAO,sBAAsB,IACpC,UAAU,MAAM,OAAO,OAAO,kBAAkB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAClC,UAAU,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACvD,oBAAoB,OAAO,2BAA2B,IAClD,UAAU,MAAM,OAAO,OAAO,uBAAuB,IAAI;AAAA,IAC7D,uBAAuB,OAAO,8BAA8B,IACxD,UAAU,MAAM,OAAO,OAAO,0BAA0B,IAAI;AAAA,IAChE,aAAa,OAAO,wBAAwB,IACxC,UAAU,MAAM,OAAO,OAAO,oBAAoB,IAAI;AAAA,IAC1D,eAAe,OAAO,0BAA0B,IAC5C,UAAU,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC5D,sBAAsB,OAAO,iCAAiC,IAC1D,UAAU,MAAM,OAAO,OAAO,6BAA6B,IAAI;AAAA,IACnE,qBAAqB,OAAO,gCAAgC,IACxD,UAAU,MAAM,OAAO,OAAO,4BAA4B,IAAI;AAAA,IAClE,UAAU,OAAO,qBAAqB,IAClC,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAClC,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IACxD,UAAU,OAAO,qBAAqB,IAAI,WAAW,MAAM,OAAO,OAAO,iBAAiB,IAAI;AAAA,IAC9F,eAAe,OAAO,0BAA0B,IAAI,WAAW,MAAM,OAAO,OAAO,sBAAsB,IAAI;AAAA,IAC7G,iBAAiB,OAAO,4BAA4B,IAChD,KAAK,OAAO,OAAO,wBAAwB,MAAM,IACjD;AAAA,IACJ,oBAAoB,OAAO,+BAA+B,IACtD,UAAU,MAAM,OAAO,OAAO,2BAA2B,IAAI;AAAA,IACjE,iBAAiB,OAAO,4BAA4B,IAChD,UAAU,MAAM,OAAO,OAAO,wBAAwB,IAAI;AAAA,IAC9D,aAAa,OAAO,sBAAsB,IACtC,UAAU,MAAM,OAAO,OAAO,kBAAkB,IAAI;AAAA;AAAA;AAAA,IAGxD,eAAe,WACX,UAAU,MAAM,OAAO,OAAO,kBAAkB,EAAE,IAClD;AAAA,IACJ,kBAAkB,MAAM;AACtB,UAAI,OAAO,aAAa,GAAI,QAAO;AACnC,YAAM,KAAK,OAAO;AAClB,aAAO,UAAU,MAAM,OAAO,OAAO,kBAAkB,KAAK,CAAC;AAAA,IAC/D,GAAG;AAAA,IACH,gBAAgB,MAAM;AACpB,UAAI,OAAO,aAAa,GAAI,QAAO;AACnC,YAAM,KAAK,OAAO;AAClB,YAAM,aAAa,OAAO,kBAAkB,KAAK;AACjD,aAAO,UAAU,MAAM,OAAO,KAAK,MAAM,aAAa,KAAK,CAAC,IAAI,CAAC;AAAA,IACnE,GAAG;AAAA;AAAA,IAGH,UAAU;AAAA,IACV,WAAW;AAAA,IACX,oBAAoB;AAAA,IACpB,YAAY;AAAA,IACZ,4BAA4B;AAAA,IAC5B,6BAA6B;AAAA,IAC7B,mBAAmB;AAAA,EACrB;AACF;AASO,SAAS,iBAAiB,MAA4B;AAC3D,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,EAAE;AAE5E,QAAM,OAAO,OAAO,YAAY,OAAO;AACvC,MAAI,KAAK,SAAS,OAAO,OAAO,cAAc,GAAG;AAC/C,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,QAAM,OAAiB,CAAC;AACxB,WAAS,OAAO,GAAG,OAAO,OAAO,aAAa,QAAQ;AACpD,UAAM,OAAO,UAAU,MAAM,OAAO,OAAO,CAAC;AAC5C,QAAI,SAAS,GAAI;AACjB,aAAS,MAAM,GAAG,MAAM,IAAI,OAAO;AACjC,UAAK,QAAQ,OAAO,GAAG,IAAK,IAAI;AAC9B,aAAK,KAAK,OAAO,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,cAAc,MAAkB,KAAsB;AACpE,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,OAAO,OAAO,YAAa,QAAO;AAC3E,QAAM,OAAO,OAAO,YAAY,OAAO;AACvC,QAAM,OAAO,KAAK,MAAM,MAAM,EAAE;AAChC,QAAM,MAAM,MAAM;AAClB,QAAM,OAAO,UAAU,MAAM,OAAO,OAAO,CAAC;AAC5C,UAAS,QAAQ,OAAO,GAAG,IAAK,QAAQ;AAC1C;AAKO,SAAS,gBAAgB,SAAyB;AACvD,QAAM,SAAS,iBAAiB,OAAO;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,cAAc,UAAU,OAAO;AACrC,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO,KAAK,MAAM,cAAc,OAAO,WAAW;AACpD;AAKO,SAAS,aAAa,MAAkB,KAAsB;AACnE,QAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kCAAkC,KAAK,MAAM,EAAE;AAE5E,QAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,OAAO,QAAQ;AACtD,UAAM,IAAI,MAAM,+BAA+B,GAAG,UAAU,SAAS,CAAC,GAAG;AAAA,EAC3E;AAEA,QAAM,OAAO,OAAO,cAAc,MAAM,OAAO;AAC/C,MAAI,KAAK,SAAS,OAAO,OAAO,aAAa;AAC3C,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAeA,QAAM,WAAW,OAAO,gBAAgB,uBACvB,OAAO,gBAAgB,2BACvB,OAAO,gBAAgB;AACxC,QAAM,WAAW,CAAC,aAAa,OAAO,gBAAgB,uBAAuB,OAAO,gBAAgB;AACpG,QAAM,YAAY,CAAC,YAAY,CAAC,YAAY,OAAO,gBAAgB,6BAA6B,OAAO,cAAc;AACrH,QAAM,UAAU,CAAC,YAAY,CAAC,YAAY,CAAC,cAAc,OAAO,cAAc,oBAAoB,OAAO,cAAc,0BAA0B,OAAO,gBAAgB,sBAAsB,OAAO,gBAAgB;AACrN,QAAM,QAAQ,CAAC,YAAY,CAAC,aAAa,OAAO,eAAe,OAAO,WAAW;AAEjF,MAAI,UAAU;AASZ,UAAM,QAAQ,OAAO,gBAAgB,2BACvB,OAAO,gBAAgB;AACrC,UAAM,KAAK,QAAQ,IAAI;AACvB,UAAM,KAAK,QAAQ,KAAK;AAExB,UAAMC,YAAW,OAAO,MAAM,OAAO,oBAAoB;AACzD,UAAMC,QAAOD,cAAa,IAAI,aAAiB;AAE/C,WAAO;AAAA,MACL,MAAAC;AAAA,MACA,WAAW;AAAA;AAAA,MACX,SAAS,WAAW,MAAM,OAAO,uBAAuB;AAAA,MACxD,KAAK,WAAW,MAAM,OAAO,sBAAsB,EAAE;AAAA,MACrD,aAAa,WAAW,MAAM,OAAO,+BAA+B,EAAE;AAAA,MACtE,qBAAqB;AAAA;AAAA,MACrB,oBAAoB;AAAA;AAAA,MACpB,cAAc,WAAW,MAAM,OAAO,mCAAmC,EAAE;AAAA,MAC3E,YAAY;AAAA;AAAA,MACZ,cAAc;AAAA;AAAA,MACd,gBAAgB,IAAIF,WAAU,KAAK,SAAS,OAAO,kCAAkC,IAAI,OAAO,kCAAkC,KAAK,EAAE,CAAC;AAAA,MAC1I,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,kCAAkC,IAAI,OAAO,kCAAkC,KAAK,EAAE,CAAC;AAAA,MAC1I,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,wBAAwB,IAAI,OAAO,wBAAwB,KAAK,EAAE,CAAC;AAAA,MAC7G,YAAY,WAAW,MAAM,OAAO,8BAA8B,EAAE;AAAA,MACpE,aAAa;AAAA;AAAA,MACb,iBAAiB;AAAA;AAAA,MACjB,qBAAqB;AAAA;AAAA,MACrB,kBAAkB;AAAA,MAClB,eAAe;AAAA,MACf,sBAAsB;AAAA,MACtB,gBAAgB;AAAA,MAChB,uBAAuB;AAAA;AAAA,MAGvB,OAAO,WAAW,MAAM,OAAO,yBAAyB,EAAE;AAAA,MAC1D,WAAW,WAAW,MAAM,OAAO,8BAA8B,EAAE;AAAA,MACnE,UAAU,WAAW,MAAM,OAAO,6BAA6B,EAAE;AAAA,MACjE,cAAc,UAAU,MAAM,OAAO,iCAAiC,EAAE;AAAA,MACxE,cAAc,OAAO,MAAM,OAAO,gCAAgC,EAAE,MAAM;AAAA,MAC1E,iBAAiB,WAAW,MAAM,OAAO,oCAAoC,EAAE;AAAA,MAC/E,cAAc,WAAW,MAAM,OAAO,iCAAiC,EAAE;AAAA,MACzE,gBAAgB,UAAU,MAAM,OAAO,mCAAmC,EAAE;AAAA,MAC5E,cAAc,UAAU,MAAM,OAAO,gCAAgC,EAAE;AAAA,MACvE,eAAe,WAAW,MAAM,OAAO,kCAAkC,EAAE;AAAA,MAC3E,gBAAgB,OAAO,MAAM,OAAO,kCAAkC,EAAE,MAAM;AAAA,MAC9E,mBAAmB,WAAW,MAAM,OAAO,sCAAsC,EAAE;AAAA,MACnF,gBAAgB,UAAU,MAAM,OAAO,kCAAkC,EAAE;AAAA,MAC3E,oBAAoB,UAAU,MAAM,OAAO,uCAAuC,EAAE;AAAA,IACtF;AAAA,EACF;AAEA,MAAI,UAAU;AAEZ,UAAMC,YAAW,OAAO,MAAM,OAAO,oBAAoB;AACzD,UAAMC,QAAOD,cAAa,IAAI,aAAiB;AAG/C,UAAM,cAAc,OAAO,MAAM,OAAO,kCAAkC;AAC1E,UAAM,sBAA4C,CAAC;AACnD,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,YAAY,OAAO,wCAAwC,IAAI;AACrE,0BAAoB,KAAK,KAAK,MAAM,WAAW,YAAY,EAAE,CAAC;AAAA,IAChE;AAEA,UAAM,uBAAuB,OAAO,MAAM,OAAO,sCAAsC,MAAM;AAC7F,UAAM,wBAAwB,OAAO,MAAM,OAAO,uCAAuC,MAAM;AAE/F,WAAO;AAAA,MACL,MAAAC;AAAA,MACA,WAAW,UAAU,MAAM,OAAO,0BAA0B;AAAA,MAC5D,SAAS,WAAW,MAAM,OAAO,uBAAuB;AAAA,MACxD,KAAK,WAAW,MAAM,OAAO,mBAAmB;AAAA,MAChD,aAAa,WAAW,MAAM,OAAO,4BAA4B;AAAA,MACjE,qBAAqB;AAAA;AAAA,MACrB,oBAAoB;AAAA;AAAA,MACpB,cAAc,WAAW,MAAM,OAAO,gCAAgC;AAAA,MACtE,YAAY,UAAU,MAAM,OAAO,2BAA2B;AAAA,MAC9D,cAAc;AAAA;AAAA,MACd,gBAAgB,IAAIF,WAAU,KAAK,SAAS,OAAO,iCAAiC,OAAO,kCAAkC,EAAE,CAAC;AAAA,MAChI,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,iCAAiC,OAAO,kCAAkC,EAAE,CAAC;AAAA,MAChI,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,uBAAuB,OAAO,wBAAwB,EAAE,CAAC;AAAA,MACnG,YAAY,WAAW,MAAM,OAAO,2BAA2B;AAAA,MAC/D,aAAa;AAAA;AAAA,MACb,iBAAiB,WAAW,MAAM,OAAO,iCAAiC;AAAA,MAC1E;AAAA,MACA,kBAAkB;AAAA,MAClB,eAAe,KAAK,MAAM,OAAO,gCAAgC,OAAO,iCAAiC,EAAE;AAAA,MAC3G;AAAA,MACA,gBAAgB,KAAK,MAAM,OAAO,iCAAiC,OAAO,kCAAkC,EAAE;AAAA,MAC9G;AAAA;AAAA,MAGA,OAAO;AAAA,MAAI,WAAW;AAAA,MAAI,UAAU;AAAA,MAAI,cAAc;AAAA,MACtD,cAAc;AAAA,MAAM,iBAAiB;AAAA,MAAM,cAAc;AAAA,MACzD,gBAAgB;AAAA,MAAM,cAAc;AAAA,MAAM,eAAe;AAAA,MACzD,gBAAgB;AAAA,MAAM,mBAAmB;AAAA,MAAM,gBAAgB;AAAA,MAAM,oBAAoB;AAAA,IAC3F;AAAA,EACF;AAGA,QAAM,mBAAmB,QAAQ,gCAAgC;AACjE,QAAM,iBAAmB,QAAQ,8BAAgC;AACjE,QAAM,kBAAoB,WAAW,YAAa,+BAAgC,QAAQ,+BAA+B;AACzH,QAAM,gBAAmB,YAAY,gCAAiC,UAAU,6BAA8B,QAAQ,6BAA6B;AACnJ,QAAM,kBAAoB,WAAW,YAAa,KAAM,QAAQ,+BAA+B;AAC/F,QAAM,iBAAmB,YAAY,oCAAqC,UAAU,iCAAkC,QAAQ,iCAAiC;AAC/J,QAAM,gBAAmB,YAAY,oCAAqC,UAAU,iCAAkC,QAAQ,iCAAiC;AAC/J,QAAM,gBAAmB,YAAY,gCAAiC,UAAU,6BAA8B,QAAQ,6BAA6B;AACnJ,QAAM,iBAAmB,YAAY,kCAAmC,UAAU,+BAAgC,QAAQ,+BAA+B;AAEzJ,QAAM,WAAW,OAAO,MAAM,OAAO,aAAa;AAClD,QAAM,OAAO,aAAa,IAAI,aAAiB;AAE/C,SAAO;AAAA,IACL;AAAA,IACA,WAAW,UAAU,MAAM,OAAO,mBAAmB;AAAA,IACrD,SAAS,WAAW,MAAM,OAAO,gBAAgB;AAAA,IACjD,KAAK,WAAW,MAAM,OAAO,YAAY;AAAA,IACzC,aAAa,QAAQ,WAAW,MAAM,OAAO,qBAAqB,IAAI,UAAU,MAAM,OAAO,qBAAqB;AAAA,IAClH,qBAAqB,UAAU,MAAM,OAAO,gBAAgB;AAAA,IAC5D,oBAAoB,WAAW,MAAM,OAAO,cAAc;AAAA,IAC1D,cAAc,WAAW,MAAM,OAAO,eAAe;AAAA,IACrD,YAAY,iBAAiB,IAAI,UAAU,MAAM,OAAO,aAAa,IAAI;AAAA;AAAA,IAEzE,cAAe,WAAW,YAAc,mBAAmB,IAAI,OAAO,UAAU,MAAM,OAAO,eAAe,CAAC,IAAI,KAAM,WAAW,MAAM,OAAO,eAAe;AAAA,IAC9J,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,gBAAgB,OAAO,iBAAiB,EAAE,CAAC;AAAA,IAC9F,gBAAgB,IAAIA,WAAU,KAAK,SAAS,OAAO,eAAe,OAAO,gBAAgB,EAAE,CAAC;AAAA,IAC5F,OAAO,IAAIA,WAAU,KAAK,SAAS,OAAO,OAAO,cAAc,OAAO,OAAO,eAAe,EAAE,CAAC;AAAA,IAC/F,YAAY,WAAW,MAAM,OAAO,aAAa;AAAA,IACjD,aAAa,UAAU,MAAM,OAAO,cAAc;AAAA,IAClD,iBAAiB;AAAA;AAAA,IACjB,qBAAqB;AAAA;AAAA,IACrB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,gBAAgB;AAAA,IAChB,uBAAuB;AAAA;AAAA,IAGvB,OAAO;AAAA,IAAI,WAAW;AAAA,IAAI,UAAU;AAAA,IAAI,cAAc;AAAA,IACtD,cAAc;AAAA,IAAM,iBAAiB;AAAA,IAAM,cAAc;AAAA,IACzD,gBAAgB;AAAA,IAAM,cAAc;AAAA,IAAM,eAAe;AAAA,IACzD,gBAAgB;AAAA,IAAM,mBAAmB;AAAA,IAAM,gBAAgB;AAAA,IAAM,oBAAoB;AAAA,EAC3F;AACF;AAiBO,IAAM,YAAY;AAUlB,IAAM,uBAAuB;AAa7B,IAAM,kBAAkB;AAGxB,IAAM,eAAe;AAgCrB,IAAM,yBAAyB;AAoB/B,IAAM,gCAAgC;AAGtC,IAAM,+BAA+B;AAGrC,IAAM,iBAAiB;AAQvB,IAAM,uBAAuB,iBAAiB;AAM9C,IAAM,uBAAuB;AAC7B,IAAM,4BAA4B;AASlC,SAAS,oBAAoB,oBAAoC;AACtE,MAAI,CAAC,OAAO,UAAU,kBAAkB,KAAK,qBAAqB,GAAG;AACnE,UAAM,IAAI,MAAM,2EAA2E,kBAAkB,EAAE;AAAA,EACjH;AACA,SAAO,uBAAuB,uBAAuB,qBAAqB;AAC5E;AASO,IAAM,4BAA4B;AAwNlC,SAAS,sBAAsB,MAAkB,YAAoB,gBAAkC;AAC5G,QAAM,UAAU,YAAY;AAC5B,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,qDAAgD,OAAO,eAAe,KAAK,MAAM;AAAA,IACnF;AAAA,EACF;AAEA,QAAM,IAAI;AAGV,QAAM,aAAa,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAC7D,QAAM,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAClE,QAAM,0BAA0B,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAC3E,QAAM,wBAAwB,WAAW,MAAM,IAAI,EAAE;AACrD,QAAM,8BAA8B,WAAW,MAAM,IAAI,GAAG;AAC5D,QAAM,cAAc,UAAU,MAAM,IAAI,GAAG;AAC3C,QAAM,kCAAkC,UAAU,MAAM,IAAI,GAAG;AAC/D,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAClD,QAAM,oCAAoC,WAAW,MAAM,IAAI,GAAG;AAClE,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AACvD,QAAM,gCAAgC,UAAU,MAAM,IAAI,GAAG;AAC7D,QAAM,gCAAgC,UAAU,MAAM,IAAI,GAAG;AAC7D,QAAM,yBAAyB,UAAU,MAAM,IAAI,GAAG;AACtD,QAAM,YAAY,UAAU,MAAM,IAAI,GAAG;AACzC,QAAM,gBAAgB,UAAU,MAAM,IAAI,GAAG;AAC7C,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AACvD,QAAM,gCAAgC,OAAO,MAAM,IAAI,GAAG;AAC1D,QAAM,aAAa,OAAO,MAAM,IAAI,GAAG;AACvC,QAAM,iBAAiB,OAAO,MAAM,IAAI,GAAG;AAC3C,QAAM,iBAAiB,OAAO,MAAM,IAAI,GAAG;AAC3C,QAAM,SAAS,OAAO,MAAM,IAAI,GAAG;AAEnC,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,iCAAiC,UAAU,MAAM,IAAI,GAAG;AAC9D,QAAM,4BAA4B,UAAU,MAAM,IAAI,GAAG;AACzD,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,uBAAuB,UAAU,MAAM,IAAI,GAAG;AACpD,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,mBAAmB,UAAU,MAAM,IAAI,GAAG;AAChD,QAAM,wBAAwB,UAAU,MAAM,IAAI,GAAG;AACrD,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,sBAAsB,UAAU,MAAM,IAAI,GAAG;AACnD,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AAGvD,QAAMG,kBAAiB;AACvB,QAAM,iBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,mBAAe,KAAK,IAAIH,WAAU,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;AAAA,EAC5F;AAGA,QAAM,oBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIG,iBAAgB,KAAK;AACvC,sBAAkB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EACzD;AAGA,QAAM,wBAAkC,CAAC;AACzC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,0BAAsB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EAC7D;AAGA,QAAM,6BAA6B,UAAU,MAAM,IAAI,GAAG;AAC1D,QAAM,uCAAuC,UAAU,MAAM,IAAI,GAAG;AACpE,QAAM,wCAAwC,UAAU,MAAM,IAAI,GAAG;AACrE,QAAM,0BAA0B,UAAU,MAAM,IAAI,GAAG;AAGvD,QAAM,uBAAuB,IAAIH,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAC1E,QAAM,0BAA0B,WAAW,MAAM,IAAI,GAAG;AACxD,QAAM,4BAA4B,WAAW,MAAM,IAAI,GAAG;AAK1D,QAAM,oBAAoB,WAAW,MAAM,IAAI,GAAG;AAClD,QAAM,sBAAsB,WAAW,MAAM,IAAI,GAAG;AACpD,QAAM,+BAA+B,WAAW,MAAM,IAAI,GAAG;AAC7D,QAAM,iCAAiC,WAAW,MAAM,IAAI,GAAG;AAC/D,QAAM,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAC/C,QAAM,aAAa,UAAU,MAAM,IAAI,GAAG;AAC1C,QAAM,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAKjD,QAAM,2BAA2B,UAAU,MAAM,IAAI,6BAA6B;AAElF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA0EO,SAAS,2BAA2B,MAAkB,YAA2C;AACtG,QAAM,UAAU,aAAa;AAC7B,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,0DAAqD,OAAO,eAAe,KAAK,MAAM;AAAA,IACxF;AAAA,EACF;AAEA,QAAM,IAAI;AACV,QAAMG,kBAAiB;AAEvB,QAAM,iBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,mBAAe,KAAK,IAAIH,WAAU,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;AAAA,EAC5F;AAEA,QAAM,oBAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAIG,iBAAgB,KAAK;AACvC,sBAAkB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EACzD;AAEA,QAAM,wBAAkC,CAAC;AACzC,WAAS,IAAI,GAAG,IAAIA,iBAAgB,KAAK;AACvC,0BAAsB,KAAK,UAAU,MAAM,IAAI,MAAM,IAAI,CAAC,CAAC;AAAA,EAC7D;AAEA,SAAO;AAAA,IACL,YAAY,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9B,gBAAgB,OAAO,MAAM,IAAI,CAAC;AAAA,IAClC,gBAAgB,OAAO,MAAM,IAAI,CAAC;AAAA,IAClC,QAAQ,OAAO,MAAM,IAAI,CAAC;AAAA,IAC1B,WAAW,UAAU,MAAM,IAAI,CAAC;AAAA,IAChC,eAAe,UAAU,MAAM,IAAI,CAAC;AAAA,IACpC,wBAAwB,UAAU,MAAM,IAAI,EAAE;AAAA,IAC9C,yBAAyB,UAAU,MAAM,IAAI,EAAE;AAAA,IAC/C,sCAAsC,UAAU,MAAM,IAAI,EAAE;AAAA,IAC5D,uCAAuC,UAAU,MAAM,IAAI,EAAE;AAAA,IAC7D,oBAAoB,IAAIH,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC/D,mBAAmB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IAC9D,wBAAwB,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,GAAG,CAAC;AAAA,IACpE,iBAAiB,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,IAC9D,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAAA,IACzC,sBAAsB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC7C,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,IACnC,kBAAkB,UAAU,MAAM,IAAI,GAAG;AAAA,IACzC,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC9C,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,IACnC,qBAAqB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC5C,yBAAyB,UAAU,MAAM,IAAI,GAAG;AAAA,IAChD,oBAAoB,UAAU,MAAM,IAAI,GAAG;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,IAAIA,WAAU,KAAK,SAAS,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,EAC3D;AACF;AAQO,SAAS,aAAa,MAA2B;AACtD,MAAI,KAAK,SAAS,GAAI,QAAO;AAC7B,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,SAAO,UAAU,aAAa,YAAY;AAC5C;AAcO,SAAS,mBAAmB,MAA2B;AAC5D,MAAI,KAAK,SAAS,eAAe,EAAG,QAAO;AAC3C,MAAI,CAAC,aAAa,IAAI,EAAG,QAAO;AAChC,SAAO,KAAK,YAAY,MAAM;AAChC;AAUA,IAAM,2BAA2B;AAMjC,IAAM,8BAA8B;AAUpC,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;AAkE9B,SAAS,sBAAsB,MAAoC;AACxE,QAAM,UAAU,uBAAuB;AACvC,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,0DAAqD,OAAO,eAAe,KAAK,MAAM;AAAA,IACxF;AAAA,EACF;AACA,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,uBAAuB;AAC5C,QAAM,mBAAmB,WAAW,MAAM,YAAY;AAGtD,QAAM,YAAY,uBAAuB;AACzC,QAAM,WAAW,KAAK;AAAA,KACnB,KAAK,SAAS,aAAa;AAAA,EAC9B;AAEA,MAAI,eAAe;AACnB,MAAI,gBAAgB;AACpB,QAAM,SAAqC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,UAAM,WAAW,YAAY,IAAI;AAGjC,UAAM,UACJ,WAAW,8BAA8B;AAC3C,UAAM,WACJ,WAAW,8BAA8B;AAG3C,QAAI,WAAW,KAAK,KAAK,OAAQ;AAEjC,UAAM,aAAa,WAAW,MAAM,OAAO;AAC3C,UAAM,cAAc,WAAW,MAAM,QAAQ;AAE7C,oBAAgB;AAChB,qBAAiB;AAEjB,QAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,aAAO,KAAK,EAAE,YAAY,GAAG,YAAY,YAAY,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,EAAE,kBAAkB,cAAc,eAAe,OAAO;AACjE;AAOA,IAAM,yBAAyB;AAC/B,IAAM,qBAAqB;AAC3B,IAAM,6BAA6B;AACnC,IAAM,yBAAyB;AAE/B,SAAS,0BACP,MACA,YACA,cACM;AACN,MAAI,KAAK,SAAS,wBAAwB;AACxC,UAAM,IAAI,MAAM,GAAG,UAAU,qBAAqB,KAAK,MAAM,MAAM,sBAAsB,GAAG;AAAA,EAC9F;AACA,QAAM,QAAQ,UAAU,MAAM,CAAC;AAC/B,MAAI,UAAU,WAAW;AACvB,UAAM,IAAI,MAAM,GAAG,UAAU,qBAAqB;AAAA,EACpD;AACA,QAAM,UAAU,UAAU,MAAM,CAAC;AACjC,MAAI,YAAY,sBAAsB;AACpC,UAAM,IAAI,MAAM,GAAG,UAAU,0BAA0B,OAAO,QAAQ,oBAAoB,GAAG;AAAA,EAC/F;AACA,QAAM,OAAO,OAAO,MAAM,EAAE;AAC5B,MAAI,SAAS,cAAc;AACzB,UAAM,IAAI,MAAM,GAAG,UAAU,+BAA+B,IAAI,QAAQ,YAAY,GAAG;AAAA,EACzF;AACF;AAIA,IAAM,oBAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,+BAAiC,oBAAoB;AAC3D,IAAM,0BAAiC,oBAAoB;AAC3D,IAAM,4BAAiC,oBAAoB;AAC3D,IAAM,yBAAiC,oBAAoB;AAC3D,IAAM,cAAiC,oBAAoB;AAC3D,IAAM,eAAiC;AACvC,IAAM,iBAAiC,cAAc;AACrD,IAAM,aAAiC,cAAc;AACrD,IAAM,sBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,4BAAiC,cAAc;AACrD,IAAM,2BAAiC,cAAc;AACrD,IAAM,qBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AACrD,IAAM,uBAAiC,cAAc;AAIrD,IAAM,cAAiC;AACvC,IAAM,cAAiC,cAAc;AACrD,IAAM,gBAAiC;AAUvC,IAAM,wBAAiC;AACvC,IAAM,wBAAiC,cAAc,gBAAgB;AACrE,IAAM,wBAAiC;AAEvC,IAAM,qBAAiC,wBAAwB,wBAAwB;AAmBvF,IAAM,wBAA2B;AACjC,IAAM,yBAA2B,4BAA4B;AAC7D,IAAM,yBAA2B,yBAAyB;AAC1D,IAAM,0BAA2B,yBAAyB;AAC1D,IAAM,yBAA2B,0BAA0B;AAmGpD,SAAS,kBAAkB,MAAgC;AAEhE,QAAM,sBAAsB,sBAAsB;AAClD,MAAI,KAAK,SAAS,qBAAqB;AACrC,UAAM,IAAI,MAAM,sCAAsC,KAAK,MAAM,MAAM,mBAAmB,GAAG;AAAA,EAC/F;AACA,4BAA0B,MAAM,qBAAqB,kBAAkB;AAGvE,QAAM,gBAAgB,IAAIA,WAAU,KAAK,SAAS,gCAAgC,iCAAiC,EAAE,CAAC;AACtH,QAAM,qBAAqB,IAAIA,WAAU,KAAK,SAAS,8BAA8B,+BAA+B,EAAE,CAAC;AACvH,QAAM,kBAAkB,IAAIA,WAAU,KAAK,SAAS,yBAAyB,0BAA0B,EAAE,CAAC;AAG1G,QAAM,QAAQ,IAAIA,WAAU,KAAK,SAAS,cAAc,eAAe,EAAE,CAAC;AAC1E,QAAM,UAAU,WAAW,MAAM,cAAc;AAC/C,QAAM,MAAM,WAAW,MAAM,UAAU;AACvC,QAAM,cAAc,WAAW,MAAM,mBAAmB;AAExD,QAAM,qCAAqC,KAAK,UAAU,uBAAuB,KAC7E,WAAW,MAAM,oBAAoB,IAAI;AAC7C,QAAM,mCAAmC,KAAK,UAAU,4BAA4B,KAChF,WAAW,MAAM,yBAAyB,IAAI;AAClD,QAAM,6BAA6B,KAAK,UAAU,2BAA2B,KACzE,WAAW,MAAM,wBAAwB,IAAI;AACjD,QAAM,aAAa,KAAK,UAAU,qBAAqB,KACnD,WAAW,MAAM,kBAAkB,IAAI;AAC3C,QAAM,sBAAsB,KAAK,UAAU,uBAAuB,KAC9D,WAAW,MAAM,oBAAoB,IAAI;AAC7C,QAAM,cAAc,KAAK,UAAU,uBAAuB,IACtD,UAAU,MAAM,oBAAoB,IAAI;AAC5C,QAAM,eAAe,KAAK,UAAU,uBAAuB,IACvD,UAAU,MAAM,oBAAoB,IAAI;AAG5C,QAAM,OAA0B,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,UAAM,IAAI,cAAc,IAAI;AAC5B,QAAI,KAAK,SAAS,IAAI,YAAa;AACnC,SAAK,KAAK;AAAA,MACR,QAAQ,KAAK,CAAC,MAAM;AAAA,MACpB,YAAY,UAAU,MAAM,IAAI,CAAC;AAAA,MACjC,UAAU,UAAU,MAAM,IAAI,CAAC;AAAA,MAC/B,MAAM,KAAK,IAAI,EAAE;AAAA,MACjB,WAAW,WAAW,MAAM,IAAI,EAAE;AAAA,MAClC,QAAQ,WAAW,MAAM,IAAI,EAAE;AAAA,MAC/B,OAAO,WAAW,MAAM,IAAI,EAAE;AAAA,MAC9B,OAAO,WAAW,MAAM,IAAI,EAAE;AAAA,MAC9B,WAAW,UAAU,MAAM,IAAI,EAAE;AAAA,MACjC,YAAY,WAAW,MAAM,IAAI,EAAE;AAAA,MACnC,OAAO,WAAW,MAAM,IAAI,GAAG;AAAA,MAC/B,MAAM,WAAW,MAAM,IAAI,GAAG;AAAA,MAC9B,YAAY,UAAU,MAAM,IAAI,GAAG;AAAA,MACnC,QAAQ,KAAK,IAAI,GAAG,MAAM;AAAA,MAC1B,OAAO,KAAK,IAAI,GAAG,MAAM;AAAA,IAC3B,CAAC;AAAA,EACH;AAGA,QAAM,gBAA4C,CAAC;AACnD,WAAS,IAAI,GAAG,IAAI,uBAAuB,KAAK;AAC9C,UAAM,IAAI,wBAAwB,IAAI;AACtC,QAAI,KAAK,SAAS,IAAI,sBAAuB;AAC7C,kBAAc,KAAK;AAAA,MACjB,QAAQ,UAAU,MAAM,IAAI,CAAC;AAAA,MAC7B,qBAAqB,UAAU,MAAM,IAAI,CAAC;AAAA,MAC1C,qBAAqB,WAAW,MAAM,IAAI,EAAE;AAAA,MAC5C,sBAAsB,WAAW,MAAM,IAAI,EAAE;AAAA,MAC7C,kCAAkC,WAAW,MAAM,IAAI,EAAE;AAAA,MACzD,+BAA+B,WAAW,MAAM,IAAI,EAAE;AAAA,MACtD,6BAA6B,WAAW,MAAM,IAAI,EAAE;AAAA,MACpD,kCAAkC,WAAW,MAAM,IAAI,EAAE;AAAA,MACzD,+BAA+B,WAAW,MAAM,IAAI,GAAG;AAAA,MACvD,uBAAuB,UAAU,MAAM,IAAI,GAAG;AAAA,MAC9C,wBAAwB,WAAW,MAAM,IAAI,GAAG;AAAA,MAChD,qCAAqC,WAAW,MAAM,IAAI,GAAG;AAAA,MAC7D,mCAAmC,WAAW,MAAM,IAAI,GAAG;AAAA,MAC3D,2CAA2C,WAAW,MAAM,IAAI,GAAG;AAAA,IACrE,CAAC;AAAA,EACH;AAEA,QAAM,iBAAiB,KAAK,UAAU,yBAAyB,KAC3D,IAAIA,WAAU,KAAK,SAAS,wBAAwB,yBAAyB,EAAE,CAAC,IAChFA,WAAU;AACd,QAAM,iBAAiB,KAAK,UAAU,yBAAyB,KAC3D,IAAIA,WAAU,KAAK,SAAS,wBAAwB,yBAAyB,EAAE,CAAC,IAChFA,WAAU;AACd,QAAM,kBAAkB,KAAK,UAAU,0BAA0B,KAC7D,IAAIA,WAAU,KAAK,SAAS,yBAAyB,0BAA0B,EAAE,CAAC,IAClFA,WAAU;AAMd,MAAI,iBAAiB;AACrB,MAAI,KAAK,UAAU,yBAAyB,GAAG;AAC7C,UAAM,aAAa,UAAU,MAAM,sBAAsB;AACzD,QAAI,aAAa,IAAI;AACnB,YAAM,IAAI;AAAA,QACR,kDAAkD,UAAU;AAAA,MAC9D;AAAA,IACF;AACA,qBAAiB,eAAe;AAAA,EAClC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWA,IAAM,0BAA0B;AAmCzB,SAAS,qBAAqB,MAAsC;AACzE,MAAI,KAAK,SAAS,yBAAyB;AACzC,UAAM,IAAI;AAAA,MACR,yCAAyC,KAAK,MAAM,MAAM,uBAAuB;AAAA,IACnF;AAAA,EACF;AACA,4BAA0B,MAAM,wBAAwB,0BAA0B;AAClF,QAAM,IAAI;AACV,SAAO;AAAA,IACL,aAAa,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAAA,IACvD,QAAQ,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IACnD,0BAA0B,WAAW,MAAM,IAAI,EAAE;AAAA,IACjD,2BAA2B,WAAW,MAAM,IAAI,EAAE;AAAA,IAClD,2BAA2B,WAAW,MAAM,IAAI,EAAE;AAAA,IAClD,OAAO,UAAU,MAAM,IAAI,GAAG;AAAA,IAC9B,yBAAyB,UAAU,MAAM,IAAI,GAAG;AAAA,IAChD,aAAa,UAAU,MAAM,IAAI,GAAG;AAAA,IACpC,2BAA2B,UAAU,MAAM,IAAI,GAAG;AAAA,IAClD,QAAQ,UAAU,MAAM,IAAI,GAAG;AAAA,IAC/B,QAAQ,KAAK,IAAI,GAAG,MAAM;AAAA,IAC1B,SAAS,KAAK,IAAI,GAAG;AAAA,IACrB,MAAM,KAAK,IAAI,GAAG;AAAA,IAClB,UAAU,KAAK,IAAI,GAAG;AAAA,EACxB;AACF;AAQA,IAAM,sBAAsB;AA6BrB,SAAS,kBAAkB,MAAmC;AACnE,MAAI,KAAK,SAAS,qBAAqB;AACrC,UAAM,IAAI;AAAA,MACR,sCAAsC,KAAK,MAAM,MAAM,mBAAmB;AAAA,IAC5E;AAAA,EACF;AACA,4BAA0B,MAAM,qBAAqB,sBAAsB;AAC3E,QAAM,IAAI;AACV,SAAO;AAAA,IACL,UAAU,IAAIA,WAAU,KAAK,SAAS,IAAI,GAAG,IAAI,EAAE,CAAC;AAAA,IACpD,UAAU,IAAIA,WAAU,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC;AAAA,IACrD,QAAQ,WAAW,MAAM,IAAI,EAAE;AAAA,IAC/B,aAAa,UAAU,MAAM,IAAI,EAAE;AAAA,IACnC,SAAS,KAAK,IAAI,EAAE;AAAA,IACpB,MAAM,KAAK,IAAI,EAAE;AAAA,EACnB;AACF;AAKO,SAAS,iBAAiB,MAAuD;AACtF,QAAM,UAAU,iBAAiB,IAAI;AACrC,QAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,QAAM,eAAe,QAAQ,OAAO,SAAO,MAAM,MAAM;AACvD,QAAM,eAAe,QAAQ,SAAS,aAAa;AACnD,MAAI,eAAe,GAAG;AACpB,YAAQ;AAAA,MACN,oCAAoC,QAAQ,MAAM,2BAA2B,MAAM,2BAClE,YAAY;AAAA,IAC/B;AAAA,EACF;AACA,SAAO,aAAa,IAAI,UAAQ;AAAA,IAC9B;AAAA,IACA,SAAS,aAAa,MAAM,GAAG;AAAA,EACjC,EAAE;AACJ;;;ACp1JA,SAAS,aAAAI,kBAAiB;AAE1B,IAAM,cAAc,IAAI,YAAY;AAUpC,SAAS,MAAM,OAA2B;AACxC,MACE,OAAO,UAAU,YACjB,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,QAAQ,OACR;AACA,UAAM,IAAI,MAAM,sDAAsD,KAAK,EAAE;AAAA,EAC/E;AACA,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE;AAAA,IAAU;AAAA,IAAG;AAAA;AAAA,IAAyB;AAAA,EAAI;AACnE,SAAO;AACT;AASO,SAAS,qBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC;AAAA,IAC5C;AAAA,EACF;AACF;AAYO,IAAM,8BAA8B,IAAIA;AAAA,EAC7C;AACF;AAWO,IAAM,oCAAoC,IAAIA;AAAA,EACnD;AACF;AAyCO,SAAS,qBACd,WACA,QACA,MACqB;AACrB,QAAM,CAAC,cAAc,IAAI,qBAAqB,WAAW,MAAM;AAC/D,SAAO,iCAAiC,gBAAgB,IAAI;AAC9D;AAmBO,SAAS,iCACd,gBACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,eAAe,QAAQ;AAAA,MACvB,kCAAkC,QAAQ;AAAA,MAC1C,KAAK,QAAQ;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AA8CO,SAAS,0BACd,WACA,QACA,MACqB;AACrB,QAAM,CAAC,gBAAgB,kBAAkB,IAAI,qBAAqB,WAAW,MAAM;AACnF,QAAM,CAAC,YAAY,cAAc,IAAI;AAAA,IACnC;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,EAChB;AACF;AAOO,SAAS,sBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,eAAe,GAAG,KAAK,QAAQ,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,IAAM,mBAAmB;AAMlB,SAAS,YACd,WACA,MACA,OACqB;AACrB,MACE,OAAO,UAAU,YACjB,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,QAAQ,kBACR;AACA,UAAM,IAAI;AAAA,MACR,gDAAgD,gBAAgB,UAAU,KAAK;AAAA,IACjF;AAAA,EACF;AACA,QAAM,SAAS,IAAI,WAAW,CAAC;AAC/B,MAAI,SAAS,OAAO,MAAM,EAAE,UAAU,GAAG,OAAO,IAAI;AACpD,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,IAAI,GAAG,KAAK,QAAQ,GAAG,MAAM;AAAA,IACjD;AAAA,EACF;AACF;AAOO,IAAM,sBAAsB,IAAIA;AAAA,EACrC;AACF;AAGO,IAAM,0BAA0B,IAAIA;AAAA,EACzC;AACF;AAGO,IAAM,0BAA0B,IAAIA;AAAA,EACzC;AACF;AAOO,IAAM,8BAA8B,IAAIA;AAAA,EAC7C;AACF;AAUO,IAAM,oBAAoB;AAoB1B,SAAS,qBACd,WACA,MACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,iBAAiB,GAAG,KAAK,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAyBO,SAAS,sBACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,UAAU,GAAG,YAAY,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AACF;AAsBO,SAAS,mBACd,WACA,UACA,UACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,eAAe;AAAA,MAClC,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAuBO,SAAS,sBACd,WACA,aACA,WACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,mBAAmB;AAAA,MACtC,YAAY,QAAQ;AAAA,MACpB,MAAM,SAAS;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;AAqBO,SAAS,eACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,WAAW,GAAG,YAAY,QAAQ,CAAC;AAAA,IACvD;AAAA,EACF;AACF;AAyBO,SAAS,kBACd,WACA,aACqB;AACrB,SAAOA,WAAU;AAAA,IACf,CAAC,YAAY,OAAO,cAAc,GAAG,YAAY,QAAQ,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AAqCO,SAAS,sBACd,WACA,QACA,UACA,eACA,aACA,YACqB;AACrB,SAAOA,WAAU;AAAA,IACf;AAAA,MACE,YAAY,OAAO,SAAS;AAAA,MAC5B,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ;AAAA,MACjB,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,uBAAuB,WAA2B;AACzD,MAAI,IAAI,UAAU,KAAK;AACvB,MAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,IAAI,GAAG;AAC5C,QAAI,EAAE,MAAM,CAAC;AAAA,EACf;AACA,SAAO;AACT;AAOA,IAAM,cAAc;AAEb,SAAS,wBAAwB,WAAwC;AAC9E,QAAM,aAAa,uBAAuB,SAAS;AACnD,MAAI,CAAC,YAAY,KAAK,UAAU,GAAG;AACjC,UAAM,IAAI;AAAA,MACR,4EAA4E,WAAW,WAAW,KAAK,+BAA+B,WAAW,SAAS,QAAQ;AAAA,IAAO;AAAA,EAC7K;AACA,QAAM,SAAS,IAAI,WAAW,EAAE;AAChC,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,WAAO,CAAC,IAAI,SAAS,WAAW,UAAU,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;AAAA,EACjE;AACA,QAAM,WAAW,IAAI,WAAW,CAAC;AACjC,SAAOC,WAAU;AAAA,IACf,CAAC,UAAU,MAAM;AAAA,IACjB;AAAA,EACF;AACF;;;AChkBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA,oBAAAC;AAAA,OACK;AAOP,eAAsB,OACpB,OACA,MACA,qBAAqB,OACrB,iBAA4BA,mBACR;AACpB,SAAO,0BAA0B,MAAM,OAAO,oBAAoB,cAAc;AAClF;AAMO,SAAS,WACd,OACA,MACA,qBAAqB,OACrB,iBAA4BA,mBACjB;AACX,SAAO,8BAA8B,MAAM,OAAO,oBAAoB,cAAc;AACtF;AAOA,eAAsB,kBACpB,YACA,SACA,iBAA4BA,mBACV;AAClB,SAAO,WAAW,YAAY,SAAS,QAAW,cAAc;AAClE;;;AC/CA,SAAqB,aAAAC,kBAAiB;;;ACoBtC,SAAS,aAAAC,kBAAiB;AA2B1B,IAAM,kBAAuC;AAAA,EAC3C,EAAE,aAAa,gDAAgD,QAAQ,YAAY,MAAM,qBAAqB;AAChH;AAUA,IAAM,iBAAsC;AAAA;AAAA;AAG5C;AAKA,IAAM,kBAAwD;AAAA,EAC5D,SAAS;AAAA,EACT,QAAQ;AACV;AAMA,IAAM,eAAqD;AAAA,EACzD,SAAS,CAAC;AAAA,EACV,QAAQ,CAAC;AACX;AAoBO,SAAS,iBAAiB,SAAuC;AACtE,QAAM,UAAU,gBAAgB,OAAO,KAAK,CAAC;AAC7C,QAAM,OAAO,aAAa,OAAO,KAAK,CAAC;AAEvC,MAAI,KAAK,WAAW,EAAG,QAAO,CAAC,GAAG,OAAO;AAGzC,QAAM,OAAO,oBAAI,IAA+B;AAChD,aAAW,SAAS,SAAS;AAC3B,SAAK,IAAI,MAAM,aAAa,KAAK;AAAA,EACnC;AACA,aAAW,SAAS,MAAM;AACxB,SAAK,IAAI,MAAM,aAAa,KAAK;AAAA,EACnC;AACA,SAAO,CAAC,GAAG,KAAK,OAAO,CAAC;AAC1B;AAyBO,SAAS,sBACd,SACA,SACM;AACN,QAAM,WAAW,aAAa,OAAO;AACrC,QAAM,OAAO,IAAI,IAAI,SAAS,IAAI,OAAK,EAAE,WAAW,CAAC;AAErD,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAa;AACxB,QAAI,KAAK,IAAI,MAAM,WAAW,EAAG;AAEjC,QAAI;AACF,UAAIA,WAAU,MAAM,WAAW;AAAA,IACjC,QAAQ;AACN,cAAQ;AAAA,QACN,yDAAyD,MAAM,WAAW;AAAA,MAC5E;AACA;AAAA,IACF;AACA,SAAK,IAAI,MAAM,WAAW;AAC1B,aAAS,KAAK,KAAK;AAAA,EACrB;AACF;AASO,SAAS,mBAAmB,SAAyB;AAC1D,MAAI,SAAS;AACX,iBAAa,OAAO,IAAI,CAAC;AAAA,EAC3B,OAAO;AACL,iBAAa,UAAU,CAAC;AACxB,iBAAa,SAAS,CAAC;AAAA,EACzB;AACF;;;ADnJA,IAAM,uBAAuB;AA8C7B,IAAM,cAAc,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AASnF,IAAM,kBAAkB,IAAI,WAAW,CAAC,GAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AA4BhF,IAAM,aAAa;AAAA,EACxB,OAAQ,kBAAkB,OAAO;AAAA,EACjC,QAAQ,kBAAkB,QAAQ;AAAA,EAClC,OAAQ,kBAAkB,OAAO;AACnC;AAGO,IAAM,gBAAgB;AAAA,EAC3B,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAW,OAAO,SAAU,aAAa,2BAAwB;AAAA,EACxG,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAW,OAAO,UAAU,aAAa,6BAA0B;AAAA,EAC1G,OAAQ,EAAE,aAAa,MAAM,UAAU,QAAW,OAAO,SAAU,aAAa,6BAA0B;AAC5G;AAgBO,IAAM,iBAAiB;AAAA,EAC5B,OAAQ,EAAE,aAAa,IAAM,UAAU,OAAY,OAAO,SAAU,aAAa,wBAAwB;AAAA,EACzG,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAY,OAAO,SAAU,aAAa,yBAAyB;AAAA,EAC1G,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAY,OAAO,UAAU,aAAa,2BAA2B;AAAA,EAC5G,OAAQ,EAAE,aAAa,MAAM,UAAU,SAAY,OAAO,SAAU,aAAa,2BAA2B;AAC9G;AAcO,IAAM,wBAAwB;AAAA,EACnC,OAAQ,EAAE,aAAa,IAAM,UAAU,OAAY,OAAO,SAAU,aAAa,uCAAuC;AAAA,EACxH,OAAQ,EAAE,aAAa,KAAM,UAAU,OAAY,OAAO,SAAU,aAAa,wCAAwC;AAAA,EACzH,QAAQ,EAAE,aAAa,MAAM,UAAU,QAAY,OAAO,UAAU,aAAa,0CAA0C;AAAA,EAC3H,OAAQ,EAAE,aAAa,MAAM,UAAU,SAAY,OAAO,SAAU,aAAa,0CAA0C;AAC7H;AAGO,IAAM,gBAAgB;AAStB,IAAM,6BAA6B;AAiBnC,SAAS,aAAa,aAA6B;AAExD,QAAM,gBAAgB;AACtB,QAAMC,wBAAuB;AAC7B,QAAM,kBAAkB;AACxB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiBA,wBAAuB,cAAc,aAAa;AACzE,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,gBAAgB,cAAc,cAAc;AACrD;AAWO,SAAS,eAAe,aAA6B;AAC1D,QAAM,gBAAgB;AACtB,QAAM,uBAAuB;AAC7B,QAAM,kBAAkB;AACxB,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE,IAAI;AAClD,QAAM,aAAa;AACnB,QAAM,gBAAgB,cAAc;AACpC,QAAM,iBAAiB,uBAAuB,cAAc,aAAa;AACzE,QAAM,cAAc,KAAK,KAAK,iBAAiB,CAAC,IAAI;AACpD,SAAO,gBAAgB,cAAc,cAAc;AACrD;AAUO,SAAS,sBAAsB,UAAkB,gBAAiC;AACvF,SAAO,aAAa;AACtB;AAGA,IAAM,iBAAiB;AAAA,EACrB,GAAG,OAAO,OAAO,UAAU,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EAChD,GAAG,OAAO,OAAO,aAAa,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACnD,GAAG,OAAO,OAAO,cAAc,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACpD,GAAG,OAAO,OAAO,qBAAqB,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EAC3D,GAAG,OAAO,OAAO,cAAc,EAAE,IAAI,OAAK,EAAE,QAAQ;AAAA,EACpD,GAAG,OAAO,OAAO,gBAAgB,EAAE,IAAI,OAAK,EAAE,QAAQ;AACxD;AAGA,IAAM,iBAAiB,WAAW,MAAM;AAGxC,IAAM,sBAAsB;AAE5B,SAASC,IAAG,MAA4B;AACtC,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACnE;AACA,SAASC,WAAU,MAAkB,KAAqB;AACxD,SAAOD,IAAG,IAAI,EAAE,UAAU,KAAK,IAAI;AACrC;AACA,SAASE,WAAU,MAAkB,KAAqB;AACxD,SAAOF,IAAG,IAAI,EAAE,aAAa,KAAK,IAAI;AACxC;AACA,SAASG,WAAU,MAAkB,KAAqB;AACxD,SAAOH,IAAG,IAAI,EAAE,YAAY,KAAK,IAAI;AACvC;AACA,SAASI,YAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAKF,WAAU,KAAK,MAAM;AAChC,QAAM,KAAKA,WAAU,KAAK,SAAS,CAAC;AACpC,SAAQ,MAAM,MAAO;AACvB;AACA,SAASG,YAAW,KAAiB,QAAwB;AAC3D,QAAM,KAAKH,WAAU,KAAK,MAAM;AAChC,QAAM,KAAKA,WAAU,KAAK,SAAS,CAAC;AACpC,QAAM,WAAY,MAAM,MAAO;AAC/B,QAAM,WAAW,MAAM;AACvB,MAAI,YAAY,SAAU,QAAO,YAAY,MAAM;AACnD,SAAO;AACT;AAUO,SAAS,iBACd,MACA,QACA,cAAsB,MACT;AACb,QAAM,OAAO,CAAC,UAAU,OAAO,YAAY;AAC3C,QAAM,OAAO,SAAS,OAAO,YAAY;AACzC,QAAM,YAAY,SAAS,OAAO,kBAAkB;AAEpD,QAAM,SAAS,OAAO;AACtB,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,IAAI,MAAM,+CAA+C,KAAK,MAAM,MAAM,MAAM,EAAE;AAAA,EAC1F;AAGA,QAAM,cAAc,KAAK,KAAK,cAAc,EAAE;AAC9C,QAAM,aAAa,YAAY,cAAc;AAC7C,QAAM,mBAAmB,KAAK,MAAM,aAAa,KAAK,CAAC,IAAI;AAE3D,QAAM,iBAAiB,KAAK,UAAU,OAAO,aAAa;AAC1D,QAAM,gBAAgB,KAAK,UAAU,OAAO,mBAAmB;AAE/D,MAAI,MAAM;AASR,WAAO;AAAA,MACL,OAAOE,YAAW,MAAM,OAAO,CAAC;AAAA,MAChC,eAAe;AAAA,QACb,SAASA,YAAW,MAAM,OAAO,EAAE;AAAA,QACnC,YAAYA,YAAW,MAAM,OAAO,EAAE;AAAA,QACtC,iBAAiB;AAAA,QACjB,cAAc;AAAA,MAChB;AAAA,MACA,aAAaF,WAAU,MAAM,OAAO,GAAG;AAAA,MACvC,mBAAmBG,YAAW,MAAM,OAAO,GAAG;AAAA,MAC9C,iBAAiBH,WAAU,MAAM,OAAO,GAAG;AAAA,MAC3C,2BAA2BC,WAAU,MAAM,OAAO,GAAG;AAAA,MACrD,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,eAAeD,WAAU,MAAM,OAAO,GAAG;AAAA,MACzC,wBAAwBA,WAAU,MAAM,OAAO,GAAG;AAAA,MAClD,mBAAmBE,YAAW,MAAM,OAAO,GAAG;AAAA,MAC9C,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAMA,YAAW,MAAM,OAAO,GAAG;AAAA,MACjC,WAAWA,YAAW,MAAM,OAAO,GAAG;AAAA,MACtC,kBAAkB;AAAA,MAClB,WAAWH,WAAU,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUA,WAAU,MAAM,OAAO,GAAG;AAAA,MACpC,oBAAoBC,WAAU,MAAM,OAAO,GAAG;AAAA,MAC9C,uBAAuBA,WAAU,MAAM,OAAO,GAAG;AAAA,MACjD,aAAaD,WAAU,MAAM,OAAO,GAAG;AAAA,MACvC,eAAeA,WAAU,MAAM,OAAO,GAAG;AAAA,MACzC,sBAAsBC,WAAU,MAAM,OAAO,GAAG;AAAA,MAChD,qBAAqBA,WAAU,MAAM,OAAO,GAAG;AAAA,MAC/C,UAAUG,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUD,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,UAAUA,YAAW,MAAM,OAAO,GAAG;AAAA,MACrC,eAAe;AAAA,MACf,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,aAAa;AAAA;AAAA,MACb,eAAe;AAAA,MACf,UAAU;AAAA,MAAI,WAAW;AAAA,MAAI,oBAAoB;AAAA,MAAI,YAAY;AAAA,MACjE,4BAA4B;AAAA,MAAI,6BAA6B;AAAA,MAAI,mBAAmB;AAAA,MACpF,iBAAiB,iBAAiBH,WAAU,MAAM,OAAO,UAAU,IAAI;AAAA,MACvE,eAAe,gBAAgBC,WAAU,MAAM,OAAO,gBAAgB,IAAI;AAAA,IAC5E;AAAA,EACF;AAmBA,MAAI,WAAW,MAAM;AACnB,UAAM,IAAI;AAEV,UAAM,wBAAwB,EAAE,8BAA8B,KAAK,EAAE,kCAAkC;AAMvG,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAID,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAIC,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,QAAQ,CAAC,QAAyB,OAAO,IAAIC,WAAU,MAAM,OAAO,GAAG,IAAI;AACjF,UAAM,SAAS,CAAC,QAAyB,OAAO,IAAIC,YAAW,MAAM,OAAO,GAAG,IAAI;AACnF,UAAM,SAAS,CAAC,QAAyB,OAAO,IAAIC,YAAW,MAAM,OAAO,GAAG,IAAI;AACnF,WAAO;AAAA,MACL,OAAOD,YAAW,MAAM,OAAO,CAAC;AAAA,MAChC,eAAe;AAAA,QACb,SAASA,YAAW,MAAM,OAAO,EAAE,kBAAkB;AAAA,QACrD,YAAYA,YAAW,MAAM,OAAO,EAAE,qBAAqB,EAAE;AAAA,QAC7D,iBAAiB,wBAAwBA,YAAW,MAAM,OAAO,EAAE,0BAA0B,IAAI;AAAA,QACjG,cAAc,wBAAwBH,WAAU,MAAM,OAAO,EAAE,8BAA8B,IAAI;AAAA,MACnG;AAAA,MACA,aAAaC,WAAU,MAAM,OAAO,EAAE,oBAAoB;AAAA;AAAA;AAAA;AAAA,MAI1D,mBAAmB,EAAE,yBAAyB,IACxC,EAAE,4BAA4B,KAAK,EAAE,2BAA2B,EAAE,0BAA0B,IAC1F,OAAOC,WAAU,MAAM,OAAO,EAAE,qBAAqB,CAAC,IACtDE,YAAW,MAAM,OAAO,EAAE,qBAAqB,IACnD;AAAA,MACJ,iBAAiB,MAAM,EAAE,wBAAwB;AAAA,MACjD,2BAA2B,MAAM,EAAE,uBAAuB;AAAA,MAC1D,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,eAAe,MAAM,EAAE,sBAAsB;AAAA,MAC7C,wBAAwB,MAAM,EAAE,0BAA0B;AAAA,MAC1D,mBAAmB,OAAO,EAAE,gBAAgB;AAAA,MAC5C,QAAQ,OAAO,EAAE,eAAe;AAAA,MAChC,SAAS,OAAO,EAAE,gBAAgB;AAAA,MAClC,MAAMD,YAAW,MAAM,OAAO,EAAE,aAAa;AAAA,MAC7C,WAAWA,YAAW,MAAM,OAAO,EAAE,kBAAkB;AAAA,MACvD,kBAAkB;AAAA,MAClB,WAAW,MAAM,EAAE,kBAAkB;AAAA,MACrC,UAAU,MAAM,EAAE,iBAAiB;AAAA,MACnC,oBAAoB,MAAM,EAAE,uBAAuB;AAAA,MACnD,uBAAuB,MAAM,EAAE,0BAA0B;AAAA,MACzD,aAAa,MAAM,EAAE,oBAAoB;AAAA,MACzC,eAAe,MAAM,EAAE,sBAAsB;AAAA,MAC7C,sBAAsB,MAAM,EAAE,6BAA6B;AAAA,MAC3D,qBAAqB,MAAM,EAAE,4BAA4B;AAAA,MACzD,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,UAAU,OAAO,EAAE,iBAAiB;AAAA,MACpC,eAAe,OAAO,EAAE,sBAAsB;AAAA,MAC9C,iBAAiB,EAAE,4BAA4B,IAAI,KAAK,OAAO,EAAE,wBAAwB,MAAM,IAAI;AAAA,MACnG,oBAAoB,MAAM,EAAE,2BAA2B;AAAA,MACvD,iBAAiB,MAAM,EAAE,wBAAwB;AAAA,MACjD,aAAa,MAAM,EAAE,kBAAkB;AAAA,MACvC,eAAe;AAAA,MACf,UAAU;AAAA,MACV,WAAW;AAAA,MACX,oBAAoB;AAAA,MACpB,YAAY;AAAA,MACZ,4BAA4B;AAAA,MAC5B,6BAA6B;AAAA,MAC7B,mBAAmB;AAAA,MACnB,iBAAiB,iBAAiBH,WAAU,MAAM,OAAO,UAAU,IAAI;AAAA,MACvE,eAAe,gBAAgBC,WAAU,MAAM,OAAO,gBAAgB,IAAI;AAAA,IAC5E;AAAA,EACF;AAIA,QAAM,IAAI,MAAM,oDAAoD,IAAI,GAAG;AAC7E;AA8FA,SAAS,iBAAiB,KAAuB;AAC/C,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,SACE,IAAI,SAAS,KAAK,KAClB,IAAI,YAAY,EAAE,SAAS,YAAY,KACvC,IAAI,YAAY,EAAE,SAAS,mBAAmB;AAElD;AAGA,SAAS,WAAW,SAAyB;AAC3C,QAAM,OAAO,KAAK,MAAM,UAAU,CAAC;AACnC,SAAO,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,UAAU,OAAO,EAAE;AAC/D;AAQA,eAAsB,gBACpB,YACA,WACA,UAAkC,CAAC,GACN;AAC7B,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,qBAAqB,CAAC,KAAO,KAAO,KAAO,IAAM;AAAA,IACjD,mBAAmB;AAAA,EACrB,IAAI;AAmBJ,QAAM,gBAAgB;AAAA,IACpB,GAAG,OAAO,OAAO,UAAU;AAAA;AAAA,IAC3B,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,iBAAiB;AAAA;AAAA,IAClC,GAAG,OAAO,OAAO,gBAAgB;AAAA;AAAA,IACjC,GAAG,OAAO,OAAO,aAAa;AAAA,IAC9B,GAAG,OAAO,OAAO,cAAc;AAAA,IAC/B,GAAG,OAAO,OAAO,qBAAqB;AAAA,IACtC,GAAG,OAAO,OAAO,aAAa;AAAA,IAC9B,GAAG,OAAO,OAAO,cAAc;AAAA,IAC/B,GAAG,OAAO,OAAO,eAAe;AAAA,IAChC,GAAG,OAAO,OAAO,gBAAgB;AAAA,IACjC,GAAG,OAAO,OAAO,uBAAuB;AAAA,EAC1C;AACA,QAAM,aAAa,oBAAI,IAAuD;AAC9E,aAAW,QAAQ,eAAe;AAChC,UAAM,WAAW,WAAW,IAAI,KAAK,QAAQ;AAC7C,QAAI,CAAC,YAAY,KAAK,cAAc,SAAS,aAAa;AACxD,iBAAW,IAAI,KAAK,UAAU,IAAI;AAAA,IACpC;AAAA,EACF;AACA,QAAM,YAAY,CAAC,GAAG,WAAW,OAAO,CAAC;AAEzC,MAAI,cAA0B,CAAC;AAM/B,iBAAe,mBACb,MACqB;AACrB,aAAS,UAAU,GAAG,WAAW,mBAAmB,QAAQ,WAAW;AACrE,UAAI;AACF,cAAM,UAAU,MAAM,WAAW,mBAAmB,WAAW;AAAA,UAC7D,SAAS,CAAC,EAAE,UAAU,KAAK,SAAS,CAAC;AAAA,UACrC,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,QACtD,CAAC;AACD,eAAO,QAAQ,IAAI,YAAU,EAAE,GAAG,OAAO,aAAa,KAAK,aAAa,UAAU,KAAK,SAAS,EAAE;AAAA,MACpG,SAAS,KAAK;AACZ,YAAI,iBAAiB,GAAG,KAAK,UAAU,mBAAmB,QAAQ;AAChE,gBAAM,QAAQ,WAAW,mBAAmB,OAAO,CAAC;AACpD,kBAAQ;AAAA,YACN,0CAA0C,KAAK,QAAQ,YAAY,UAAU,CAAC,iBAAiB,KAAK;AAAA,UACtG;AACA,gBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,KAAK,CAAC;AAC3C;AAAA,QACF;AAEA,gBAAQ;AAAA,UACN,iDAAiD,KAAK,QAAQ,aAAa,UAAU,CAAC;AAAA,UACtF,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AACA,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,iBAAiB,QAAQ,kBAAkB,UAAU;AAC3D,QAAM,eAAe,UAAU,MAAM,GAAG,cAAc;AAGtD,QAAM,4BAA4B,KAAK,IAAI,GAAG,OAAO,SAAS,gBAAgB,IAAI,mBAAmB,CAAC;AAEtG,MAAI;AACF,QAAI,YAAY;AAEd,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAM,OAAO,aAAa,CAAC;AAC3B,cAAM,UAAU,MAAM,mBAAmB,IAAI;AAC7C,oBAAY,KAAK,GAAG,OAAO;AAC3B,YAAI,IAAI,aAAa,SAAS,GAAG;AAC/B,gBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,gBAAgB,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF,OAAO;AAGL,eAAS,SAAS,GAAG,SAAS,aAAa,QAAQ,UAAU,2BAA2B;AACtF,cAAM,QAAQ,aAAa,MAAM,QAAQ,SAAS,yBAAyB;AAC3E,cAAM,UAAU,MAAM;AAAA,UAAI,UACxB,WAAW,mBAAmB,WAAW;AAAA,YACvC,SAAS,CAAC,EAAE,UAAU,KAAK,SAAS,CAAC;AAAA,YACrC,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,UACtD,CAAC,EAAE;AAAA,YAAK,CAAAI,aACNA,SAAQ,IAAI,YAAU;AAAA,cACpB,GAAG;AAAA,cACH,aAAa,KAAK;AAAA,cAClB,UAAU,KAAK;AAAA,YACjB,EAAE;AAAA,UACJ;AAAA,QACF;AAEA,cAAM,UAAU,MAAM,QAAQ,WAAW,OAAO;AAChD,mBAAW,UAAU,SAAS;AAC5B,cAAI,OAAO,WAAW,aAAa;AACjC,uBAAW,SAAS,OAAO,OAAO;AAChC,0BAAY,KAAK,KAAiB;AAAA,YACpC;AAAA,UACF,OAAO;AACL,oBAAQ;AAAA,cACN;AAAA,cACA,OAAO,kBAAkB,QAAQ,OAAO,OAAO,UAAU,OAAO;AAAA,YAClE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAMA,QAAI;AACF,YAAM,aAAa,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAChE,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO,OAAO,KAAK,eAAe,EAAE,SAAS,QAAQ;AAAA,cACrD,UAAU;AAAA,YACZ;AAAA,UACF;AAAA,QACF;AAAA,QACA,WAAW,EAAE,QAAQ,GAAG,QAAQ,oBAAoB;AAAA,MACtD,CAAC;AACD,iBAAW,KAAK,YAAY;AAC1B,oBAAY,KAAK,EAAE,GAAG,GAAG,aAAa,GAAG,UAAU,EAAE,QAAQ,KAAK,OAAO,CAAa;AAAA,MACxF;AAAA,IACF,QAAQ;AAAA,IAER;AAIA,QAAI,YAAY,WAAW,GAAG;AAC5B,cAAQ,KAAK,+EAA+E;AAG5F,YAAM,WAAW,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC9D,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AACD,oBAAc,CAAC,GAAG,QAAQ,EAAE,IAAI,OAAK;AACnC,cAAM,MAAM,EAAE,QAAQ,KAAK;AAC3B,cAAM,MAAM,iBAAiB,KAAK,IAAI,WAAW,EAAE,QAAQ,IAAI,CAAC;AAChE,eAAO,EAAE,GAAG,GAAG,aAAa,KAAK,eAAe,MAAM,UAAU,IAAI;AAAA,MACtE,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN;AAAA,MACA,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AACA,QAAI;AAEF,YAAM,WAAW,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC9D,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AACD,oBAAc,CAAC,GAAG,QAAQ,EAAE,IAAI,OAAK;AACnC,cAAM,MAAM,EAAE,QAAQ,KAAK;AAC3B,cAAM,MAAM,iBAAiB,KAAK,IAAI,WAAW,EAAE,QAAQ,IAAI,CAAC;AAChE,eAAO,EAAE,GAAG,GAAG,aAAa,KAAK,eAAe,MAAM,UAAU,IAAI;AAAA,MACtE,CAAC;AAAA,IACH,SAAS,WAAW;AAElB,cAAQ;AAAA,QACN;AAAA,QACA,qBAAqB,QAAQ,UAAU,UAAU;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAKA,MAAI,YAAY,WAAW,KAAK,QAAQ,YAAY;AAClD,YAAQ;AAAA,MACN;AAAA,IACF;AACA,QAAI;AACF,YAAM,YAAY,MAAM;AAAA,QACtB;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,EAAE,WAAW,QAAQ,aAAa;AAAA,MACpC;AACA,UAAI,UAAU,SAAS,GAAG;AACxB,eAAO;AAAA,MACT;AAEA,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,SAAS,QAAQ;AACf,cAAQ;AAAA,QACN;AAAA,QACA,kBAAkB,QAAQ,OAAO,UAAU;AAAA,MAC7C;AAAA,IAEF;AAAA,EACF;AAKA,MAAI,YAAY,WAAW,KAAK,QAAQ,SAAS;AAC/C,UAAM,gBAAgB,iBAAiB,QAAQ,OAAO;AACtD,QAAI,cAAc,SAAS,GAAG;AAC5B,cAAQ;AAAA,QACN,qEAAqE,cAAc,MAAM,kBAAkB,QAAQ,OAAO;AAAA,MAC5H;AACA,UAAI;AACF,eAAO,MAAM;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF,SAAS,WAAW;AAClB,gBAAQ;AAAA,UACN;AAAA,UACA,qBAAqB,QAAQ,UAAU,UAAU;AAAA,QACnD;AAAA,MAEF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN,qDAAqD,QAAQ,OAAO;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW;AAEjB,QAAM,UAA8B,CAAC;AAGrC,QAAM,cAAc,oBAAI,IAAY;AAEpC,aAAW,EAAE,QAAQ,SAAS,aAAa,SAAS,KAAK,UAAU;AACjE,UAAM,QAAQ,OAAO,SAAS;AAC9B,QAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,gBAAY,IAAI,KAAK;AACrB,UAAM,OAAO,IAAI,WAAW,QAAQ,IAAI;AAUxC,QAAI,mBAAmB,IAAI,GAAG;AAC5B,UAAI;AACF,cAAM,YAAY,sBAAsB,IAAI;AAC5C,gBAAQ,KAAK;AAAA,UACX,aAAa;AAAA,UACb;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,iDAAiD,KAAK;AAAA,UACtD,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAI,KAAK,CAAC,MAAM,YAAY,CAAC,GAAG;AAC9B,gBAAQ;AACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,MAAO;AAKZ,UAAM,SAAS,iBAAiB,UAAU,IAAI;AAE9C,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN,sCAAsC,KAAK,sCAAsC,QAAQ;AAAA,MAC3F;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,YAAY,MAAM,MAAM;AACvC,YAAM,SAAS,iBAAiB,MAAM,QAAQ,WAAW;AACzD,YAAM,SAAS,YAAY,MAAM,MAAM;AAEvC,cAAQ,KAAK,EAAE,aAAa,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjF,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,6CAA6C,OAAO,SAAS,CAAC;AAAA,QAC9D,eAAe,QAAQ,IAAI,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAwDA,eAAsB,oBACpB,YACA,WACA,WACA,UAAsC,CAAC,GACV;AAC7B,MAAI,UAAU,WAAW,EAAG,QAAO,CAAC;AAEpC,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,oBAAoB;AAAA,EACtB,IAAI;AAEJ,QAAM,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,GAAG,CAAC;AAI/D,QAAM,UAA2B,CAAC;AAElC,WAAS,SAAS,GAAG,SAAS,UAAU,QAAQ,UAAU,oBAAoB;AAC5E,UAAM,QAAQ,UAAU,MAAM,QAAQ,SAAS,kBAAkB;AAEjE,UAAM,WAAW,MAAM,WAAW,wBAAwB,KAAK;AAE/D,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,OAAO,SAAS,CAAC;AACvB,UAAI,QAAQ,KAAK,MAAM;AACrB,YAAI,CAAC,KAAK,MAAM,OAAO,SAAS,GAAG;AACjC,kBAAQ;AAAA,YACN,kCAAkC,MAAM,CAAC,EAAE,SAAS,CAAC,8BACxC,UAAU,SAAS,CAAC,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,UACjE;AACA;AAAA,QACF;AACA,gBAAQ,KAAK,EAAE,QAAQ,MAAM,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC;AAAA,MACpD;AAAA,IACF;AAGA,QAAI,oBAAoB,KAAK,SAAS,qBAAqB,UAAU,QAAQ;AAC3E,YAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,iBAAiB,CAAC;AAAA,IACzD;AAAA,EACF;AAGA,QAAM,UAA8B,CAAC;AAErC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAO;AACZ,UAAM,EAAE,QAAQ,MAAM,QAAQ,IAAI;AAClC,UAAM,OAAO,IAAI,WAAW,OAAO;AAKnC,QAAI,mBAAmB,IAAI,GAAG;AAC5B,UAAI;AACF,cAAM,YAAY,sBAAsB,IAAI;AAI5C,gBAAQ,KAAK;AAAA,UACX,aAAa;AAAA,UACb;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,CAAC;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,qDAAqD,OAAO,SAAS,CAAC;AAAA,UACtE,eAAe,QAAQ,IAAI,UAAU;AAAA,QACvC;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,UAAI,KAAK,CAAC,MAAM,YAAY,CAAC,GAAG;AAC9B,gBAAQ;AACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,OAAO;AACV,cAAQ;AAAA,QACN,kCAAkC,OAAO,SAAS,CAAC;AAAA,MACrD;AACA;AAAA,IACF;AAGA,UAAM,SAAS,iBAAiB,KAAK,QAAQ,IAAI;AACjD,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN,kCAAkC,OAAO,SAAS,CAAC,sCAAsC,KAAK,MAAM;AAAA,MACtG;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,YAAY,IAAI;AAC/B,YAAM,SAAS,YAAY,MAAM,MAAM;AACvC,YAAM,SAAS,iBAAiB,MAAM,QAAQ,OAAO,WAAW;AAChE,YAAM,SAAS,YAAY,MAAM,MAAM;AAEvC,cAAQ,KAAK,EAAE,aAAa,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjF,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,iDAAiD,OAAO,SAAS,CAAC;AAAA,QAClE,eAAe,QAAQ,IAAI,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAqEA,eAAsB,sBACpB,YACA,WACA,YACA,UAAwC,CAAC,GACZ;AAC7B,QAAM,EAAE,YAAY,KAAQ,eAAe,IAAI;AAG/C,QAAM,OAAO,WAAW,QAAQ,QAAQ,EAAE;AAC1C,QAAM,MAAM,GAAG,IAAI;AAGnB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,KAAK;AAAA,MAC1B,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACtC,QAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,EACH,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AAEA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,wCAAwC,SAAS,MAAM,IAAI,SAAS,UAAU,SAAS,GAAG;AAAA,IAC5F;AAAA,EACF;AAEA,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAM,aAAa,KAAK;AAExB,MAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW,GAAG;AACzD,YAAQ,KAAK,gDAAgD;AAC7D,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,YAAyB,CAAC;AAChC,aAAW,SAAS,YAAY;AAC9B,QAAI,CAAC,MAAM,gBAAgB,OAAO,MAAM,iBAAiB,SAAU;AACnE,QAAI;AACF,gBAAU,KAAK,IAAIC,WAAU,MAAM,YAAY,CAAC;AAAA,IAClD,QAAQ;AACN,cAAQ;AAAA,QACN,0DAA0D,MAAM,YAAY;AAAA,MAC9E;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,KAAK,0DAA0D;AACvE,WAAO,CAAC;AAAA,EACV;AAEA,UAAQ;AAAA,IACN,wCAAwC,UAAU,MAAM;AAAA,EAC1D;AAGA,SAAO,oBAAoB,YAAY,WAAW,WAAW,cAAc;AAC7E;AAqDA,eAAsB,+BACpB,YACA,WACA,SACA,UAAiD,CAAC,GACrB;AAC7B,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAGlC,QAAM,YAAyB,CAAC;AAChC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,eAAe,OAAO,MAAM,gBAAgB,SAAU;AACjE,QAAI;AACF,gBAAU,KAAK,IAAIA,WAAU,MAAM,WAAW,CAAC;AAAA,IACjD,QAAQ;AACN,cAAQ;AAAA,QACN,mEAAmE,MAAM,WAAW;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,KAAK,2EAA2E;AACxF,WAAO,CAAC;AAAA,EACV;AAEA,UAAQ;AAAA,IACN,6CAA6C,UAAU,MAAM;AAAA,EAC/D;AAEA,SAAO,oBAAoB,YAAY,WAAW,WAAW,QAAQ,cAAc;AACrF;;;AE1yCA,SAAqB,aAAAC,kBAAiB;AA6B/B,SAAS,cAAc,gBAA2C;AACvE,MAAI,eAAe,OAAO,mBAAmB,EAAG,QAAO;AACvD,MAAI,eAAe,OAAO,uBAAuB,EAAG,QAAO;AAC3D,MAAI,eAAe,OAAO,uBAAuB,EAAG,QAAO;AAC3D,SAAO;AACT;AAWO,SAAS,aACd,SACA,aACA,MACa;AACb,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO,kBAAkB,aAAa,IAAI;AAAA,IAC5C,KAAK;AACH,aAAO,qBAAqB,aAAa,IAAI;AAAA,IAC/C,KAAK;AACH,aAAO,iBAAiB,aAAa,IAAI;AAAA,EAC7C;AACF;AA0BO,SAAS,sBACd,SACA,MACA,WACA,UACA,YACQ;AACR,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,6DAA6D;AAK7F,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,4DAA4D;AAAA,MAC9E;AACA,aAAO,uBAAuB,MAAM,WAAW,UAAU,UAAU;AAAA,IACrE,KAAK;AACH,aAAO,0BAA0B,IAAI;AAAA,IACvC,KAAK;AAIH,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,gEAAgE;AAAA,MAClF;AACA,aAAO,0BAA0B,MAAM,SAAS,MAAM,SAAS,KAAK;AAAA,EACxE;AACF;AAYO,IAAM,2BAA2B;AA6BxC,eAAsB,kBACpB,YACA,MACiB;AACjB,QAAM,OAAO,MAAM,WAAW,eAAe,IAAI;AACjD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,iDAAiD,KAAK,SAAS,CAAC,EAAE;AAAA,EACpF;AACA,MAAI,KAAK,KAAK,UAAU,0BAA0B;AAChD,UAAM,IAAI;AAAA,MACR,8CAA8C,KAAK,KAAK,MAAM,oBAAoB,KAAK,SAAS,CAAC;AAAA,IACnG;AAAA,EACF;AACA,SAAO,KAAK,KAAK,wBAAwB;AAC3C;AAWO,IAAM,YAAY,IAAIC,WAAU,6CAA6C;AA2BpF,IAAM,mBAAmB;AAMzB,SAAS,kBAAkB,aAAwB,MAA+B;AAChF,MAAI,KAAK,SAAS,kBAAkB;AAClC,UAAM,IAAI,MAAM,iCAAiC,KAAK,MAAM,MAAM,gBAAgB,EAAE;AAAA,EACtF;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIA,WAAU,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA,IAC1C,WAAW,IAAIA,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC5C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,IAC7C,YAAY,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAChD;AACF;AAEA,IAAM,2BAA2B;AA0BjC,SAAS,uBACP,UACA,WACA,UACA,YACQ;AACR,MAAI,SAAS,SAAS,kBAAkB;AACtC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,MAAM,gBAAgB,EAAE;AAAA,EAC1F;AACA,MAAI,UAAU,KAAK,SAAS,0BAA0B;AACpD,UAAM,IAAI,MAAM,uCAAuC,UAAU,KAAK,MAAM,MAAM,wBAAwB,EAAE;AAAA,EAC9G;AACA,MAAI,UAAU,MAAM,SAAS,0BAA0B;AACrD,UAAM,IAAI,MAAM,wCAAwC,UAAU,MAAM,MAAM,MAAM,wBAAwB,EAAE;AAAA,EAChH;AACA,sBAAoB,YAAY,QAAQ,SAAS,IAAI;AACrD,sBAAoB,YAAY,SAAS,SAAS,KAAK;AAEvD,QAAM,SAAS,IAAI,SAAS,UAAU,KAAK,QAAQ,UAAU,KAAK,YAAY,UAAU,KAAK,UAAU;AACvG,QAAM,UAAU,IAAI,SAAS,UAAU,MAAM,QAAQ,UAAU,MAAM,YAAY,UAAU,MAAM,UAAU;AAE3G,QAAM,aAAaC,WAAU,QAAQ,EAAE;AACvC,QAAM,cAAcA,WAAU,SAAS,EAAE;AAEzC,MAAI,eAAe,GAAI,QAAO;AAO9B,QAAM,YAAY,OAAO,OAAO,SAAS,IAAI;AAC7C,QAAM,aAAa,OAAO,OAAO,SAAS,KAAK;AAC/C,QAAM,iBAAkB,cAAc,YAAY,YAAe,aAAa;AAE9E,QAAM,YAAY,IAAID,WAAU,SAAS,MAAM,IAAI,GAAG,CAAC;AACvD,MAAI,UAAU,OAAO,SAAS,GAAG;AAE/B,QAAI,eAAe,QAAW;AAC5B,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAQ,iBAAiB,aAAc;AAAA,EACzC;AAGA,SAAO;AACT;AAMA,IAAM,uBAAuB;AAM7B,SAAS,qBAAqB,aAAwB,MAA+B;AACnF,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,qCAAqC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EAC9F;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIA,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC3C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AACF;AAYA,IAAM,qBAAqB;AAE3B,SAAS,oBAAoB,SAAiB,OAAe,UAAwB;AACnF,MAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,KAAK,WAAW,oBAAoB;AAChF,UAAM,IAAI;AAAA,MACR,GAAG,OAAO,KAAK,KAAK,2BAA2B,QAAQ,0BAA0B,kBAAkB;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,0BAA0B,MAA0B;AAC3D,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EACzF;AACA,QAAME,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAErE,QAAM,YAAY,KAAK,GAAG;AAC1B,QAAM,YAAY,KAAK,GAAG;AAE1B,MAAI,YAAY,sBAAsB,YAAY,oBAAoB;AACpE,UAAM,IAAI;AAAA,MACR,wCAAwC,SAAS,KAAK,SAAS,UAAU,kBAAkB;AAAA,IAC7F;AAAA,EACF;AAEA,QAAM,eAAeC,YAAWD,KAAI,GAAG;AAEvC,MAAI,iBAAiB,GAAI,QAAO;AAUhC,QAAM,QAAQ,eAAe,eAAe;AAE5C,QAAM,cAAc,IAAI,YAAY;AACpC,QAAM,eAAe,cAAc;AAEnC,MAAI,gBAAgB,GAAG;AACrB,WAAQ,QAAQ,OAAO,OAAO,YAAY,KAAM;AAAA,EAClD,OAAO;AACL,WAAO,UAAU,MAAM,QAAQ,OAAO,OAAO,CAAC,YAAY;AAAA,EAC5D;AACF;AAwBA,IAAM,uBAAuB;AAW7B,SAAS,iBAAiB,aAAwB,MAA+B;AAC/E,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,qCAAqC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EAC9F;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,UAAU,IAAIF,WAAU,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA,IAC3C,WAAW,IAAIA,WAAU,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EAC/C;AACF;AAYA,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAE1B,SAAS,0BACP,MACA,cACA,eACQ;AACR,MAAI,KAAK,SAAS,sBAAsB;AACtC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,oBAAoB,EAAE;AAAA,EACzF;AACA,sBAAoB,gBAAgB,QAAQ,YAAY;AACxD,sBAAoB,gBAAgB,SAAS,aAAa;AAC1D,QAAME,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAMrE,QAAM,UAAUA,IAAG,UAAU,IAAI,IAAI;AACrC,QAAM,WAAWA,IAAG,SAAS,IAAI,IAAI;AAErC,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,UAAU,cAAc;AAC1B,UAAM,IAAI,MAAM,yBAAyB,OAAO,gBAAgB,YAAY,EAAE;AAAA,EAChF;AACA,MAAI,KAAK,IAAI,QAAQ,IAAI,mBAAmB;AAC1C,UAAM,IAAI;AAAA,MACR,4BAA4B,KAAK,IAAI,QAAQ,CAAC,gBAAgB,iBAAiB;AAAA,IACjF;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,QAAM,OAAO,QAAS,OAAO,OAAO,IAAI,QAAS;AAEjD,QAAM,QAAQ,WAAW;AACzB,MAAI,MAAM,QAAQ,OAAO,CAAC,QAAQ,IAAI,OAAO,QAAQ;AAErD,MAAI,SAAS;AACb,MAAI,IAAI;AAER,SAAO,MAAM,IAAI;AACf,QAAI,MAAM,IAAI;AACZ,eAAU,SAAS,IAAK;AAAA,IAC1B;AACA,YAAQ;AACR,QAAI,MAAM,IAAI;AACZ,UAAK,IAAI,IAAK;AAAA,IAChB;AAAA,EACF;AASA,QAAM,OAAO,eAAe;AAE5B,MAAI,OAAO;AACT,QAAI,WAAW,GAAI,QAAO;AAE1B,UAAM,MAAM;AACZ,QAAI,QAAQ,GAAG;AACb,aAAQ,MAAM,OAAO,OAAO,IAAI,IAAK;AAAA,IACvC;AACA,WAAO,OAAO,SAAS,OAAO,OAAO,CAAC,IAAI;AAAA,EAC5C,OAAO;AAEL,QAAI,QAAQ,GAAG;AACb,aAAQ,SAAS,OAAO,OAAO,IAAI,IAAK;AAAA,IAC1C;AACA,WAAO,UAAU,iBAAqB,OAAO,OAAO,CAAC,IAAI;AAAA,EAC3D;AACF;AAOA,SAASD,WAAUC,KAAc,QAAwB;AACvD,QAAM,KAAK,OAAOA,IAAG,UAAU,QAAQ,IAAI,CAAC;AAC5C,QAAM,KAAK,OAAOA,IAAG,UAAU,SAAS,GAAG,IAAI,CAAC;AAChD,SAAO,KAAM,MAAM;AACrB;AAGA,SAASC,YAAWD,KAAc,QAAwB;AACxD,QAAM,KAAKD,WAAUC,KAAI,MAAM;AAC/B,QAAM,KAAKD,WAAUC,KAAI,SAAS,CAAC;AACnC,SAAO,KAAM,MAAM;AACrB;;;AClfA,IAAM,qBAAqB;AAG3B,IAAM,eAAe;AAGrB,IAAM,4BAA4B;AAOlC,IAAM,6BAA6B;AAMnC,IAAM,0BAA0B;AA4BhC,SAASE,QAAO,MAAkB,KAAqB;AACrD,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,eAAe,MAAkB,KAAqB;AAC7D,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,YAAY,KAAK,IAAI;AAC1F;AAEA,SAAS,gBAAgB,MAAkB,KAAqB;AAC9D,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,aAAa,KAAK,IAAI;AAC3F;AAEA,SAASC,WAAU,MAAkB,KAAqB;AACxD,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,EAAE,UAAU,KAAK,IAAI;AACxF;AAWA,IAAM,mCAAmC;AAqBlC,SAAS,oBAAoB,MAAkB,SAA8C;AAClG,MAAI,KAAK,SAAS,oBAAoB;AACpC,UAAM,IAAI;AAAA,MACR,kCAAkC,KAAK,MAAM,yBAAyB,kBAAkB;AAAA,IAC1F;AAAA,EACF;AAEA,QAAM,WAAWD,QAAO,MAAM,yBAAyB;AACvD,MAAI,WAAW,cAAc;AAC3B,UAAM,IAAI;AAAA,MACR,iCAAiC,QAAQ,SAAS,YAAY;AAAA,IAChE;AAAA,EACF;AAYA,QAAM,SACH,eAAe,MAAM,0BAA0B,CAAC,KAAK,MACtD,gBAAgB,MAAM,uBAAuB;AAC/C,MAAI,UAAU,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,iCAAiC,MAAM;AAAA,IACzC;AAAA,EACF;AACA,QAAM,QAAQ;AAGd,QAAM,YAAYC,WAAU,MAAM,0BAA0B;AAE5D,MAAI,SAAS,wBAAwB,QAAW;AAI9C,QAAI,aAAa,GAAG;AAClB,YAAM,IAAI;AAAA,QACR,oDAAoD,SAAS;AAAA,MAC/D;AAAA,IACF;AACA,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,UAAM,MAAM,MAAM;AAIlB,UAAM,kBACJ,QAAQ,0BAA0B;AACpC,QAAI,MAAM,CAAC,iBAAiB;AAC1B,YAAM,IAAI;AAAA,QACR,+BAA+B,CAAC,GAAG,8BAA8B,eAAe;AAAA,MAElF;AAAA,IACF;AACA,QAAI,MAAM,QAAQ,qBAAqB;AACrC,YAAM,IAAI;AAAA,QACR,uCAAuC,GAAG,cAAc,QAAQ,mBAAmB;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,UAAU,WAAW,YAAY,IAAI,YAAY,OAAU;AAC7E;AAOO,SAAS,uBAAuB,MAA2B;AAChE,MAAI;AACF,wBAAoB,IAAI;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AChNA,SAAqB,aAAAC,mBAAiB;AACtC,SAAS,oBAAAC,yBAAwB;AAK1B,IAAM,wBAAwB,IAAID;AAAA,EACvC;AACF;AAeA,eAAsB,mBACpB,YACA,MACoB;AACpB,QAAM,OAAO,MAAM,WAAW,eAAe,IAAI;AACjD,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,2BAA2B,KAAK,SAAS,CAAC,EAAE;AAEvE,MAAI,KAAK,MAAM,OAAOC,iBAAgB,EAAG,QAAOA;AAChD,MAAI,KAAK,MAAM,OAAO,qBAAqB,EAAG,QAAO;AAErD,QAAM,IAAI;AAAA,IACR,WAAW,KAAK,SAAS,CAAC,+BAA+B,KAAK,MAAM,SAAS,CAAC,0BACnDA,kBAAiB,SAAS,CAAC,qBACrC,sBAAsB,SAAS,CAAC;AAAA,EACnD;AACF;AAKO,SAAS,YAAY,gBAAoC;AAC9D,SAAO,eAAe,OAAO,qBAAqB;AACpD;AAKO,SAAS,gBAAgB,gBAAoC;AAClE,SAAO,eAAe,OAAOA,iBAAgB;AAC/C;;;AC/BA,SAAS,aAAAC,aAAW,iBAAAC,gBAAe,sBAAAC,qBAAoB,uBAAAC,4BAA2B;AAClF,SAAS,oBAAAC,mBAAkB,yBAAAC,8BAA6B;AAiCjD,IAAM,oBAAoB;AAAA,EAC/B,QAAQ;AAAA,EACR,SAAS;AACX;AACA,OAAO,OAAO,iBAAiB;AAG/B,IAAM,0BAA0B,IAAI,IAAY,OAAO,OAAO,iBAAiB,CAAC;AAYzE,SAAS,kBAAkB,SAA2C;AAI3E,MAAI,CAAC,SAAS;AACZ,UAAM,WAAW,QAAQ,kBAAkB;AAC3C,QAAI,UAAU;AAGZ,UACE,CAAC,wBAAwB,IAAI,QAAQ,KACrC,QAAQ,uCAAuC,MAAM,KACrD;AACA,cAAM,IAAI;AAAA,UACR,8CAA8C,QAAQ,2DACnC,CAAC,GAAG,uBAAuB,EAAE,KAAK,IAAI,CAAC;AAAA,QAG5D;AAAA,MACF;AACA,cAAQ;AAAA,QACN,0DAA0D,QAAQ;AAAA,MACpE;AACA,aAAO,IAAIC,YAAU,QAAQ;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,kBACJ,YACC,MAAM;AACL,UAAM,IAAI,QAAQ,6BAA6B,GAAG,YAAY,KACpD,QAAQ,SAAS,GAAG,YAAY,KAAK;AAC/C,QAAI,MAAM,aAAa,MAAM,eAAgB,QAAO;AACpD,QAAI,MAAM,SAAU,QAAO;AAkB3B,UAAM,IAAI;AAAA,MACR;AAAA,IASF;AAAA,EACF,GAAG;AAEL,QAAM,KAAK,kBAAkB,eAAe;AAC5C,MAAI,CAAC,IAAI;AACP,UAAM,IAAI;AAAA,MACR,iCAAiC,eAAe;AAAA,IAElD;AAAA,EACF;AACA,SAAO,IAAIA,YAAU,EAAE;AACzB;AAUO,IAAM,mBAAmB,IAAIA,YAAU,kBAAkB,MAAM;AAkB/D,IAAM,WAAW;AAAA,EACtB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAed,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYd,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcb,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWzB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWxB,wBAAwB;AAAA;AAAA;AAAA,EAGxB,eAAe;AAAA;AAAA;AAAA,EAGf,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,uBAAuB;AAAA;AAAA;AAAA;AAAA,EAIvB,wBAAwB;AAAA;AAAA;AAAA;AAAA,EAIxB,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,iBAAiB;AAAA;AAAA,EAEjB,wBAAwB;AAAA;AAAA;AAAA,EAGxB,yBAAyB;AAAA;AAAA,EAEzB,YAAY;AAAA;AAAA,EAEZ,iBAAiB;AAAA;AAAA,EAEjB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcnB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAef,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYxB,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW1B,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAezB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBzB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYvB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAenB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAarB,kCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAalC,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY7B,2BAA2B;AAC7B;AACA,OAAO,OAAO,QAAQ;AAmBf,IAAM,eAAuC;AAAA,EAClD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AACA,OAAO,OAAO,YAAY;AAM1B,IAAMC,QAAO,IAAI,YAAY;AAGtB,SAAS,gBAAgB,MAAiB,WAAuB;AACtE,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,YAAY,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AACvF;AAGO,SAAS,qBAAqB,MAAiB,WAAuB;AAC3E,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,YAAY,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AACvF;AAGO,SAAS,iBAAiB,MAAiB,MAAiB,WAAuB;AACxF,SAAOD,YAAU;AAAA,IACf,CAACC,MAAK,OAAO,eAAe,GAAG,KAAK,QAAQ,GAAG,KAAK,QAAQ,CAAC;AAAA,IAAM,aAAa,kBAAkB;AAAA,EAAI;AAC1G;AAMA,SAASC,WAAU,MAAkB,KAAqB;AACxD,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,SAAO,KAAK;AAAA,IAAa;AAAA;AAAA,IAAyB;AAAA,EAAI;AACxD;AAGA,SAASC,WAAU,MAAkB,KAAqB;AACxD,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,SAAO,KAAK;AAAA,IAAU;AAAA;AAAA,IAAyB;AAAA,EAAI;AACrD;AAEA,SAAS,qBACP,aACA,MACA,QACA,UACM;AACN,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AAC3C,QAAI,KAAK,SAAS,CAAC,MAAM,SAAS,CAAC,GAAG;AACpC,YAAM,IAAI,MAAM,GAAG,WAAW,wBAAwB;AAAA,IACxD;AAAA,EACF;AACF;AAMA,SAAS,MAAM,GAAgC;AAC7C,MAAI,OAAO,MAAM,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;AACrD,UAAM,IAAI,MAAM,iBAAiB,CAAC,oDAA+C;AAAA,EACnF;AAEA,QAAM,MAAM,OAAO,CAAC;AACpB,MAAI,MAAM,GAAI,OAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AAC7E,MAAI,MAAM,oBAAwB,OAAM,IAAI,MAAM,8BAA8B;AAChF,QAAM,MAAM,IAAI,WAAW,CAAC;AAC5B,MAAI,SAAS,IAAI,MAAM,EAAE,aAAa,GAAG,KAAK,IAAI;AAAI,SAAO;AAC/D;AAEA,SAAS,OAAO,GAAgC;AAC9C,MAAI,OAAO,MAAM,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;AACrD,UAAM,IAAI,MAAM,kBAAkB,CAAC,oDAA+C;AAAA,EACpF;AAEA,QAAM,MAAM,OAAO,CAAC;AACpB,MAAI,MAAM,GAAI,OAAM,IAAI,MAAM,2CAA2C,GAAG,EAAE;AAC9E,MAAI,OAAO,MAAM,QAAQ,GAAI,OAAM,IAAI,MAAM,gCAAgC;AAC7E,QAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,QAAM,OAAO,IAAI,SAAS,IAAI,MAAM;AAAI,OAAK,aAAa,GAAG,MAAM,qBAAqB,IAAI;AAC5F,OAAK,aAAa,GAAG,OAAO,KAAK,IAAI;AACrC,SAAO;AACT;AAEA,SAAS,MAAM,GAAuB;AACpC,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,MAAQ,OAAM,IAAI,MAAM,iDAAiD,CAAC,EAAE;AAAI,QAAM,MAAM,IAAI,WAAW,CAAC;AAAI,MAAI,SAAS,IAAI,MAAM,EAAE,UAAU,GAAG,GAAG,IAAI;AACtM,SAAO;AACT;AAGO,SAAS,oBAAoB,eAAgC,YAAyC;AAC3G,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,QAAQ,CAAC;AAAA,IAClC,MAAM,aAAa;AAAA,IACnB,MAAM,UAAU;AAAA,EAClB;AACF;AAGO,SAAS,mBAAmB,QAAqC;AACtE,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC;AACtE;AAGO,SAAS,oBAAoB,UAAuC;AACzE,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,QAAQ,CAAC,GAAG,MAAM,QAAQ,CAAC;AACzE;AAGO,SAAS,4BAA4B,QAAqC;AAC/E,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,gBAAgB,CAAC,GAAG,MAAM,MAAM,CAAC;AAC/E;AAGO,SAAS,wBACd,kBACA,eACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,YAAY,CAAC;AAAA,IACtC,IAAI,WAAW,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;AAAA,IACjD,MAAM,oBAAoB,EAAE;AAAA,IAC5B,IAAI,WAAW,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;AAAA,IAC9C,MAAM,iBAAiB,EAAE;AAAA,EAC3B;AACF;AAEA,SAAS,wBAAwB,MAAc,KAAoB;AACjE,QAAM,IAAI;AAAA,IACR,GAAG,IAAI,eAAe,GAAG;AAAA,EAC3B;AACF;AAWO,SAAS,wBAAwB,UAAiC;AACvE,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,YAAY,CAAC;AAAA,IACtC,SAAS,QAAQ;AAAA,EACnB;AACF;AAQO,SAAS,yBAAqC;AACnD,SAAO,IAAI,WAAW,CAAC,SAAS,WAAW,CAAC;AAC9C;AAUO,SAAS,mCAAmC,kBAA+C;AAChG,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAAA,IACjD,MAAM,gBAAgB;AAAA,EACxB;AACF;AAQO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AAQO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AASO,SAAS,2BAAuC;AACrD,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,mCAAmC,cAAqC;AACtF,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,iCAAiC,cAA2C;AAC1F,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,kCAAkC,QAAqC;AACrF,OAAK;AACL,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAOO,SAAS,gCAA4C;AAC1D,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAGO,SAAS,2BAA2B,QAAqC;AAC9E,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,eAAe,CAAC;AAAA,IACzC,MAAM,MAAM;AAAA,EACd;AACF;AAGO,SAAS,kCAAkC,QAAqC;AACrF,SAAO,2BAA2B,MAAM;AAC1C;AAGO,SAAS,wBAAoC;AAClD,SAAO,IAAI,WAAW,CAAC,SAAS,UAAU,CAAC;AAC7C;AAGO,SAAS,2BAA2B,eAAgC,YAAyC;AAClH,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,eAAe,CAAC;AAAA,IACzC,MAAM,aAAa;AAAA,IACnB,MAAM,UAAU;AAAA,EAClB;AACF;AAGO,SAAS,6BACd,SACA,aACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,iBAAiB,CAAC;AAAA,IAC3C,IAAI,WAAW,CAAC,UAAU,IAAI,CAAC,CAAC;AAAA,IAChC,MAAM,WAAW;AAAA,EACnB;AACF;AAcO,SAAS,iCAAiC,kBAAsC;AACrF,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,qBAAqB,CAAC;AAAA,IAC/C,MAAM,gBAAgB;AAAA,EACxB;AACF;AAWO,SAAS,yBAAyB,QAAqC;AAC5E,SAAO,YAAY,IAAI,WAAW,CAAC,SAAS,aAAa,CAAC,GAAG,MAAM,MAAM,CAAC;AAC5E;AAaO,SAAS,+BAA2C;AACzD,SAAO,IAAI,WAAW,CAAC,SAAS,iBAAiB,CAAC;AACpD;AAsBO,SAAS,oCAAgD;AAC9D,SAAO,IAAI,WAAW,CAAC,SAAS,sBAAsB,CAAC;AACzD;AAyCO,SAAS,+BACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAkBO,SAAS,sCAAkD;AAChE,SAAO,IAAI,WAAW,CAAC,SAAS,wBAAwB,CAAC;AAC3D;AAkBO,SAAS,qCAAiD;AAC/D,SAAO,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAC1D;AAoCO,SAAS,wBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAmBO,SAAS,4BAAwC;AACtD,SAAO,IAAI,WAAW,CAAC,SAAS,cAAc,CAAC;AACjD;AA+BO,SAAS,uBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAuBO,SAAS,mCAAmC,QAAqC;AACtF,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,uBAAuB,CAAC;AAAA,IACjD,MAAM,MAAM;AAAA,EACd;AACF;AA2CO,SAAS,gCACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,QAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,SAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,WAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,WAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,eAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,cAAoB,UAAU,OAAO,YAAY,KAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,kBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,cAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,IACnE,EAAE,QAAQ,EAAE,mBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,EACrE;AACF;AAqBO,SAAS,mCAA+C;AAC7D,SAAO,IAAI,WAAW,CAAC,SAAS,qBAAqB,CAAC;AACxD;AA4BO,SAAS,8BACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAiDO,SAAS,+BACd,iBACA,YACA,mBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,mBAAmB,CAAC;AAAA,IAC7C,MAAM,eAAe;AAAA,IACrB,MAAM,UAAU;AAAA,IAChB,MAAM,iBAAiB;AAAA,EACzB;AACF;AAsBO,SAAS,4CACd,uBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,gCAAgC,CAAC;AAAA,IAC1D,OAAO,qBAAqB;AAAA,EAC9B;AACF;AAsBO,SAAS,uCACd,QACA,QACA,mBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,2BAA2B,CAAC;AAAA,IACrD,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,IACZ,MAAM,iBAAiB;AAAA,EACzB;AACF;AAqBO,SAAS,qCACd,iBACY;AACZ,SAAO;AAAA,IACL,IAAI,WAAW,CAAC,SAAS,yBAAyB,CAAC;AAAA,IACnD,MAAM,eAAe;AAAA,EACvB;AACF;AAiCO,SAAS,yBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAGO,IAAM,8BAA8B;AAGpC,IAAM,2CAA2C;AAuCjD,SAAS,yBACd,GACiE;AACjE,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAmB,UAAU,MAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,SAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,WAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,MAAmB,UAAU,OAAO,YAAY,KAAM;AAAA,IAClE,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AAGO,IAAM,sCAAsC;AAG5C,IAAM,oCAAoC;AAG1C,SAAS,mCACd,WACA,iBACA,gBACA,eACY;AACZ,OAAK;AACL,OAAK;AACL,OAAK;AACL,OAAK;AACL,SAAO,wBAAwB,sCAAsC,SAAS,uBAAuB;AACvG;AAuKO,IAAM,qBAAqB;AAe3B,IAAM,qBAAqB;AAiB3B,IAAM,qBAAqB;AAS3B,IAAM,kBAAkB;AACxB,IAAM,2BAA2B,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI,CAAC;AAChG,IAAM,6BAA6B;AAsBnC,SAAS,gBAAgB,MAAkC;AAChE,QAAM,OAAO,KAAK,UAAU;AAC5B,QAAM,OAAO,CAAC,QAAQ,KAAK,UAAU;AACrC,QAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,UAAU;AAC9C,MAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM;AAC3B,UAAM,IAAI,MAAM,6BAA6B,KAAK,MAAM,MAAM,kBAAkB,EAAE;AAAA,EACpF;AAIA,QAAM,iBAAiB,OAAO,MAAM;AACpC,uBAAqB,aAAa,MAAM,gBAAgB,wBAAwB;AAChF,QAAM,UAAU,KAAK,iBAAiB,CAAC;AACvC,QAAM,kBAAkB,OAAO,IAAI,OAAO,IAAI;AAC9C,MAAI,YAAY,iBAAiB;AAC/B,UAAM,IAAI,MAAM,kCAAkC,OAAO,QAAQ,eAAe,EAAE;AAAA,EACpF;AAEA,QAAM,QAAQ,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAC1E,MAAI,MAAM;AACV,QAAM,gBAAgB,MAAM,GAAG,MAAM;AAAG,SAAO;AAC/C,QAAM,OAAO,MAAM,GAAG;AAAG,SAAO;AAChC,QAAM,qBAAqB,MAAM,GAAG;AAAG,SAAO;AAC9C,QAAM,mBAAmB,MAAM,GAAG,MAAM;AAAG,SAAO;AAClD,SAAO;AAEP,QAAM,OAAO,IAAIH,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAClE,QAAM,QAAQ,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AACnE,QAAM,iBAAiB,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAC5E,QAAM,SAAS,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AACpE,QAAM,QAAQ,IAAIA,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAEnE,QAAM,iBAAiBE,WAAU,OAAO,GAAG;AAAG,SAAO;AACrD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,aAAaA,WAAU,OAAO,GAAG;AAAG,SAAO;AACjD,QAAM,eAAeA,WAAU,OAAO,GAAG;AAAG,SAAO;AACnD,QAAM,gBAAgBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACpD,QAAM,iBAAiBA,WAAU,OAAO,GAAG;AAAG,SAAO;AAErD,QAAM,oBAAoB,IAAIF,YAAU,MAAM,SAAS,KAAK,MAAM,EAAE,CAAC;AAAG,SAAO;AAG/E,QAAM,kBAAkBE,WAAU,OAAO,GAAG;AAAG,SAAO;AACtD,QAAM,qBAAqBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACzD,QAAM,oBAAoBA,WAAU,OAAO,GAAG;AAAG,SAAO;AACxD,QAAM,WAAW,MAAM,GAAG;AAAG,SAAO;AACpC,SAAO;AAIP,MAAI,eAAiC;AACrC,MAAI,QAAQ,MAAM;AAChB,UAAM,oBAAoB,MAAM,SAAS,KAAK,MAAM,EAAE;AAAG,WAAO;AAChE,mBAAe,kBAAkB,MAAM,OAAK,MAAM,CAAC,IAC/C,OACA,IAAIF,YAAU,iBAAiB;AAAA,EACrC;AAGA,QAAM,gBAAgB;AAKtB,QAAM,iBAAiB,MAAM,gBAAgB,CAAC,MAAM;AACpD,QAAM,aAAa,MAAM,gBAAgB,EAAE,MAAM;AACjD,QAAM,cAAcG,WAAU,OAAO,gBAAgB,EAAE;AACvD,QAAM,oBAAoBD,WAAU,OAAO,gBAAgB,EAAE;AAC7D,QAAM,eAAeA,WAAU,OAAO,gBAAgB,EAAE;AAGxD,QAAM,iBAAiB,MAAM,gBAAgB,EAAE,MAAM;AACrD,QAAM,gBAAgBA,WAAU,OAAO,gBAAgB,EAAE;AACzD,QAAM,gBAAgBA,WAAU,OAAO,gBAAgB,EAAE;AACzD,QAAM,mBAAmBC,WAAU,OAAO,gBAAgB,EAAE;AAI5D,QAAM,uBAAuBD,WAAU,OAAO,gBAAgB,EAAE;AAChE,QAAM,yBAAyBA,WAAU,OAAO,gBAAgB,EAAE;AAGlE,QAAM,qBAAqBA,WAAU,OAAO,gBAAgB,EAAE;AAC9D,QAAM,mBAAmB,MAAM,gBAAgB,EAAE,MAAM;AAMvD,QAAM,4BAA4B,OAC9BA,WAAU,OAAO,gBAAgB,EAAE,IACnC;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,IAAM,qBAAqB;AAC3B,IAAM,8BAA8B,IAAI,WAAW,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,IAAM,CAAI,CAAC;AAC1G,IAAM,gCAAgC;AAyB/B,SAAS,iBAAiB,MAAqC;AACpE,MAAI,KAAK,SAAS,oBAAoB;AACpC,UAAM,IAAI,MAAM,gCAAgC,KAAK,MAAM,MAAM,kBAAkB,EAAE;AAAA,EACvF;AACA,uBAAqB,gBAAgB,MAAM,+BAA+B,2BAA2B;AACrG,SAAO;AAAA,IACL,eAAe,KAAK,CAAC,MAAM;AAAA,IAC3B,MAAM,KAAK,CAAC;AAAA,IACZ,MAAM,IAAIF,YAAU,KAAK,SAAS,GAAG,EAAE,CAAC;AAAA,IACxC,MAAM,IAAIA,YAAU,KAAK,SAAS,IAAI,EAAE,CAAC;AAAA,IACzC,iBAAiBE,WAAU,MAAM,EAAE;AAAA,IACnC,UAAUA,WAAU,MAAM,EAAE;AAAA,EAC9B;AACF;AA4DO,SAAS,iBACd,GACA,iBAA4BE,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,OAAO,UAAU,MAAM,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC/D,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQC,eAAc,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IACtE,EAAE,QAAQC,qBAAoB,UAAU,OAAO,YAAY,MAAM;AAAA,EACnE;AACF;AASO,SAAS,gBACd,GACA,iBAA4BF,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,MAAM,UAAU,MAAM,YAAY,MAAM;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,KAAK;AAAA,IACjE,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,IACzD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,YAAY,UAAU,OAAO,YAAY,KAAK;AAAA,IAC1D,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQG,sBAAqB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQF,eAAc,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,EACxE;AACF;AASO,SAAS,iBACd,GACA,iBAA4BD,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,MAAM,UAAU,MAAM,YAAY,MAAM;AAAA,IACpD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,KAAK;AAAA,IACzD,EAAE,QAAQ,EAAE,QAAQ,UAAU,OAAO,YAAY,KAAK;AAAA,IACtD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,KAAK;AAAA,IACjE,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,YAAY,UAAU,OAAO,YAAY,KAAK;AAAA,IAC1D,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,IAC7D,EAAE,QAAQG,sBAAqB,UAAU,OAAO,YAAY,MAAM;AAAA,EACpE;AACF;AASO,SAAS,yBACd,GACA,iBAA4BH,mBAC5B;AACA,SAAO;AAAA,IACL,EAAE,QAAQ,EAAE,QAAQ,UAAU,MAAM,YAAY,MAAM;AAAA,IACtD,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,OAAO,UAAU,OAAO,YAAY,KAAK;AAAA,IACrD,EAAE,QAAQ,EAAE,WAAW,UAAU,OAAO,YAAY,MAAM;AAAA,IAC1D,EAAE,QAAQ,EAAE,MAAM,UAAU,OAAO,YAAY,KAAK;AAAA,IACpD,EAAE,QAAQ,EAAE,cAAc,UAAU,OAAO,YAAY,KAAK;AAAA,IAC5D,EAAE,QAAQ,EAAE,mBAAmB,UAAU,OAAO,YAAY,MAAM;AAAA,IAClE,EAAE,QAAQ,gBAAgB,UAAU,OAAO,YAAY,MAAM;AAAA,EAC/D;AACF;;;AC38DA,IAAM,8BACJ;AAiFF,SAAS,cAAc,KAAa,SAAyB;AAC3D,MAAI,YAAY,GAAI,QAAO;AAC3B,SAAQ,MAAM,SAAW;AAC3B;AAsBO,SAAS,eAAe,UAA+B;AAC5D,QAAM,SAAS,iBAAiB,SAAS,QAAQ,QAAQ;AACzD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACF,UAAM,SAAS,YAAY,QAAQ;AACnC,QAAI,OAAO,cAAc,GAAI,QAAO;AACpC,UAAM,SAAS,YAAY,UAAU,MAAM;AAC3C,QAAI,OAAO,cAAc,GAAI,QAAO;AACpC,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAyBA,eAAsB,wBACpB,YACA,MAC2B;AAC3B,QAAM,OAAO,MAAM,UAAU,YAAY,IAAI;AAC7C,SAAO,iBAAiB,IAAI;AAC9B;AAMO,SAAS,iBAAiB,UAAwC;AACvE,QAAM,SAAS,iBAAiB,SAAS,QAAQ,QAAQ;AAEzD,MAAI,YAAY;AAChB,MAAI,eAA+B;AACnC,MAAI;AACF,UAAM,SAAS,YAAY,QAAQ;AACnC,gBAAY,OAAO;AAInB,UAAM,cACJ,WAAW,QAAQ,OAAO,mBAAmB,KAAK,OAAO,oBAAoB;AAC/E,QAAI,aAAa;AAEf,qBAAe,OAAO,UAAU,OAAO,SAAS,UAAU;AAAA,IAC5D;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN;AAAA,MACA,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AAEA,MAAI,YAAY;AAChB,MAAI,cAAc;AAClB,MAAI,QAAQ;AACV,QAAI;AACF,YAAM,SAAS,YAAY,UAAU,MAAM;AAC3C,kBAAY,OAAO;AACnB,oBAAc,YAAY,MAAM,YAAY;AAAA,IAC9C,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,WAAW,iBAAiB,QAAQ;AAG1C,QAAM,YAAiC,CAAC;AACxC,aAAW,EAAE,KAAK,QAAQ,KAAK,UAAU;AACvC,QAAI,QAAQ,sBAA2B;AACvC,QAAI,QAAQ,iBAAiB,GAAI;AAEjC,UAAM,OAAgB,QAAQ,eAAe,KAAK,SAAS;AAI3D,UAAM,SAAS,cAAc,QAAQ,KAAK,QAAQ,OAAO;AAEzD,cAAU,KAAK;AAAA,MACb;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,cAAc,QAAQ;AAAA,MACtB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,MACA,SAAS;AAAA;AAAA,IACX,CAAC;AAAA,EACH;AAGA,QAAM,QAAQ,UACX,OAAO,OAAK,EAAE,SAAS,MAAM,EAC7B,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK,CAAE;AAC1E,QAAM,QAAQ,CAAC,GAAG,MAAM;AAAE,MAAE,UAAU;AAAA,EAAG,CAAC;AAK1C,QAAM,SAAS,UACZ,OAAO,OAAK,EAAE,SAAS,OAAO,EAC9B,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK,CAAE;AAC1E,SAAO,QAAQ,CAAC,GAAG,MAAM;AAAE,MAAE,UAAU;AAAA,EAAG,CAAC;AAG3C,QAAM,SAAS,CAAC,GAAG,OAAO,GAAG,MAAM,EAAE;AAAA,IACnC,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE,SAAS,KAAK;AAAA,EAClE;AAEA,SAAO,EAAE,QAAQ,OAAO,QAAQ,aAAa,WAAW,WAAW,aAAa;AAClF;AAkBO,SAAS,oBACd,SACA,OACA,SACA,YACA,WACA,iBAA8B,CAAC,GACP;AACxB,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,YAAY,GAAG;AACjD,UAAM,IAAI;AAAA,MACR,sEAAsE,SAAS;AAAA,IACjF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,2BAA2B;AAC7C;AAmBO,SAAS,gBACd,SACA,YAC+B;AAC/B,MAAI,eAAe,OAAQ,QAAO,QAAQ,MAAM,CAAC;AACjD,MAAI,eAAe,QAAS,QAAO,QAAQ,OAAO,CAAC;AACnD,MAAI,QAAQ,iBAAiB,OAAQ,QAAO,QAAQ,MAAM,CAAC;AAC3D,MAAI,QAAQ,iBAAiB,QAAS,QAAO,QAAQ,OAAO,CAAC;AAC7D,SAAO,QAAQ,OAAO,CAAC;AACzB;AAsCA,eAAsB,oBACpB,YACA,QACA,MACA,QACA,WACA,YACA,gBAA6B,CAAC,GACU;AACxC,QAAM,UAAU,MAAM,wBAAwB,YAAY,IAAI;AAE9D,MAAI,CAAC,QAAQ,YAAa,QAAO;AAEjC,QAAM,SAAS,gBAAgB,SAAS,UAAU;AAElD,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,oBAAoB,QAAQ,MAAM,QAAQ,WAAW,OAAO,KAAK,aAAa;AACvF;AA0CA,IAAM,gBAAgB;AAwBf,SAAS,cACd,MACA,qBACiB;AAGjB,MAAI,mBAAmB,wBAAwB;AAC/C,MAAI,WAAW;AAEf,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,SAAS,SAAU;AAE9B,QAAI,wBAAwB,QAAW;AAErC,UAAI,KAAK,WAAW,WAAW,mBAAmB,SAAS,GAAG;AAC5D,2BAAmB;AACnB,mBAAW;AACX;AAAA,MACF;AACA,UACE,KAAK,WAAW,WAAW,mBAAmB,UAAU,KACxD,KAAK,WAAW,WAAW,mBAAmB,SAAS,GACvD;AACA,2BAAmB;AACnB;AAAA,MACF;AAEA,UAAI,kBAAkB;AACpB,YAAI,sBAAsB,KAAK,IAAI,GAAG;AACpC;AACA;AAAA,QACF;AACA,YAAI,mCAAmC,KAAK,IAAI,GAAG;AACjD,qBAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AACnC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,oBAAoB,WAAW,EAAG;AAAA,IACzC;AAGA,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,IACF;AACA,QAAI,CAAC,MAAO;AAEZ,QAAI;AACJ,QAAI;AACF,YAAM,OAAO,MAAM,CAAC,CAAC;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AAEA,QAAI,QAAQ,cAAe;AAE3B,QAAI;AACF,YAAM,YAAY,OAAO,OAAO,MAAM,CAAC,CAAC,CAAC;AACzC,YAAM,QAAQ,OAAO,MAAM,CAAC,CAAC;AAC7B,YAAM,WAAW,OAAO,MAAM,CAAC,CAAC;AAChC,YAAM,WAAW,OAAO,MAAM,CAAC,CAAC;AAEhC,YAAM,YAAa,YAAY,MAAO;AACtC,aAAO,EAAE,KAAK,WAAW,OAAO,UAAU;AAAA,IAC5C,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAyEA,eAAsB,iBACpB,SACA,MACA,UAAwB,OACD;AACvB,QAAM,UAAU,OAAO,SAAS,WAAW,OAAO,KAAK,SAAS;AAChE,QAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;AACtC,QAAM,MAAM,GAAG,IAAI,0BAA0B,mBAAmB,OAAO,CAAC;AAExE,QAAM,MAAM,MAAM,QAAQ,GAAG;AAC7B,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,OAAO;AACX,QAAI;AAAE,aAAO,MAAM,IAAI,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAe;AACtD,UAAM,IAAI;AAAA,MACR,0BAA0B,IAAI,MAAM,SAAS,GAAG,GAAG,OAAO,WAAM,IAAI,KAAK,EAAE;AAAA,IAC7E;AAAA,EACF;AAEA,QAAM,OAAgB,MAAM,IAAI,KAAK;AAGrC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,QAAM,MAAM;AACZ,MAAI,CAAC,MAAM,QAAQ,IAAI,QAAQ,GAAG;AAChC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,MAAI,OAAO,IAAI,cAAc,WAAW;AACtC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,MAAI,OAAO,IAAI,gBAAgB,WAAW;AACxC,UAAM,IAAI,MAAM,gDAAgD,IAAI,WAAW,EAAE;AAAA,EACnF;AACA,MAAI,OAAO,IAAI,gBAAgB,UAAU;AACvC,UAAM,IAAI,MAAM,gDAAgD,IAAI,WAAW,EAAE;AAAA,EACnF;AACA,MAAI,OAAO,IAAI,cAAc,UAAU;AACrC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,MAAI,OAAO,IAAI,cAAc,UAAU;AACrC,UAAM,IAAI,MAAM,8CAA8C,IAAI,SAAS,EAAE;AAAA,EAC/E;AACA,aAAW,SAAS,IAAI,UAAU;AAChC,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,UAAM,IAAI;AACV,QAAI,OAAO,EAAE,QAAQ,YAAY,CAAC,OAAO,UAAU,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG;AACtE,YAAM,IAAI,MAAM,0CAA0C,EAAE,GAAG,EAAE;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AACT;;;AC5lBA,SAAS,SAAS,MAAkB,KAAqB;AACvD,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AAC9E,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,YAAY,MAAkB,KAAqB;AAC1D,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AACjF,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI;AAC9E;AAEA,SAAS,YAAY,MAAkB,KAAqB;AAC1D,MAAI,MAAM,IAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AACjF,SAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;AACjF;AAEA,SAAS,aAAa,MAAkB,KAAqB;AAC3D,MAAI,MAAM,KAAK,KAAK,OAAQ,OAAM,IAAI,MAAM,kCAAkC,GAAG,EAAE;AACnF,QAAMI,MAAK,IAAI,SAAS,KAAK,QAAQ,KAAK,aAAa,KAAK,EAAE;AAC9D,QAAM,KAAKA,IAAG,aAAa,GAAG,IAAI;AAClC,QAAM,KAAKA,IAAG,aAAa,GAAG,IAAI;AAClC,SAAQ,MAAM,MAAO;AACvB;AAOO,IAAM,uBAAuB;AAE7B,IAAM,6BAA6B;AAEnC,IAAM,qBAAqB;AAE3B,IAAM,kCAAkC;AAGxC,IAAM,6BAA6B;AAEnC,IAAM,8BAA8B;AAEpC,IAAM,+BAA+B;AAErC,IAAM,yBAAyB;AAGtC,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,YAAY;AAGX,IAAM,uBAAuB;AAQ7B,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,0CAAA,WAAQ,KAAR;AACA,EAAAA,0CAAA,WAAQ,KAAR;AACA,EAAAA,0CAAA,aAAU,KAAV;AACA,EAAAA,0CAAA,cAAW,KAAX;AAJU,SAAAA;AAAA,GAAA;AAQL,SAAS,wBAAwB,QAAwB;AAC9D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,WAAW,MAAM;AAAA,EAC5B;AACF;AA+HO,SAAS,yBACd,QACA,KACS;AAET,MAAI,IAAI,SAAS,qBAAsB,QAAO;AAE9C,MAAI,OAAO,SAAS,KAAK,OAAO,UAAU,IAAI,uBAAwB,QAAO;AAE7E,MAAI,OAAO,WAAW,cAA2B,QAAO;AACxD,SAAO,IAAI,WAAW,OAAO;AAC/B;AAsCO,SAAS,uBACd,MACA,OAAmC,CAAC,GACV;AAC1B,QAAM,UAAU,uBAAuB;AACvC,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,IAAI;AAAA,MACR,2DAAsD,OAAO,eAAe,KAAK,MAAM;AAAA,IACzF;AAAA,EACF;AACA,MAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW;AACjB,QAAM,OAAO,SAAS,MAAM,WAAW,kBAAkB;AACzD,QAAM,oBAAoB,YAAY,MAAM,WAAW,0BAA0B;AACjF,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,WAAW,uBAAuB;AAAA,EACpC;AAIA,QAAM,YACJ,KAAK,cAAc,SAAY,KAAK,OAAO,KAAK,SAAS;AAC3D,MAAI,YAAY,IAAI;AAClB,UAAM,IAAI,MAAM,+DAA+D,SAAS,EAAE;AAAA,EAC5F;AACA,QAAM,UAAU,YAAY,oBAAoB,YAAY;AAE5D,QAAM,YAAY,WAAW;AAC7B,QAAM,qBAAqB,KAAK;AAAA,IAC9B;AAAA,IACA,KAAK,OAAO,KAAK,SAAS,aAAa,yBAAyB;AAAA,EAClE;AACA,QAAM,wBAAwB,KAAK,IAAI,gBAAgB,kBAAkB;AACzE,QAAM,yBAAyB,wBAAwB;AAEvD,QAAM,MAAkC,EAAE,MAAM,SAAS,uBAAuB;AAChF,QAAM,UAA8B,CAAC;AAErC,WAAS,aAAa,GAAG,aAAa,uBAAuB,cAAc;AACzE,UAAM,aACJ,YAAY,aAAa,4BAA4B;AACvD,eAAW,QAAQ,CAAC,QAAQ,OAAO,GAAY;AAC7C,YAAM,YACJ,cACC,SAAS,SAAS,8BAA8B;AACnD,UAAI,YAAY,yBAAyB,KAAK,OAAQ;AAEtD,YAAM,SAAS,aAAa,KAAK,SAAS,UAAU,IAAI;AACxD,YAAM,SAAS,SAAS,MAAM,YAAY,SAAS;AACnD,YAAM,aAAa,YAAY,MAAM,YAAY,cAAc;AAC/D,YAAM,SAAS,WAAW,iBAA6B,WAAW;AAElE,YAAM,SAA2B;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,YAAY,MAAM,YAAY,YAAY;AAAA,QACpD,yBAAyB,aAAa,MAAM,YAAY,iBAAiB;AAAA,QACzE,uBAAuB,aAAa,MAAM,YAAY,eAAe;AAAA,QACrE,0BAA0B,aAAa,MAAM,YAAY,kBAAkB;AAAA,QAC3E,0BAA0B,aAAa,MAAM,YAAY,kBAAkB;AAAA,QAC3E,wBAAwB,aAAa,MAAM,YAAY,kBAAkB;AAAA,QACzE;AAAA,QACA;AAAA,QACA,YAAY,wBAAwB,MAAM;AAAA,QAC1C;AAAA,QACA,WAAW;AAAA,MACb;AACA,aAAO,YAAY,yBAAyB,QAAQ,GAAG;AACvD,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAyBO,SAAS,4BACd,MACA,OAAmC,CAAC,GAC1B;AACV,SAAO,uBAAuB,MAAM,IAAI,EACrC,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,EACjC,IAAI,CAAC,MAAM,EAAE,MAAM;AACxB;;;AC7bA;AAAA,EACE,cAAAC;AAAA,OAGK;AA2NP,eAAsB,eACpB,UACA,YAAoB,KACM;AAK1B,QAAM,QAAQ,YAAY,IAAI;AAC9B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,UAAU;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACnB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,QAAQ,CAAC,EAAE,YAAY,YAAY,CAAC;AAAA,MACtC,CAAC;AAAA,MACD,QAAQ,YAAY,QAAQ,SAAS;AAAA,IACvC,CAAC;AACD,UAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,KAAK;AACtD,QAAI,CAAC,IAAI,IAAI;AACX,aAAO,EAAE,UAAU,SAAS,OAAO,WAAW,MAAM,GAAG,OAAO,QAAQ,IAAI,MAAM,GAAG;AAAA,IACrF;AACA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAI,MAAM,SAAS,OAAO,MAAM,WAAW,UAAU;AACnD,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,MAAM;AAAA,QACN,OAAO,MAAM,OAAO,WAAW;AAAA,MACjC;AAAA,IACF;AACA,WAAO,EAAE,UAAU,SAAS,MAAM,WAAW,MAAM,KAAK,OAAO;AAAA,EACjE,SAAS,KAAK;AACZ,UAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,KAAK;AACtD,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,MAAM;AAAA,MACN,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD;AAAA,EACF;AACF;AAeA,SAAS,mBAAmB,KAAuD;AACjF,MAAI,QAAQ,MAAO,QAAO;AAC1B,QAAM,IAAI,OAAO,CAAC;AAClB,SAAO;AAAA,IACL,YAAY,EAAE,cAAc;AAAA,IAC5B,aAAa,EAAE,eAAe;AAAA,IAC9B,YAAY,EAAE,cAAc;AAAA,IAC5B,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7D,sBAAsB,EAAE,wBAAwB,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,EACrE;AACF;AAEA,SAAS,kBAAkB,IAAmD;AAC5E,MAAI,OAAO,OAAO,SAAU,QAAO,EAAE,KAAK,GAAG;AAC7C,SAAO;AACT;AAEA,SAAS,cAAc,IAA+B;AACpD,MAAI,GAAG,MAAO,QAAO,GAAG;AACxB,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,GAAG,EAAE;AAAA,EACzB,QAAQ;AACN,WAAO,GAAG,IAAI,MAAM,GAAG,EAAE;AAAA,EAC3B;AACF;AAEA,SAAS,YAAY,KAAc,OAA0B;AAC3D,MAAI,CAAC,IAAK,QAAO;AAKjB,QAAM,UAAW,KAA4B;AAC7C,MAAI,YAAY,gBAAgB,YAAY,eAAgB,QAAO;AACnE,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,IAAI,OAAO,aAAa,IAAI,WAAW;AACvD,QAAI,QAAQ,KAAK,GAAG,EAAG,QAAO;AAAA,EAChC;AAEA,QAAM,QAAQ,IAAI,YAAY;AAC9B,MACE,MAAM,SAAS,YAAY,KAC3B,MAAM,SAAS,mBAAmB,KAClC,MAAM,SAAS,aAAa,KAC5B,MAAM,SAAS,qBAAqB,KACpC,MAAM,SAAS,YAAY,KAC3B,MAAM,SAAS,cAAc,KAC7B,MAAM,SAAS,gBAAgB,KAC/B,MAAM,SAAS,SAAS,KACxB,MAAM,SAAS,SAAS;AAAA;AAAA;AAAA,EAIxB,MAAM,SAAS,cAAc,GAC7B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,aAAa,SAAiB,QAAqC;AAC1E,QAAM,MAAM,KAAK;AAAA,IACf,OAAO,cAAc,KAAK,IAAI,GAAG,OAAO;AAAA,IACxC,OAAO;AAAA,EACT;AACA,MAAI,OAAO,iBAAiB,EAAG,QAAO;AACtC,QAAM,OAAO,KAAK,MAAM,MAAM,CAAC;AAC/B,SAAO,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,OAAO,EAAE;AAC3D;AAEA,SAAS,YAAe,IAAY,SAA8D;AAChG,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,GAAG,WAAW;AAC5C,YAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE;AAAA,EACzD,CAAC;AACD,SAAO,EAAE,SAAS,QAAQ,MAAM,aAAa,KAAM,EAAE;AACvD;AAGA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAMA,SAAS,UAAU,KAAqB;AACtC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,YAAY;AAClB,eAAW,KAAK,CAAC,GAAG,EAAE,aAAa,KAAK,CAAC,GAAG;AAC1C,UAAI,UAAU,KAAK,CAAC,GAAG;AACrB,UAAE,aAAa,IAAI,GAAG,KAAK;AAAA,MAC7B;AAAA,IACF;AACA,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAyDO,IAAM,UAAN,MAAM,SAAQ;AAAA,EACF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAGT,UAAkB;AAAA;AAAA,EAG1B,OAAwB,sBAAsB;AAAA;AAAA,EAG9C,OAAwB,cAAc;AAAA,EAEtC,YAAY,QAAuB;AACjC,QAAI,CAAC,OAAO,aAAa,OAAO,UAAU,WAAW,GAAG;AACtD,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,SAAK,WAAW,OAAO,YAAY;AACnC,SAAK,cAAc,mBAAmB,OAAO,KAAK;AAClD,SAAK,mBAAmB,OAAO,oBAAoB;AACnD,SAAK,UAAU,OAAO,WAAW;AACjC,SAAK,kBAAkB,OAAO,mBAAmB;AAEjD,UAAM,aAAa,OAAO,cAAc;AAExC,SAAK,YAAY,OAAO,UAAU,IAAI,SAAO;AAC3C,YAAM,KAAK,kBAAkB,GAAG;AAChC,YAAM,aAA+B;AAAA,QACnC;AAAA,QACA,GAAG,GAAG;AAAA,MACR;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,YAAY,IAAIA,YAAW,GAAG,KAAK,UAAU;AAAA,QAC7C,OAAO,cAAc,EAAE;AAAA,QACvB,QAAQ,KAAK,IAAI,GAAG,GAAG,UAAU,CAAC;AAAA,QAClC,UAAU;AAAA,QACV,SAAS;AAAA,QACT,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,MAAM,KAAQ,IAAwD;AACpE,UAAM,cAAc,KAAK,cAAc,KAAK,YAAY,aAAa,IAAI;AACzE,QAAI;AAGJ,UAAM,iBAAiB,oBAAI,IAAY;AAEvC,UAAM,qBAAqB,cAAc,KAAK,UAAU;AACxD,QAAI,kBAAkB;AAEtB,aAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,UAAI,EAAE,kBAAkB,mBAAoB;AAC5C,YAAM,QAAQ,KAAK,eAAe,cAAc;AAChD,UAAI,UAAU,IAAI;AAEhB;AAAA,MACF;AACA,YAAM,KAAK,KAAK,UAAU,KAAK;AAE/B,YAAM,UAAU,YAAe,KAAK,kBAAkB,+BAA+B,KAAK,gBAAgB,OAAO,GAAG,KAAK,GAAG;AAC5H,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,UAChC,GAAG,GAAG,UAAU;AAAA,UAChB,QAAQ;AAAA,QACV,CAAC;AAGD,WAAG,WAAW;AACd,WAAG,UAAU;AACb,WAAG,iBAAiB;AACpB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,oBAAY;AACZ,WAAG;AAEH,YAAI,GAAG,YAAY,SAAQ,qBAAqB;AAC9C,aAAG,UAAU;AACb,aAAG,iBAAiB,GAAG,kBAAkB,KAAK,IAAI;AAClD,cAAI,KAAK,SAAS;AAChB,oBAAQ;AAAA,cACN,sBAAsB,GAAG,KAAK,2BAA2B,GAAG,QAAQ;AAAA,YACtE;AAAA,UACF;AAAA,QACF;AAEA,cAAM,YAAY,KAAK,cACnB,YAAY,KAAK,KAAK,YAAY,oBAAoB,IACtD;AAEJ,YAAI,CAAC,WAAW;AAEd,cAAI,KAAK,aAAa,cAAc,KAAK,UAAU,SAAS,GAAG;AAC7D,2BAAe,IAAI,KAAK;AAExB;AACA,gBAAI,eAAe,QAAQ,KAAK,UAAU,OAAQ;AAClD;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAGA,YAAI,KAAK,SAAS;AAChB,kBAAQ;AAAA,YACN,gCAAgC,GAAG,KAAK,aAAa,UAAU,CAAC,IAAI,WAAW;AAAA,YAC/E,eAAe,QAAQ,IAAI,UAAU;AAAA,UACvC;AAAA,QACF;AAGA,YAAI,KAAK,aAAa,cAAc,KAAK,UAAU,SAAS,GAAG;AAC7D,yBAAe,IAAI,KAAK;AAAA,QAC1B;AAGA,YAAI,UAAU,cAAc,KAAK,KAAK,aAAa;AACjD,gBAAM,QAAQ,aAAa,SAAS,KAAK,WAAW;AACpD,gBAAM,MAAM,KAAK;AAAA,QACnB;AAAA,MACF,UAAE;AACA,gBAAQ,OAAO;AAAA,MACjB;AAAA,IACF;AAGA,SAAK,sBAAsB;AAE3B,UAAM,aAAa,IAAI,MAAM,kCAAkC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,gBAA4B;AAC1B,UAAM,MAAM,KAAK,eAAe;AAChC,QAAI,QAAQ,IAAI;AAEd,WAAK,sBAAsB;AAC3B,aAAO,KAAK,UAAU,CAAC,EAAE;AAAA,IAC3B;AACA,WAAO,KAAK,UAAU,GAAG,EAAE;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,YAAY,YAAoB,KAAmC;AACvE,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,KAAK,UAAU,IAAI,OAAO,OAAO;AAC/B,cAAM,SAAS,MAAM,eAAe,GAAG,OAAO,KAAK,SAAS;AAC5D,WAAG,gBAAgB,OAAO;AAC1B,WAAG,UAAU,OAAO;AACpB,YAAI,OAAO,SAAS;AAClB,aAAG,WAAW;AACd,aAAG,iBAAiB;AAAA,QACtB;AACA,eAAO,WAAW,UAAU,OAAO,QAAQ;AAC3C,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,UAAU,OAAO,QAAM,GAAG,OAAO,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAMG;AACD,WAAO,KAAK,UAAU,IAAI,SAAO;AAAA,MAC/B,OAAO,GAAG;AAAA,MACV,KAAK,UAAU,GAAG,OAAO,GAAG;AAAA,MAC5B,SAAS,GAAG;AAAA,MACZ,UAAU,GAAG;AAAA,MACb,eAAe,GAAG;AAAA,IACpB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,eAAe,SAA+B;AAGpD,QAAI,KAAK,kBAAkB,GAAG;AAC5B,YAAM,MAAM,KAAK,IAAI;AACrB,iBAAW,MAAM,KAAK,WAAW;AAC/B,YAAI,CAAC,GAAG,WAAW,GAAG,mBAAmB,UAAc,MAAM,GAAG,kBAAmB,KAAK,iBAAiB;AACvG,aAAG,UAAU;AACb,aAAG,WAAW;AACd,aAAG,iBAAiB;AACpB,cAAI,KAAK,SAAS;AAChB,oBAAQ,KAAK,sBAAsB,GAAG,KAAK,mBAAmB,KAAK,eAAe,oBAAoB;AAAA,UACxG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,UAClB,IAAI,CAAC,IAAI,OAAO,EAAE,IAAI,EAAE,EAAE,EAC1B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAE,SAAS,IAAI,CAAC,CAAE;AAEzD,QAAI,QAAQ,WAAW,GAAG;AAExB,YAAM,YAAY,KAAK,UACpB,IAAI,CAAC,GAAG,MAAM,CAAC,EACf,OAAO,OAAK,CAAE,SAAS,IAAI,CAAC,CAAE;AACjC,aAAO,UAAU,SAAS,IAAI,UAAU,CAAC,IAAI;AAAA,IAC/C;AAEA,QAAI,KAAK,aAAa,YAAY;AAEhC,aAAO,QAAQ,CAAC,EAAE;AAAA,IACpB;AAGA,UAAM,cAAc,QAAQ,OAAO,CAAC,KAAK,EAAE,GAAG,MAAM,MAAM,GAAG,QAAQ,CAAC;AACtE,SAAK,WAAW,KAAK,UAAU,KAAK;AAEpC,QAAI,aAAa;AACjB,eAAW,EAAE,IAAI,EAAE,KAAK,SAAS;AAC/B,oBAAc,GAAG;AACjB,UAAI,KAAK,UAAU,WAAY,QAAO;AAAA,IACxC;AAEA,WAAO,QAAQ,QAAQ,SAAS,CAAC,EAAE;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAA8B;AACpC,UAAM,eAAe,KAAK,UAAU,OAAO,QAAM,GAAG,OAAO,EAAE;AAC7D,QAAI,eAAe,SAAQ,aAAa;AACtC,UAAI,KAAK,SAAS;AAChB,gBAAQ,KAAK,iEAA4D;AAAA,MAC3E;AACA,iBAAW,MAAM,KAAK,WAAW;AAC/B,WAAG,UAAU;AACb,WAAG,WAAW;AACd,WAAG,iBAAiB;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;AA6BA,eAAsB,UACpB,IACA,QACY;AACZ,QAAM,WAAW,mBAAmB,MAAM,KAAK;AAAA,IAC7C,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,sBAAsB,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,EAC3C;AAEA,MAAI;AACJ,QAAM,cAAc,SAAS,aAAa;AAE1C,WAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,KAAK;AACZ,kBAAY;AAEZ,UAAI,CAAC,YAAY,KAAK,SAAS,oBAAoB,GAAG;AACpD,cAAM;AAAA,MACR;AAEA,UAAI,UAAU,cAAc,GAAG;AAC7B,cAAM,QAAQ,aAAa,SAAS,QAAQ;AAC5C,cAAM,MAAM,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,IAAI,MAAM,mCAAmC;AAClE;AAOO,IAAM,YAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACp0BA;AAAA,EAGE;AAAA,EACA;AAAA,EAKA;AAAA,OACK;AAOP,IAAM,oBAAoB;AAAA,EACxB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AACb;AAQA,SAAS,yBAAyB,YAAgC;AAWhE,UAAQ,YAAY;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AACE,aAAO,kBAAkB;AAAA,EAC7B;AACF;AAQA,SAAS,gBACP,UACA,UACS;AACT,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,kBAAkB,QAAQ,KAAK,yBAAyB,QAAQ;AACzE;AAWO,SAAS,QAAQ,QAA+C;AACrE,SAAO,IAAI,uBAAuB;AAAA,IAChC,WAAW,OAAO;AAAA,IAClB,MAAM,OAAO;AAAA;AAAA;AAAA,IAGb,MAAM,OAAO;AAAA,EACf,CAAC;AACH;AAkCA,IAAM,yBAAyB;AAMxB,IAAM,+BAA+B,MAAM;AAElD,IAAM,uBAAuB,KAAK;AAClC,IAAM,uBAAuB,MAAM;AAEnC,eAAsB,eACpB,QACmB;AACnB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,EACnB,IAAI;AAIJ,QAAM,sBAAsB,eAAe,WAAW,cAAc;AAEpE,MAAI,OAAO,aAAa,WAAW;AACjC,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AAEA,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,MAAI,qBAAqB,QAAW;AAClC,QACE,OAAO,qBAAqB,YAC5B,CAAC,OAAO,UAAU,gBAAgB,KAClC,mBAAmB,KACnB,mBAAmB,wBACnB;AACA,YAAM,IAAI;AAAA,QACR,8CAA8C,sBAAsB;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,mBAAmB,GAAG;AACxB,QACE,OAAO,mBAAmB,YAC1B,CAAC,OAAO,UAAU,cAAc,KAChC,iBAAiB,SAAS,KAC1B,iBAAiB,wBACjB,iBAAiB,sBACjB;AACA,YAAM,IAAI;AAAA,QACR,sDAAsD,oBAAoB,KAAK,oBAAoB;AAAA,MACrG;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,IAAI,YAAY;AAK3B,MAAI,mBAAmB,GAAG;AACxB,OAAG,IAAI,qBAAqB,iBAAiB,EAAE,OAAO,eAAe,CAAC,CAAC;AAAA,EACzE;AAGA,MAAI,qBAAqB,QAAW;AAClC,OAAG;AAAA,MACD,qBAAqB,oBAAoB;AAAA,QACvC,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,KAAG,IAAI,EAAE;AACT,QAAM,kBAAkB,MAAM,WAAW,mBAAmB,mBAAmB;AAC/E,KAAG,kBAAkB,gBAAgB;AACrC,KAAG,WAAW,QAAQ,CAAC,EAAE;AAEzB,MAAI,UAAU;AACZ,QAAI;AACF,SAAG,KAAK,GAAG,OAAO;AAClB,YAAM,SAAS,MAAM,WAAW,oBAAoB,IAAI,OAAO;AAC/D,YAAM,OAAO,OAAO,MAAM,QAAQ,CAAC;AACnC,UAAI,MAAqB;AACzB,UAAI;AAEJ,UAAI,OAAO,MAAM,KAAK;AACpB,cAAM,SAAS,mBAAmB,IAAI;AACtC,YAAI,QAAQ;AACV,gBAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,iBAAO,OAAO;AAAA,QAChB,OAAO;AACL,gBAAM,KAAK,UAAU,OAAO,MAAM,GAAG;AAAA,QACvC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM,OAAO,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,OAAO,MAAM,iBAAiB;AAAA,MAC/C;AAAA,IACF,SAAS,GAAY;AACnB,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM;AAAA,QACN,KAAK;AAAA,QACL,MAAM,CAAC;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAuB;AAAA,IAC3B,eAAe;AAAA,IACf,qBAAqB;AAAA,EACvB;AAIA,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,WAAW,gBAAgB,IAAI,SAAS,OAAO;AAAA,EACnE,SAAS,GAAY;AACnB,UAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,WAAO;AAAA,MACL,WAAW;AAAA,MACX,MAAM;AAAA,MACN,KAAK;AAAA,MACL,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AAKA,QAAM,aAAa,wBAAwB,cAAc,cAAc;AAEvE,MAAI;AACF,UAAM,eAAe,MAAM,WAAW;AAAA,MACpC;AAAA,QACE;AAAA,QACA,WAAW,gBAAgB;AAAA,QAC3B,sBAAsB,gBAAgB;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,WAAW,eAAe,WAAW;AAAA,MACxD,YAAY;AAAA,MACZ,gCAAgC;AAAA,IAClC,CAAC;AAED,UAAM,OAAO,QAAQ,MAAM,eAAe,CAAC;AAC3C,QAAI,MAAqB;AACzB,QAAI;AAEJ,QAAI,aAAa,MAAM,KAAK;AAC1B,YAAM,SAAS,mBAAmB,IAAI;AACtC,UAAI,QAAQ;AACV,cAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,eAAO,OAAO;AAAA,MAChB,OAAO;AACL,cAAM,KAAK,UAAU,aAAa,MAAM,GAAG;AAAA,MAC7C;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,QAAQ,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,GAAY;AAUnB,UAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,mBAAmB,WAAW;AAAA,QAC5D,0BAA0B;AAAA,MAC5B,CAAC;AAMD,UAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,oBAAoB,mBAAmB,GAAG;AACzF,cAAM,SAAS,MAAM,WAAW,eAAe,WAAW;AAAA,UACxD,YAAY;AAAA,UACZ,gCAAgC;AAAA,QAClC,CAAC;AACD,cAAM,OAAO,QAAQ,MAAM,eAAe,CAAC;AAC3C,YAAI,MAAqB;AACzB,YAAI;AACJ,YAAI,OAAO,MAAM,KAAK;AACpB,gBAAM,SAAS,mBAAmB,IAAI;AACtC,cAAI,QAAQ;AACV,kBAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;AACnD,mBAAO,OAAO;AAAA,UAChB,OAAO;AACL,kBAAM,KAAK,UAAU,OAAO,MAAM,GAAG;AAAA,UACvC;AAAA,QACF;AACA,eAAO;AAAA,UACL;AAAA;AAAA;AAAA;AAAA,UAIA,MAAM,QAAQ,QAAQ,OAAO,MAAM;AAAA,UACnC;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,OAAO;AAGhB,cAAM,WAAW,OAAO,MAAM,sBAAsB;AACpD,eAAO;AAAA,UACL;AAAA,UACA,MAAM,OAAO,MAAM;AAAA,UACnB,KACE,gCAAgC,OAAO,iCAA4B,QAAQ,UACnE,mBAAmB,0EACR,SAAS;AAAA,UAC9B,MAAM,CAAC;AAAA,QACT;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAGR;AACA,WAAO;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN,KAAK,gCAAgC,OAAO,qEAAgE,SAAS;AAAA,MACrH,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,aAAa,QAAkB,UAA2B;AACxE,MAAI,UAAU;AACZ,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,KAAK;AACd,UAAM,KAAK,UAAU,OAAO,GAAG,EAAE;AACjC,QAAI,OAAO,MAAM;AACf,YAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AAAA,IACnC;AACA,QAAI,OAAO,kBAAkB,QAAW;AACtC,YAAM,KAAK,kBAAkB,OAAO,cAAc,eAAe,CAAC,EAAE;AAAA,IACtE;AACA,QAAI,OAAO,KAAK,SAAS,GAAG;AAC1B,YAAM,KAAK,OAAO;AAClB,aAAO,KAAK,QAAQ,CAAC,QAAQ,MAAM,KAAK,KAAK,GAAG,EAAE,CAAC;AAAA,IACrD;AAAA,EACF,OAAO;AACL,UAAM,KAAK,cAAc,OAAO,SAAS,EAAE;AAC3C,UAAM,KAAK,SAAS,OAAO,IAAI,EAAE;AACjC,QAAI,OAAO,kBAAkB,QAAW;AACtC,YAAM,KAAK,kBAAkB,OAAO,cAAc,eAAe,CAAC,EAAE;AAAA,IACtE;AACA,QAAI,OAAO,cAAc,eAAe;AACtC,YAAM,KAAK,4CAA4C,OAAO,SAAS,EAAE;AAAA,IAC3E;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC1XA,SAAS,aAAAC,aAAmC,eAAAC,oBAAmB;AAaxD,IAAM,wBAAwB,IAAID;AAAA,EACvC;AACF;AAGO,IAAM,4BAA4B;AAOlC,IAAM,gCAAgC;AAMtC,IAAM,yBAAyB,oBAAI,IAAI;AAAA,EAC5C;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF,CAAU;AAiBH,SAAS,wBAAwB,IAAqC;AAC3E,SAAO,GAAG,UAAU,OAAO,qBAAqB;AAClD;AA0BO,SAAS,kBAAkB,OAAyB;AACzD,QAAM,MAAM,oBAAoB,KAAK;AACrC,MAAI,CAAC,IAAK,QAAO;AAGjB,MAAI,IAAI,SAAS,yBAAyB,EAAG,QAAO;AAGpD,MAAI,wCAAwC,KAAK,GAAG,EAAG,QAAO;AAG9D,MAAI,wBAAwB,KAAK,GAAG,KAAK,oBAAoB,KAAK,GAAG,EAAG,QAAO;AAE/E,SAAO;AACT;AAYO,SAAS,0BAA0B,MAAyB;AACjE,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO;AAEjC,MAAI,kBAAkB;AAEtB,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,SAAS,SAAU;AAG9B,QAAI,KAAK,SAAS,WAAW,yBAAyB,SAAS,GAAG;AAChE;AACA;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,WAAW,yBAAyB,UAAU,GAAG;AACjE,UAAI,kBAAkB,EAAG;AACzB;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,WAAW,yBAAyB,SAAS,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAwBO,SAAS,4BACd,cACA,qBAC0B;AAI1B,MAAI,qBAAqB;AACvB,UAAM,kBAAkB,aAAa;AAAA,MACnC,CAAC,OAAO,GAAG,UAAU,OAAO,mBAAmB;AAAA,IACjD;AACA,QAAI,CAAC,iBAAiB;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,aAAa,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC;AACjE;AAuBO,SAAS,+BACd,aACA,qBACa;AAGb,MAAI,qBAAqB;AACvB,UAAM,kBAAkB,YAAY,aAAa;AAAA,MAC/C,CAAC,OAAO,GAAG,UAAU,OAAO,mBAAmB;AAAA,IACjD;AACA,QAAI,CAAC,gBAAiB,QAAO;AAAA,EAC/B;AAEA,QAAM,gBAAgB,YAAY,aAAa,KAAK,uBAAuB;AAC3E,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,QAAQ,IAAIC,aAAY;AAC9B,QAAM,kBAAkB,YAAY;AACpC,QAAM,WAAW,YAAY;AAE7B,aAAW,MAAM,YAAY,cAAc;AACzC,QAAI,CAAC,wBAAwB,EAAE,GAAG;AAChC,YAAM,IAAI,EAAE;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,4BACd,SACQ;AACR,QAAM,eAAe,MAAM,QAAQ,OAAO,IAAI,UAAU,QAAQ;AAChE,SAAO,aAAa,OAAO,uBAAuB,EAAE;AACtD;AAWO,IAAM,0BACX;AAgBK,SAAS,wBAAwB,OAA+B;AACrE,MAAI,kBAAkB,KAAK,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAMA,SAAS,oBAAoB,OAA+B;AAC1D,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,iBAAiB,MAAO,QAAO,MAAM;AACzC,MAAI,OAAO,UAAU,YAAY,aAAa,OAAO;AACnD,WAAO,OAAQ,MAA+B,OAAO;AAAA,EACvD;AACA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACrUO,SAAS,eACd,cACA,YACA,aACQ;AACR,MAAI,iBAAiB,MAAM,gBAAgB,GAAI,QAAO;AACtD,QAAM,SAAS,eAAe,KAAK,CAAC,eAAe;AACnD,QAAM,OACJ,eAAe,KACX,cAAc,aACd,aAAa;AACnB,SAAQ,OAAO,SAAU;AAC3B;AAMO,SAAS,gBACd,YACA,SACA,cACA,sBACQ;AACR,MAAI,iBAAiB,MAAM,eAAe,GAAI,QAAO;AACrD,QAAM,SAAS,eAAe,KAAK,CAAC,eAAe;AAEnD,QAAM,mBAAoB,UAAU,WAAc;AAElD,MAAI,eAAe,IAAI;AACrB,UAAM,WAAY,mBAAmB,UAAW,SAAS;AACzD,UAAM,MAAM,aAAa;AACzB,WAAO,MAAM,KAAK,MAAM;AAAA,EAC1B,OAAO;AAIL,QAAI,wBAAwB,OAAQ,QAAO;AAC3C,UAAM,WAAY,mBAAmB,UAAW,SAAS;AACzD,WAAO,aAAa;AAAA,EACtB;AACF;AAMO,SAAS,wBACd,UACA,QACA,SACA,UACA,QACA,WACQ;AACR,MAAI,aAAa,MAAM,WAAW,MAAM,YAAY,GAAI,QAAO;AAC/D,QAAM,SAAS,UAAU,KAAK,CAAC,UAAU;AACzC,QAAM,YAAY,cAAc,SAAS,SAAS,CAAC;AAInD,QAAM,YAAa,WAAW,SAAU;AACxC,MAAI;AACJ,MAAI,cAAc,QAAQ;AACxB,oBAAgB,WAAW;AAAA,EAC7B,OAAO;AAIL,UAAM,aAAa,WAAW;AAC9B,oBAAgB,aAAa,KAAK,aAAa;AAAA,EACjD;AACA,SAAO,gBAAgB,eAAe,QAAQ,WAAW,QAAQ;AACnE;AAKO,SAAS,kBACd,UACA,eACQ;AACR,SAAQ,WAAW,gBAAiB;AACtC;AA4BO,SAAS,qBACd,UACA,QACQ;AACR,MAAI,OAAO,mBAAmB,GAAI,QAAO,OAAO;AAChD,MAAI,OAAO,iBAAiB,MAAM,YAAY,OAAO,eAAgB,QAAO,OAAO;AACnF,MAAI,YAAY,OAAO,eAAgB,QAAO,OAAO;AACrD,SAAO,OAAO;AAChB;AAQO,SAAS,yBACd,UACA,QACQ;AACR,QAAM,SAAS,qBAAqB,UAAU,MAAM;AACpD,MAAI,YAAY,MAAM,UAAU,GAAI,QAAO;AAC3C,UAAQ,WAAW,SAAS,SAAS;AACvC;AAqBO,SAAS,gBACd,UACA,QAC0B;AAC1B,MAAI,OAAO,UAAU,MAAM,OAAO,gBAAgB,MAAM,OAAO,eAAe,IAAI;AAChF,WAAO,CAAC,UAAU,IAAI,EAAE;AAAA,EAC1B;AACA,QAAM,WAAW,OAAO,QAAQ,OAAO,cAAc,OAAO;AAC5D,MAAI,OAAO,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,aAAa,IAAI;AAC1E,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,MAAI,aAAa,QAAQ;AACvB,UAAM,IAAI,MAAM,sDAAsD,QAAQ,EAAE;AAAA,EAClF;AAEA,QAAM,KAAM,WAAW,OAAO,QAAS;AACvC,QAAM,WAAY,WAAW,OAAO,cAAe;AACnD,QAAM,UAAU,WAAW,KAAK;AAChC,SAAO,CAAC,IAAI,UAAU,OAAO;AAC/B;AAUO,SAAS,kBACd,WACA,SACQ;AACR,MAAI,YAAY,GAAI,QAAO;AAC3B,QAAM,YAAa,YAAY,SAAW;AAI1C,QAAM,cAAc,OAAO,OAAO,gBAAgB;AAClD,MAAI,YAAY,YAAa,QAAO,OAAO,mBAAmB;AAC9D,MAAI,YAAY,CAAC,YAAa,QAAO,EAAE,OAAO,mBAAmB;AACjE,SAAO,OAAO,SAAS,IAAI;AAC7B;AAKO,SAAS,2BACd,UACA,eACA,WACQ;AACR,MAAI,aAAa,GAAI,QAAO;AAC5B,QAAM,YAAa,WAAW,gBAAiB;AAC/C,MAAI,cAAc,OAAQ,QAAO,WAAW;AAI5C,QAAM,aAAa,WAAW;AAC9B,SAAO,aAAa,KAAK,aAAa;AACxC;AAEA,IAAM,kBAAkB,OAAO,OAAO,gBAAgB;AACtD,IAAM,kBAAkB,OAAO,CAAC,OAAO,gBAAgB;AAKhD,SAAS,6BACd,uBACQ;AAGR,MAAI,wBAAwB,gBAAiB,QAAO;AACpD,MAAI,wBAAwB,gBAAiB,QAAO;AACpD,QAAM,aAAa,OAAO,qBAAqB;AAC/C,QAAM,eAAe,MAAM,KAAK,KAAK,KAAK;AAC1C,SAAQ,aAAa,eAAgB;AACvC;AAKO,SAAS,sBACd,UACA,kBACQ;AACR,SAAQ,WAAW,mBAAoB;AACzC;AAWO,SAAS,mBAAmB,kBAAkC;AACnE,MAAI,oBAAoB,IAAI;AAC1B,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AAIA,SAAO,MAAQ,OAAO,gBAAgB;AACxC;AAaO,SAAS,wBAAwB,kBAAkC;AACxE,MAAI,oBAAoB,IAAI;AAC1B,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AACA,SAAO,SAAS;AAClB;;;AC3QO,SAAS,6BACd,cACA,aACA,iBACA,mBACQ;AAER,MAAI,sBAAsB,MAAM,oBAAoB,GAAI,QAAO;AAC/D,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,UAAU,cAAc,kBAC1B,cAAc,kBACd;AAGJ,MAAI,WAAW,kBAAmB,QAAO;AAGzC,SAAQ,eAAe,UAAW;AACpC;AAoBO,SAAS,yBACd,kBACA,cACA,aACA,iBACA,mBACQ;AAIR,QAAM,SAAS,wBAAwB,gBAAgB;AAGvD,MAAI,sBAAsB,MAAM,oBAAoB,GAAI,QAAO,OAAO,MAAM;AAC5E,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY,GAAI,QAAO;AAG3B,QAAM,eAAe,OAAQ,SAAS,WAAY,YAAY;AAC9D,SAAO,KAAK,IAAI,GAAG,YAAY;AACjC;AAgBO,SAAS,6BACd,kBACA,cACA,aACA,iBACA,mBACQ;AACR,QAAM,SAAS,wBAAwB,gBAAgB;AACvD,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO,WAAW;AACpB;;;ACxHA,SAAS,aAAAC,mBAAiB;AAG1B,IAAMC,WAAU;AAChB,IAAM,UAAU,OAAO,sBAAsB;AAC7C,IAAM,UAAU,OAAO,sBAAsB;AAC7C,IAAM,UAAU,OAAO,qBAAqB;AAC5C,IAAM,YAAY,MAAM,QAAQ;AAChC,IAAM,WAAW,EAAE,MAAM;AACzB,IAAM,YAAY,MAAM,QAAQ;AAEzB,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACkB,OAChB,SACA;AACA,UAAM,WAAW,KAAK,KAAK,OAAO,EAAE;AAHpB;AAIhB,SAAK,OAAO;AAAA,EACd;AACF;AAMA,IAAM,kBAAkB;AAMxB,IAAMC,kBAAiB;AAUhB,SAAS,yBAAyB,OAAe,OAAuB;AAC7E,QAAM,IAAI,MAAM,KAAK;AACrB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,IAAI,KAAK,yBAAyB;AAAA,EACrE;AACA,MAAI,CAAC,gBAAgB,KAAK,CAAC,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAoBO,SAAS,WAAW,KAAa,QAAwB;AAC9D,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,CAACA,gBAAe,KAAK,CAAC,GAAG;AAC3B,UAAM,IAAI;AAAA,MACR,GAAG,MAAM,MAAM,GAAG;AAAA,IAEpB;AAAA,EACF;AACA,SAAO,OAAO,CAAC;AACjB;AAKO,SAAS,kBAAkB,OAAe,OAA0B;AACzE,MAAI;AACF,WAAO,IAAIF,YAAU,KAAK;AAAA,EAC5B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IAEX;AAAA,EACF;AACF;AAKO,SAAS,cAAc,OAAe,OAAuB;AAClE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,OAAOC,QAAO,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAcA,QAAO,mBAAmB,CAAC;AAAA,IAC3C;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;AAKO,SAAS,eAAe,OAAe,OAAuB;AACnE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,MAAM,OAAO,CAAC;AAEpB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,6BAA6B,GAAG,EAAE;AAAA,EACrE;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aAAa,OAAe,OAAuB;AACjE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,MAAM,OAAO,CAAC;AAEpB,MAAI,MAAM,IAAI;AACZ,UAAM,IAAI,gBAAgB,OAAO,6BAA6B,GAAG,EAAE;AAAA,EACrE;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,MAAI;AAEJ,MAAI;AACF,UAAM,WAAW,OAAO,KAAK;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,OAAO,mBAAmB,GAAG;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aAAa,OAAe,OAAuB;AACjE,MAAI;AAEJ,MAAI;AACF,UAAM,WAAW,OAAO,KAAK;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,IAAI,KAAK;AAAA,IACX;AAAA,EACF;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,MAAM,UAAU;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAc,QAAQ,oBAAoB,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,QAAQ;AACf,UAAM,IAAI;AAAA,MACR;AAAA,MACA,gCAAgC,CAAC;AAAA,IACnC;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,SAAO,eAAe,OAAO,KAAK;AACpC;AAKO,SAAS,YAAY,OAAe,OAAuB;AAChE,QAAM,IAAI,yBAAyB,OAAO,KAAK;AAC/C,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,KAAK,OAAOA,QAAO,GAAG;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,cAAcA,QAAO,mBAAmB,CAAC;AAAA,IAC3C;AAAA,EACF;AACA,SAAO,OAAO,EAAE;AAClB;;;AC1NA,IAAM,6BAA6B;AAEnC,SAAS,SAAS,GAA0C;AAC1D,SAAO,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAChE;AAEA,SAAS,oBAAoB,SAAqC;AAChE,QAAM,UAAU,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO;AAC7C,MAAI,SAAS;AACX,UAAM,IAAI,IAAI,gBAAgB;AAC9B,MAAE,MAAM,QAAQ,MAAM;AACtB,WAAO,EAAE;AAAA,EACX;AACA,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO;AAC/C,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,IAAI,gBAAgB;AAC9B,MAAE,MAAM;AACR,WAAO,EAAE;AAAA,EACX;AACA,MAAI,OAAO,WAAW,EAAG,QAAO,OAAO,CAAC;AACxC,QAAM,OAAO,IAAI,gBAAgB;AACjC,aAAW,KAAK,QAAQ;AACtB,MAAE,iBAAiB,SAAS,MAAM,KAAK,MAAM,EAAE,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,EACxE;AACA,SAAO,KAAK;AACd;AAEA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,YAAY,WAAW,SAAS,CAAC;AAEpE,SAAS,sBAAsB,MAA8B;AAC3D,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO,CAAC;AAC7B,QAAM,WAAW,KAAK;AACtB,MAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO,CAAC;AACtC,QAAM,UAAyB,CAAC;AAEhC,aAAW,QAAQ,UAAU;AAC3B,QAAI,CAAC,SAAS,IAAI,EAAG;AACrB,QAAI,KAAK,YAAY,SAAU;AAC/B,UAAM,QAAQ,OAAO,KAAK,SAAS,EAAE,EAAE,YAAY;AACnD,QAAI,CAAC,kBAAkB,IAAI,KAAK,EAAG;AAEnC,QAAI,YAAY;AAChB,QAAI,SAAS,KAAK,SAAS,KAAK,OAAO,KAAK,UAAU,QAAQ,UAAU;AACtE,kBAAY,KAAK,UAAU;AAAA,IAC7B;AACA,QAAI,YAAY,IAAK;AAErB,QAAI,aAAa;AACjB,QAAI,YAAY,IAAW,cAAa;AAAA,aAC/B,YAAY,IAAS,cAAa;AAAA,aAClC,YAAY,IAAQ,cAAa;AAAA,aACjC,YAAY,IAAO,cAAa;AAEzC,UAAM,WAAW,KAAK;AACtB,UAAM,QACJ,OAAO,aAAa,YAAY,OAAO,aAAa,WAChD,WAAW,OAAO,QAAQ,CAAC,KAAK,IAChC;AAMN,QAAI,EAAE,QAAQ,GAAI;AAElB,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI,SAAS,KAAK,SAAS,KAAK,OAAO,KAAK,UAAU,WAAW,UAAU;AACzE,gBAAU,KAAK,UAAU;AAAA,IAC3B;AACA,QAAI,SAAS,KAAK,UAAU,KAAK,OAAO,KAAK,WAAW,WAAW,UAAU;AAC3E,iBAAW,KAAK,WAAW;AAAA,IAC7B;AAEA,UAAM,OAAO,KAAK;AAClB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS,OAAO,SAAS,WAAW,OAAO;AAAA,MAC3C;AAAA,MACA,WAAW,GAAG,OAAO,MAAM,QAAQ;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAChD,SAAO,QAAQ,MAAM,GAAG,EAAE;AAC5B;AAeA,SAAS,sBACP,MACA,MACiE;AACjE,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAG5B,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI,SAAS,KAAK,KAAK,MAAM,aAAa,UAAa,MAAM,aAAa,MAAM;AAC9E,UAAME,SAAQ,WAAW,OAAO,MAAM,QAAQ,CAAC,KAAK;AACpD,QAAIA,UAAS,EAAG,QAAO;AACvB,UAAM,YACJ,OAAO,MAAM,cAAc,YAAY,OAAO,SAAS,MAAM,SAAS,IAClE,MAAM,YACN;AACN,WAAO,EAAE,OAAAA,QAAO,YAAY,KAAK,UAAU;AAAA,EAC7C;AAGA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,CAAC,SAAS,GAAG,EAAG,QAAO;AAC3B,QAAM,WAAW,IAAI;AACrB,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AACxD,QAAM,QAAQ,WAAW,OAAO,QAAQ,CAAC,KAAK;AAC9C,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,aAAa;AACjB,MAAI,OAAO,IAAI,eAAe,SAAU,cAAa,IAAI;AACzD,SAAO,EAAE,OAAO,YAAY,WAAW,EAAE;AAC3C;AAMO,IAAM,oBAAsE;AAAA;AAAA,EAEjF,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,+CAA+C;AAAA;AAAA,EAE3I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,WAAW,MAAM,+CAA+C;AAAA;AAAA,EAE9I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,+CAA+C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,UAAU,MAAM,8CAA8C;AAAA;AAAA,EAE5I,oEAAoE,EAAE,QAAQ,KAAK,MAAM,+CAA+C;AAAA;AAAA,EAExI,oEAAoE,EAAE,QAAQ,QAAQ,MAAM,8CAA8C;AAAA;AAAA,EAE1I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAAA;AAAA,EAEzI,oEAAoE,EAAE,QAAQ,UAAU,MAAM,8CAA8C;AAAA;AAAA,EAE5I,oEAAoE,EAAE,QAAQ,OAAO,MAAM,8CAA8C;AAC3I;AACA,OAAO,OAAO,iBAAiB;AAG/B,IAAM,oBAAoB,oBAAI,IAAgD;AAC9E,WAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAC9D,oBAAkB,IAAI,KAAK,MAAM,EAAE,QAAQ,QAAQ,KAAK,OAAO,CAAC;AAClE;AAMA,IAAM,2BAA2B;AAEjC,SAAS,gBAAgB,QAAmC;AAC1D,SAAO,UAAU,YAAY,QAAQ,wBAAwB;AAC/D;AAEA,eAAe,gBAAgB,MAAc,QAA8C;AACzF,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB,iDAAiD,mBAAmB,IAAI,CAAC;AAAA,MACzE;AAAA,QACE,QAAQ,gBAAgB,MAAM;AAAA,QAC9B,SAAS,EAAE,cAAc,iBAAiB;AAAA,MAC5C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,GAAI,QAAO,CAAC;AACtB,UAAM,OAAgB,MAAM,KAAK,KAAK;AACtC,WAAO,sBAAsB,IAAI;AAAA,EACnC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAMA,SAAS,iBAAiB,MAAkC;AAC1D,QAAM,QAAQ,kBAAkB,IAAI,IAAI;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,MAAM;AAAA,IACf,WAAW,GAAG,MAAM,MAAM;AAAA,IAC1B,WAAW;AAAA;AAAA,IACX,OAAO;AAAA;AAAA,IACP,YAAY;AAAA;AAAA,EACd;AACF;AAMA,eAAe,mBAAmB,MAAc,QAAmD;AACjG,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB,mCAAmC,mBAAmB,IAAI,CAAC;AAAA,MAC3D;AAAA,QACE,QAAQ,gBAAgB,MAAM;AAAA,QAC9B,SAAS,EAAE,cAAc,iBAAiB;AAAA,MAC5C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,GAAI,QAAO;AACrB,UAAM,OAAgB,MAAM,KAAK,KAAK;AACtC,UAAM,MAAM,sBAAsB,MAAM,IAAI;AAC5C,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW,GAAG,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA,MAI5B,WAAW,IAAI;AAAA,MACf,OAAO,IAAI;AAAA,MACX,YAAY;AAAA;AAAA,IACd;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,aACpB,MACA,QACA,SAC4B;AAC5B,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,gBAAgB,YAAY,QAAQ,SAAS;AACnD,QAAM,iBAAiB,SACnB,oBAAoB,CAAC,QAAQ,aAAa,CAAC,IAC3C;AAEJ,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpD,gBAAgB,MAAM,cAAc;AAAA,IACpC,mBAAmB,MAAM,cAAc;AAAA,EACzC,CAAC;AAcD,QAAM,2BAA2B;AAKjC,QAAM,6BAA6B;AACnC,MAAI,iBAAiB,cAAc,QAAQ,GAAG;AAa5C,UAAM,oBAAoB,cAAc,YAAY;AACpD,UAAM,aAAa,KAAK,IAAI,GAAG,cAAc,aAAa,0BAA0B;AACpF,QAAI,mBAAmB;AAKrB,iBAAW,OAAO,YAAY;AAC5B,cAAM,cAAc,IAAI,QAAQ,cAAc,SAAS;AACvD,cAAM,mBAAmB,KAAK,IAAI,IAAI,QAAQ,cAAc,KAAK,IAAI;AACrE,YAAI,mBAAmB,0BAA0B;AAC/C,cAAI,aAAa,KAAK,IAAI,IAAI,YAAY,UAAU;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,iBAAiB,IAAI;AAExC,QAAM,aAA4B,CAAC;AAGnC,MAAI,YAAY;AAKd,UAAM,WAAW,WAAW,CAAC,GAAG,SAAS;AACzC,UAAM,WAAW,eAAe,SAAS;AAWzC,QAAI,gBAAgB;AACpB,QAAI,eAAe;AACnB,QAAI,WAAW,KAAK,WAAW,GAAG;AAChC,YAAM,OAAO,WAAW,YAAY;AACpC,YAAM,YAAY,KAAK,IAAI,WAAW,QAAQ,IAAI;AAClD,UAAI,aAAa,0BAA0B;AACzC,wBAAgB;AAAA,MAClB,OAAO;AAGL,gBAAQ;AAAA,UACN,uCAAuC,QAAQ,kBAAkB,QAAQ,iBAC1D,YAAY,KAAK,QAAQ,CAAC,CAAC,OAAO,2BAA2B,GAAG;AAAA,QAEjF;AAAA,MACF;AAAA,IACF,WAAW,WAAW,KAAK,WAAW,GAAG;AACvC,sBAAgB,WAAW,IAAI,WAAW;AAC1C,qBAAe;AAAA,IACjB;AACA,QAAI,gBAAgB,GAAG;AACrB,iBAAW,QAAQ;AACnB,UAAI,cAAc;AAChB,mBAAW,aAAa,KAAK,IAAI,WAAW,YAAY,EAAE;AAAA,MAC5D;AACA,iBAAW,KAAK,UAAU;AAAA,IAC5B;AAAA,EACF;AAGA,aAAW,KAAK,GAAG,UAAU;AAG7B,MAAI,eAAe;AACjB,eAAW,KAAK,aAAa;AAAA,EAC/B;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAErD,SAAO;AAAA,IACL;AAAA,IACA,YAAY,WAAW,CAAC,KAAK;AAAA,IAC7B;AAAA,IACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AACF;","names":["PublicKey","PublicKey","PublicKey","PublicKey","PublicKey","bitmapBytes","AccountKind","PublicKey","kindByte","kind","ORACLE_LEG_CAP","PublicKey","PublicKey","TOKEN_PROGRAM_ID","PublicKey","PublicKey","ENGINE_BITMAP_OFF_V0","dv","readU16LE","readU64LE","readI64LE","readU128LE","readI128LE","results","PublicKey","PublicKey","PublicKey","readU64LE","dv","readU128LE","readU8","readU32LE","PublicKey","TOKEN_PROGRAM_ID","PublicKey","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","TOKEN_PROGRAM_ID","TOKEN_2022_PROGRAM_ID","PublicKey","TEXT","readU64LE","readU16LE","TOKEN_PROGRAM_ID","SystemProgram","SYSVAR_RENT_PUBKEY","SYSVAR_CLOCK_PUBKEY","dv","BackingBucketStatus","Connection","PublicKey","Transaction","PublicKey","U16_MAX","DECIMAL_INT_RE","price"]} \ No newline at end of file diff --git a/src/abi/nft.ts b/src/abi/nft.ts index 39731fa..3af311f 100644 --- a/src/abi/nft.ts +++ b/src/abi/nft.ts @@ -362,7 +362,13 @@ export function deriveExtraAccountMetas( * [119..127] epoch_snap_at_mint u64 * [127..159] position_owner_at_mint [u8; 32] * [159..167] minted_at i64 - * [167..199] _reserved + * [167..199] last_holder [u8; 32] + * + * NOTE: [167..199] is `last_holder`, not reserved space. #138 claimed those + * bytes for the field the transfer hook rewrites on every transfer, and + * `ReconcileBurnedNft` reads it to decide who receives the released escrow and + * the rent — it is account 6 of that instruction and cannot be derived, only + * read from here. */ export const POSITION_NFT_STATE_LEN = 199; const POSITION_NFT_MAGIC = 0x5045_5243_4e46_5400n; @@ -383,6 +389,15 @@ export interface PositionNftState { /** Backward-compatible alias for positionOwnerAtMint. */ positionOwner: PublicKey; mintedAt: bigint; + /** + * The wallet the transfer hook last recorded as holding this NFT (#138). + * + * This is the sole authorisation for `ReconcileBurnedNft`: the program + * releases the escrowed portfolio and all rent to whichever account matches + * it, and refuses any other. Supply it as account 6 of + * `ACCOUNTS_NFT_RECONCILE` — there is no way to derive it. + */ + lastHolder: PublicKey; } /** @@ -450,5 +465,6 @@ export function parsePositionNftAccount(data: Uint8Array): PositionNftState { positionOwnerAtMint, positionOwner: positionOwnerAtMint, mintedAt: view.getBigInt64(159, true), + lastHolder: new PublicKey(data.subarray(167, 199)), }; } diff --git a/test/drift-check.test.ts b/test/drift-check.test.ts index 1dd2bd9..1b1e234 100644 --- a/test/drift-check.test.ts +++ b/test/drift-check.test.ts @@ -403,6 +403,26 @@ describe("SDK drift guards", () => { expect(parsed.positionOwner.equals(owner)).toBe(true); }); + it("parses lastHolder from bytes 167..199 — the Reconcile recipient (#138)", () => { + // [167..199] is `last_holder`, not reserved space. It is the sole + // authorisation for ReconcileBurnedNft: the program releases the escrow and + // all rent to whichever account matches it, and it is account 6 of + // ACCOUNTS_NFT_RECONCILE. It cannot be derived — only read from here. + const buf = new Uint8Array(POSITION_NFT_STATE_LEN); + const view = new DataView(buf.buffer); + const owner = PublicKey.unique(); + const holder = PublicKey.unique(); + view.setBigUint64(0, 0x5045_5243_4e46_5400n, true); + buf[8] = 2; + buf.set(owner.toBytes(), 127); + buf.set(holder.toBytes(), 167); + const parsed = parsePositionNftAccount(buf); + expect(parsed.lastHolder.equals(holder)).toBe(true); + // ...and it is a distinct field from the mint-time owner. + expect(parsed.positionOwnerAtMint.equals(owner)).toBe(true); + expect(parsed.lastHolder.equals(parsed.positionOwnerAtMint)).toBe(false); + }); + it("standalone NFT helpers use v16 portfolio model (mint=asset_index, PDA=market_id)", () => { const portfolio = PublicKey.unique(); const assetIndex = 7;