From ae1093521a8cca71ffb81021dee772b20a8111ee Mon Sep 17 00:00:00 2001 From: dcccrypto Date: Thu, 27 Aug 2026 12:10:21 +0100 Subject: [PATCH] fix(abi): NFT_PROGRAM_ID pointed at a program that is not deployed on devnet The ABI exported NFT_PROGRAM_ID defaulting to FqhKJT9g..., which is the MAINNET address, while every other program id in this SDK is devnet. `solana account FqhKJT9g... -u devnet` returns AccountNotFound, so any consumer importing this constant built transactions against a program that does not exist and failed late and unhelpfully with "Account not found on-chain". percolator-launch already hit this and works around it with its own constant, which documents the symptom verbatim: "made position-NFT mint/burn/transfer fail with Account not found on-chain". Now derived from PROGRAM_IDS_V17.nft rather than carrying an independent literal, so the two cannot drift apart again. The devnet id joins the env-override allowlist; the mainnet id remains allowed for an explicit override. before: NFT_PROGRAM_ID = FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS (not deployed) after: NFT_PROGRAM_ID = CNGBPZRALk9Xu8BdgWNyrLJ7daQ9eJYFf1GnEEC7YCU3 (deployed) Found by the pre-deploy gate harness, which asserts SDK program-id constants against the programs actually on chain. Fixes dcccrypto/percolator-sdk#371. SDK suite: 968 passed / 31 skipped, unchanged. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NgoNgagkvw7i5SSRC3FJ8D --- dist/abi/nft.d.ts | 11 ++++++++++- dist/index.js | 13 +++++++------ dist/index.js.map | 2 +- dist/solana/stake.d.ts | 13 ++++++++++--- src/abi/nft.ts | 17 +++++++++++++---- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/dist/abi/nft.d.ts b/dist/abi/nft.d.ts index 2bc6594..ea16c5a 100644 --- a/dist/abi/nft.d.ts +++ b/dist/abi/nft.d.ts @@ -15,7 +15,16 @@ * Mint authority : ["mint_authority"] */ import { PublicKey } from "@solana/web3.js"; -/** The standalone percolator-nft program (TransferHook + mint authority). */ +/** + * The standalone percolator-nft program (TransferHook + mint authority). + * + * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant + * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET + * address while every other id in the SDK is devnet, so any consumer importing it built + * transactions against a program that does not exist on devnet and failed late with + * "Account not found on-chain". The frontend hit exactly that and had to define its own + * constant to work around it. + */ export declare const NFT_PROGRAM_ID: PublicKey; export declare function getNftProgramId(): PublicKey; export declare const NFT_IX_TAG: { diff --git a/dist/index.js b/dist/index.js index 746cee3..2fbec2a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2681,8 +2681,10 @@ function getCurrentNetwork() { // src/abi/nft.ts var KNOWN_NFT_PROGRAM_IDS = /* @__PURE__ */ new Set([ - "FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS" + "FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS", // mainnet + PROGRAM_IDS_V17.nft + // v17 devnet — the default below ]); var NFT_PROGRAM_OVERRIDE = safeEnv("NFT_PROGRAM_ID"); if (NFT_PROGRAM_OVERRIDE !== void 0 && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OVERRIDE)) { @@ -2690,9 +2692,7 @@ if (NFT_PROGRAM_OVERRIDE !== void 0 && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM_OV `[percolator-sdk] NFT_PROGRAM_ID env var "${NFT_PROGRAM_OVERRIDE}" is not a known NFT program address. Allowed values: ${[...KNOWN_NFT_PROGRAM_IDS].join(", ")}. Pass the programId argument explicitly to bypass env resolution.` ); } -var NFT_PROGRAM_ID = new PublicKey4( - NFT_PROGRAM_OVERRIDE ?? "FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS" -); +var NFT_PROGRAM_ID = new PublicKey4(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft); function getNftProgramId() { return NFT_PROGRAM_ID; } @@ -6928,8 +6928,9 @@ function getStakeProgramId(network) { const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? ""; if (n === "mainnet" || n === "mainnet-beta") return "mainnet"; if (n === "devnet") return "devnet"; - if (typeof window !== "undefined") return "mainnet"; - return "devnet"; + throw new Error( + "getStakeProgramId: cannot determine the network. Neither NETWORK nor NEXT_PUBLIC_DEFAULT_NETWORK is set (in a browser bundle process.env is empty, so this is expected there; in Node it means the variable is unset). Pass an explicit network argument \u2014 getStakeProgramId('devnet') or getStakeProgramId('mainnet') \u2014 or set STAKE_PROGRAM_ID to override the address directly. Refusing to guess: this resolves a fund-custody program address, and callers that derive PDAs from it (deriveStakePool, deriveStakeVaultAuth, deriveDepositPda) would otherwise produce addresses for the wrong network." + ); })(); const id = STAKE_PROGRAM_IDS[detectedNetwork]; if (!id) { diff --git a/dist/index.js.map b/dist/index.js.map index c391452..84a83de 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};\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 { 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]);\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/** The standalone percolator-nft program (TransferHook + mint authority). */\nexport const NFT_PROGRAM_ID = new PublicKey(\n NFT_PROGRAM_OVERRIDE ?? \"FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS\",\n);\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 — no confirmed mainnet stake/vault deployment found in any\n * v17 planning doc (Percolator mainnet is still in prep). Do not treat this as ground\n * truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps confirms.\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 // In browser bundles, process.env is empty (env vars aren't inlined into\n // third-party SDK code). Default to mainnet to match the app's fail-closed\n // behavior — devnet must be opted into explicitly.\n if (typeof window !== 'undefined') return 'mainnet' as const;\n return 'devnet' as const;\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;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;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;;;AC3ZA,SAAS,aAAAC,kBAAiB;;;ACjB1B,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;;;AD/JA,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA;AACF,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;AAGO,IAAM,iBAAiB,IAAIC;AAAA,EAChC,wBAAwB;AAC1B;AAEO,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;AAmBO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC/C;AAgBO,IAAM,8BAA6C;AAAA,EACxD;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAC/C;AAaO,IAAM,yBAAwC;AAAA,EACnD;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAChC;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;;;AEtaA,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;AA0BjD,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;AAI3B,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,WAAO;AAAA,EACT,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;;;AC76DA,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\";\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};\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 diff --git a/dist/solana/stake.d.ts b/dist/solana/stake.d.ts index fa7978b..67c0f7e 100644 --- a/dist/solana/stake.d.ts +++ b/dist/solana/stake.d.ts @@ -34,9 +34,16 @@ export { TOKEN_2022_PROGRAM_ID }; * new integrations) and already runs the ADOPTED `percolator-stake` lineage this * module targets — see the module doc above. * - * mainnet: UNVERIFIED — no confirmed mainnet stake/vault deployment found in any - * v17 planning doc (Percolator mainnet is still in prep). Do not treat this as ground - * truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps confirms. + * mainnet: UNVERIFIED as *ours* — no confirmed mainnet stake/vault deployment exists + * in any v17 planning doc (Percolator mainnet is still in prep). Do not treat this as + * ground truth; prefer the STAKE_PROGRAM_ID env override on mainnet until DevOps + * confirms. + * + * IMPORTANT: "unverified" does NOT mean "inert". Checked against mainnet RPC on + * 2026-08-16, DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F is a LIVE, executable + * BPFLoaderUpgradeable program. That is precisely why getStakeProgramId() must not + * silently default to mainnet: an unconfigured browser caller would have resolved to + * a real, executing mainnet program rather than failing safe. */ export declare const STAKE_PROGRAM_IDS: { readonly devnet: "GCHhcgwPyrai8SWHEVWw3odedguFXEtJobNnWSfWBCU3"; diff --git a/src/abi/nft.ts b/src/abi/nft.ts index 5c4a747..a0a4c38 100644 --- a/src/abi/nft.ts +++ b/src/abi/nft.ts @@ -16,6 +16,7 @@ */ import { PublicKey } from "@solana/web3.js"; +import { PROGRAM_IDS_V17 } from "../config/program-ids.js"; import { safeEnv } from "../config/program-ids.js"; // --------------------------------------------------------------------------- @@ -25,6 +26,7 @@ import { safeEnv } from "../config/program-ids.js"; /** Allowlist of known NFT program addresses. */ const KNOWN_NFT_PROGRAM_IDS = new Set([ "FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS", // mainnet + PROGRAM_IDS_V17.nft, // v17 devnet — the default below ]); const NFT_PROGRAM_OVERRIDE = safeEnv("NFT_PROGRAM_ID"); @@ -36,10 +38,17 @@ if (NFT_PROGRAM_OVERRIDE !== undefined && !KNOWN_NFT_PROGRAM_IDS.has(NFT_PROGRAM ); } -/** The standalone percolator-nft program (TransferHook + mint authority). */ -export const NFT_PROGRAM_ID = new PublicKey( - NFT_PROGRAM_OVERRIDE ?? "FqhKJT9gtScjrmfUuRMjeg7cXNpif1fqsy5Jh65tJmTS", -); +/** + * The standalone percolator-nft program (TransferHook + mint authority). + * + * Derived from `PROGRAM_IDS_V17.nft` rather than carrying its own literal, so this constant + * and `program-ids.ts` cannot drift apart. They previously did: this defaulted to the MAINNET + * address while every other id in the SDK is devnet, so any consumer importing it built + * transactions against a program that does not exist on devnet and failed late with + * "Account not found on-chain". The frontend hit exactly that and had to define its own + * constant to work around it. + */ +export const NFT_PROGRAM_ID = new PublicKey(NFT_PROGRAM_OVERRIDE ?? PROGRAM_IDS_V17.nft); export function getNftProgramId(): PublicKey { return NFT_PROGRAM_ID;