@panoptic-eng/sdk 1.0.33 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/cow/index.js +3 -3
  2. package/dist/{cow-aX6of9TS.js → cow-Zsey85vV.js} +2 -2
  3. package/dist/{cow-aX6of9TS.js.map → cow-Zsey85vV.js.map} +1 -1
  4. package/dist/deployments.d.ts +5 -1
  5. package/dist/deployments.d.ts.map +1 -1
  6. package/dist/deployments.js +7 -1
  7. package/dist/deployments.js.map +1 -1
  8. package/dist/index-CURXeKNy.d.ts.map +1 -1
  9. package/dist/index.d.ts +405 -548
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +807 -551
  12. package/dist/index.js.map +1 -1
  13. package/dist/{irm-JPcV9ykY.js → irm-C02_oZwE.js} +12 -3
  14. package/dist/{irm-JPcV9ykY.js.map → irm-C02_oZwE.js.map} +1 -1
  15. package/dist/{irm-Dw2agmGR.d.ts → irm-CmgC1Mqi.d.ts} +3 -3
  16. package/dist/{irm-Dw2agmGR.d.ts.map → irm-CmgC1Mqi.d.ts.map} +1 -1
  17. package/dist/panoptic/v2/index.d.ts +1 -1
  18. package/dist/panoptic/v2/index.js +5 -5
  19. package/dist/panoptic/v2/react-public.d.ts +3 -3
  20. package/dist/panoptic/v2/react-public.d.ts.map +1 -1
  21. package/dist/panoptic/v2/react-public.js +7 -7
  22. package/dist/{position-C8rkkKhi.js → position-Ca57RRjN.js} +2 -2
  23. package/dist/{position-C8rkkKhi.js.map → position-Ca57RRjN.js.map} +1 -1
  24. package/dist/{router-CS86ptMu.js → router-BOwbvQBP.js} +3 -3
  25. package/dist/{router-CS86ptMu.js.map → router-BOwbvQBP.js.map} +1 -1
  26. package/dist/{router-DcoU2KmV.js → router-CW5w7Y5U.js} +2 -2
  27. package/dist/{router-DcoU2KmV.js.map → router-CW5w7Y5U.js.map} +1 -1
  28. package/dist/uniswap/index.js +4 -4
  29. package/dist/{v2-B68I6nwv.js → v2-CC5WDfS9.js} +4 -4
  30. package/dist/{v2-B68I6nwv.js.map → v2-CC5WDfS9.js.map} +1 -1
  31. package/dist/{writes-AupZCK4M.js → writes-DUUcU9P7.js} +2 -2
  32. package/dist/{writes-AupZCK4M.js.map → writes-DUUcU9P7.js.map} +1 -1
  33. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"v2-B68I6nwv.js","names":["params: ResolveBlockNumbersParams","blockNumber: bigint","targetTimestamp: number","low: bigint","high: bigint","params: EstimateBlockNumbersParams","params: MulticallReadParams<TContracts>","results: MulticallResult<unknown>[]","tokenURI: string","startBlock: bigint","endBlock: bigint","points: number","plan: SfpmSwapPlan","sfpmV3Abi","params: FetchSfpmV3PoolIdParams","sfpmV3Abi","params: EnsureSfpmV3PoolInitializedParams","WIDE_LIMITS: [number, number]","slippageBps: bigint","params: SfpmSwapPlanParams","invertedLimits: [number, number]","swapOn: 'mint' | 'burn'","packed: bigint","half: bigint","err: unknown","params: QuoteSfpmSwapParams","sfpmV3Abi","params: GetUniswapV3PoolFromIdParams","params: GetUniswapV4PoolKeyFromIdParams","params: GetEnforcedTickLimitsParams","params: GetChunkLiquiditiesParams","params: GetFactoryTokenURIParams","params: GetFactoryOwnerOfParams","params: GetFactoryConstructMetadataParams","params: GetPanopticPoolAddressParams","params: MinePoolAddressParams","result: readonly [bigint, bigint]","params: SimulateDeployNewPoolParams","result","params: GetPanopticPoolFromPoolIdParams","params: ResolvePanopticPoolFromPoolIdParams","err: unknown","value: bigint","byteLength: number","addr: Address","hex: Hex","factory: Address","salt: bigint","addrInt: bigint","deployerAddress: Address","v3Pool: Address","riskEngine: Address","poolKey: PoolKey","params: MinePoolAddressLocalParams","params: GetAccountPremiaParams","_meta","params: GetPositionsWithPremiaParams","positions: PositionWithPremia[]","legs: TokenIdLeg[]","params: EstimateCollateralRequiredParams","effectiveTick: bigint","params: GetMaxPositionSizeParams","positionIds: bigint[]","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n low: bigint\n high: bigint\n precisionDivisor: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}","positionSize: bigint","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n positionSize: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}","tickLimits: readonly [number, number, number]","tickLimits","params: GetRequiredCreditForITMParams","tickTriplet: readonly [number, number, number]","params: GetItmAmountsParams","Q192","value: bigint","tokenIndex: 0n | 1n","signedAmount: bigint","signedTick: bigint","poolId: bigint","baseTokenId: bigint","neutralLegs: NeutralLeg[]","prepend: boolean","params: CreateFlowNeutralTokenIdParams","index: 0n | 1n","amount: bigint","abs","indices: (0n | 1n)[]","residual: RequiredCreditForITM","params: GetMaxWithdrawableParams","params: GetMaxRedeemParams","params: {\n client: PublicClient\n collateralTrackerAddress: Address\n account: Address\n assets: bigint\n positionIdList: bigint[]\n usePremiaAsCollateral: boolean\n}","client: PublicClient","poolAddress: Address","tokenIndex: 0 | 1","providedAddress?: Address","params: ERC4626PreviewParams","params: GetGuardianUnlockStateParams","params: GetSafeModeParams","params: GetPortfolioValueParams","params: CheckCollateralAcrossTicksParams","MIN_TICK","MAX_TICK","dataPoints: CollateralDataPoint[]","params: OptimizeTokenIdRiskPartnersParams","effectiveTick: bigint","params: GetPoolLiquiditiesParams","TEN","formatRatio","numerator: bigint","denominator: bigint","precision: bigint","bps: bigint","util: bigint","percent: string","config: PoolFormatterConfig","tick: bigint","precision: bigint","price: string","amount: bigint","amount: string","TEN","formatRatio","numerator: bigint","denominator: bigint","precision: bigint","chainId: bigint","address: Address","tokenListId: string","token0Symbol: string","token1Symbol: string","feeBps: bigint","numerator: bigint","denominator: bigint","precision: bigint","address: string","timestamp: bigint","locale?: string","options?: Intl.DateTimeFormatOptions","ms: bigint","minutes","seconds: bigint","blockNumber: bigint","gas: bigint","hash: string","value: bigint","tokenId: bigint","poolId: bigint","formatted: string","wei: bigint","params: GetAccountGreeksParams","targetBlock","_meta","positions: AccountGreeksResult['positions']","params: CalculateAccountGreeksPureParams","totalValue: bigint[]","totalDelta: bigint[]","positionResults: AccountGreeksCurveResult['positions']","posValues: bigint[]","posDeltas: bigint[]","posGammas: bigint[]","MIN_TICK","MAX_TICK","Q128","a: bigint","b: bigint","convert0to1","amount: bigint","sqrtPriceX96: bigint","convert1to0","params: GetMarginBufferParams","collateralToken0: Address","collateralToken1: Address","calls: MulticallBlockCall[]","usageBps0: bigint | null","usageBps1: bigint | null","crossMarginUsageBps: bigint | null","mintableMarginBinding: bigint | null","required: bigint | undefined","balance: bigint | undefined","denominatedInToken: 0 | 1","lowerLiquidationTick: bigint | null","upperLiquidationTick: bigint | null","liquidationDistance: bigint | null","params: GetDeltaHedgeParamsInput","currentTick: bigint","tickSpacing: bigint","poolMeta: BlockMeta","primaryAsset: bigint","currentDelta: bigint","hedgeLeg: LegConfig","simulatedTickAfter: bigint | undefined","collateralAddresses: [Address, Address]","blockNumber: bigint","client: Client","e: unknown","client: Client","collateralTrackerAddresses: Address[]","chainId: number","blockNumber?: bigint","Q128","convert0to1","amount: bigint","sqrtPriceX96: bigint","convert1to0","params: GetAccountBuyingPowerParams","collateralToken0: Address","collateralToken1: Address","calls: MulticallBlockCall[]","params: BuildCreditWrappedDispatchParams","swapping: TickAndSpreadLimits","notSwapping: TickAndSpreadLimits","wrapped: DispatchIntent","params: SimulateDispatchParams","tokenFlow: TokenFlow","data: Hex | undefined","data","data: DispatchSimulation","BPS_DENOMINATOR","params: BuildTokenShortfallRecoveryDispatchParams","error: unknown","candidate: NotEnoughTokensError | null","args: Partial<\n Pick<NotEnoughTokensError, 'tokenAddress' | 'assetsRequested' | 'assetBalance'>\n >","estimatedAmountIn: bigint","slippageBps: bigint","tokenFlow: TokenFlow","tokenInIndex: 0n | 1n","tokenIndex: 0n | 1n","tokenOutIndex: 0n | 1n","params: TokenShortfallRecoveryQuoteParams","params: GetOpenPositionPreviewParams","tokenShortfall: NotEnoughTokensError | null","params: GetNativeTokenPriceParams","params: GetAccountHistoryParams","trades: AccountTrade[]","params: GetUniswapFeeHistoryParams","_meta","initialFees0: bigint | null","initialFees1: bigint | null","snapshots: UniswapFeeSnapshot[]","client: PublicClient","blockNumbers: (bigint | undefined)[]","legs: StreamiaLeg[]","poolConfig: PoolVersionConfig","blockData: UniswapBlockData","blockNumber: bigint | undefined","uniqueTicks: number[]","poolAddress: Address","stateViewAddress: Address","poolId: `0x${string}`","params: GetStreamiaHistoryParams","_meta","initialUniswapFees0: bigint | null","initialUniswapFees1: bigint | null","snapshots: StreamiaSnapshot[]","params: GetUniswapV3PoolInfoParams","startTick: number","tickSpacing: number","nTicks: bigint","params: GetUniswapV3PoolLiquiditiesParams","poolKey: UniswapV4PoolKey","_params: ResolveUniswapV4PoolKeyParams","params: GetUniswapV4PoolBasicStateParams","client: Pick<PublicClient, 'multicall'>","address: Address","blockNumber?: bigint","params: GetUniswapV4PoolInfoParams","params: GetUniswapV4PoolLiquiditiesParams","Q128","error: unknown","params: GetUniswapV3LpPositionStateParams","feeGrowthInsideCurrentX128: bigint","feeGrowthInsideLastX128: bigint","liquidity: bigint","params: GetUniswapV4LpPositionStateParams","params: GetPriceHistoryParams","_meta","snapshots: PriceSnapshot[]","client: PublicClient","blockNumber: bigint | undefined","poolConfig: PoolVersionConfig","tokenId: bigint","callName: string","cause?: unknown","params: GetPositionEnrichmentDataParams","client: PublicClient","queryAddress: Address","positions: PositionInput[]","currentTick: number","blockNumber: bigint | undefined","_meta: BlockMeta","panopticQueryAbi","entries: [string, PositionEnrichmentResult][]","params: GetSyncStatusParams","params: SaveClosedPositionParams","history: ClosedPosition[]","params: GetTradeHistoryParams","params: GetRealizedPnLParams","params: Omit<\n GetTradeHistoryParams,\n 'limit' | 'offset' | 'closureReason' | 'fromBlock' | 'toBlock'\n >","chunk: LiquidityChunkKey","key: string","params: AddTrackedChunksParams","trackedKeys: Set<string>","params: RemoveTrackedChunksParams","params: GetTrackedChunksParams","params: GetChunkSpreadsParams","netLiquidity: bigint","removedLiquidity: bigint","vegoid: bigint","params: ScanChunksParams","chunks: ScannedChunk[]","params: GetPositionChunkDataParams","_meta","positions: PositionChunkData[]","legs: LegChunkData[]","params: AddPendingPositionParams","pending: PendingPosition[]","params: GetPendingPositionsParams","params: ConfirmPendingPositionParams","params: FailPendingPositionParams","currentBlock: bigint","maxAgeBlocks: bigint","params: EventReconstructionParams","mintEvents: MintEvent[]","burnEvents: BurnEvent[]","openPositions: bigint[]","closedPositions: bigint[]","client: PublicClient","poolAddress: Address","foundBlock: bigint | null","params: SimulateBatchDispatchParams","params: SimulateClosePositionParams","tickLimits: readonly [number, number, number]","tickLimits","data: ClosePositionSimulation","params: SimulateForceExerciseParams","emptyTokenFlow: TokenFlow","_meta","data: ForceExerciseSimulation","tokenFlow: TokenFlow","params: SimulateLiquidateParams","emptyTokenFlow: TokenFlow","_meta","data: LiquidateSimulation","tokenFlow: TokenFlow","params: SimulateSettleParams","tokenFlow: TokenFlow","forfeitAmounts: [bigint, bigint] | undefined","data: SettleSimulation","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n positionIdList: bigint[]\n tokenId: bigint\n dispatchCallData: Hex\n blockNumber: bigint\n}","data: Hex","params: SimulateDepositParams","data: DepositSimulation","params: SimulateWithdrawParams","data: WithdrawSimulation","poolKey: PoolKey","v3PoolAddress: Address","params: SimulateSFPMParams","creditTokenId: bigint","existingPositionIds: bigint[]","amount: bigint","mintTickLimits: readonly [number, number, number]","burnTickLimits: readonly [number, number, number]","builderCode: bigint","tokenFlow: TokenFlow","tokenOutIndex: bigint","params: SimulateSwapExactOutParams","params: SimulateSwapExactInParams","sqrtPriceX96: bigint","amount: bigint","fromTokenIndex: bigint","toTokenIndex: bigint","tokenFlow: TokenFlow","index: bigint","value: bigint","amount: bigint","slippageBps: bigint","params: OneTokenFlowQuoteParams","swapAmount: bigint","direction: CreditWrapDirection","baseTargetDelta: bigint | null","maximumAmountIn","POOL_EVENT_NAMES: Record<string, PanopticEventType>","COLLATERAL_EVENT_NAMES: Record<string, PanopticEventType>","RISK_ENGINE_EVENT_NAMES: Record<string, PanopticEventType>","SFPM_EVENT_NAMES: Record<string, PanopticEventType>","POOL_MANAGER_EVENT_NAMES: Record<string, PanopticEventType>","log: DecodedLog","eventName: string","params: WatchEventsParams","unwatchFns: (() => void)[]","events: PanopticEvent[]","DEFAULT_RECONNECT_CONFIG: ReconnectConfig","params: CreateEventSubscriptionParams","config: ReconnectConfig","unwatchFns: (() => void)[]","reconnectTimeout: ReturnType<typeof setTimeout> | null","a: PanopticEvent","b: PanopticEvent","event: PanopticEvent","poolEventTypes: PanopticEventType[]","collateralEventTypes: PanopticEventType[]","riskEngineEventTypes: PanopticEventType[]","sfpmEventTypes: PanopticEventType[]","poolManagerEventTypes: PanopticEventType[]","fromBlock: bigint","toBlock: bigint","allEvents: PanopticEvent[]","parseLog: (log: DecodedLog) => PanopticEvent | null","events: PanopticEvent[]","eventType: PanopticEventType","error: Error","params: CreateEventPollerParams","pollTimeout: ReturnType<typeof setTimeout> | null","poolEventTypes: PanopticEventType[]","collateralEventTypes: PanopticEventType[]","riskEngineEventTypes: PanopticEventType[]","sfpmEventTypes: PanopticEventType[]","poolManagerEventTypes: PanopticEventType[]","from: bigint","to: bigint","allEvents: PanopticEvent[]"],"sources":["../src/panoptic/v2/clients/blocksByTimestamp.ts","../src/panoptic/v2/clients/multicall.ts","../src/panoptic/v2/utils/factory.ts","../src/panoptic/v2/utils/interpolateBlocks.ts","../src/panoptic/v2/sfpmSwap/calldata.ts","../src/panoptic/v2/sfpmSwap/init.ts","../src/panoptic/v2/sfpmSwap/plan.ts","../src/panoptic/v2/sfpmSwap/quote.ts","../src/panoptic/v2/reads/sfpm.ts","../src/panoptic/v2/reads/factory.ts","../src/panoptic/v2/reads/minePoolAddressLocal.ts","../src/panoptic/v2/reads/premia.ts","../src/panoptic/v2/reads/collateralEstimate.ts","../src/panoptic/v2/reads/erc4626.ts","../src/panoptic/v2/reads/guardian.ts","../src/panoptic/v2/reads/safeMode.ts","../src/panoptic/v2/reads/queryUtils.ts","../src/panoptic/v2/reads/liquidity.ts","../src/panoptic/v2/formatters/percentage.ts","../src/panoptic/v2/formatters/poolFormatters.ts","../src/panoptic/v2/formatters/tokenList.ts","../src/panoptic/v2/formatters/display.ts","../src/panoptic/v2/reads/accountGreeks.ts","../src/panoptic/v2/reads/margin.ts","../src/panoptic/v2/reads/hedge.ts","../src/panoptic/v2/reads/collateralSharePrice.ts","../src/panoptic/v2/reads/collateralTotalAssets.ts","../src/panoptic/v2/reads/buyingPower.ts","../src/panoptic/v2/simulations/creditWrap.ts","../src/panoptic/v2/simulations/simulateDispatch.ts","../src/panoptic/v2/simulations/tokenShortfallRecovery.ts","../src/panoptic/v2/reads/openPositionPreview.ts","../src/panoptic/v2/reads/nativeTokenPrice.ts","../src/panoptic/v2/reads/history.ts","../src/panoptic/v2/reads/uniswapFeeHistory.ts","../src/panoptic/v2/reads/streamiaHistory.ts","../src/panoptic/v2/reads/uniswapPool.ts","../src/panoptic/v2/reads/uniswapLpPosition.ts","../src/panoptic/v2/reads/priceHistory.ts","../src/panoptic/v2/reads/enrichment.ts","../src/panoptic/v2/sync/getSyncStatus.ts","../src/panoptic/v2/sync/tradeHistory.ts","../src/panoptic/v2/sync/chunkTracking.ts","../src/panoptic/v2/sync/pendingPositions.ts","../src/panoptic/v2/sync/eventReconstruction.ts","../src/panoptic/v2/simulations/simulateBatchDispatch.ts","../src/panoptic/v2/simulations/simulateClosePosition.ts","../src/panoptic/v2/simulations/simulateForceExercise.ts","../src/panoptic/v2/simulations/simulateLiquidate.ts","../src/panoptic/v2/simulations/simulateSettle.ts","../src/panoptic/v2/simulations/simulateVault.ts","../src/panoptic/v2/simulations/sfpm.ts","../src/panoptic/v2/simulations/simulateSwap.ts","../src/panoptic/v2/utils/priceConvert.ts","../src/panoptic/v2/simulations/oneTokenFlow.ts","../src/panoptic/v2/abis/poolManager.ts","../src/panoptic/v2/events/watchEvents.ts","../src/panoptic/v2/events/subscription.ts","../src/panoptic/v2/events/poller.ts"],"sourcesContent":["/**\n * Timestamp-to-block resolution via RPC binary search.\n * No subgraph dependency — uses only eth_getBlockByNumber.\n * @module v2/clients/blocksByTimestamp\n */\n\nimport type { PublicClient } from 'viem'\n\n/**\n * Parameters for resolveBlockNumbers.\n */\nexport interface ResolveBlockNumbersParams {\n /** viem PublicClient */\n client: PublicClient\n /** Array of Unix timestamps (seconds) to resolve to block numbers */\n timestamps: number[]\n}\n\n/**\n * Resolve an array of Unix timestamps to the closest block numbers via RPC binary search.\n *\n * All binary searches run in parallel, sharing an in-flight-deduped block cache\n * so concurrent searches for nearby timestamps avoid redundant RPC calls.\n *\n * @param params - The parameters\n * @returns Array of block numbers in the same order as the input timestamps\n *\n * @example\n * ```typescript\n * const blocks = await resolveBlockNumbers({\n * client,\n * timestamps: [1700000000, 1700003600, 1700007200],\n * })\n * // blocks: [18500000n, 18500300n, 18500600n]\n * ```\n */\nexport async function resolveBlockNumbers(params: ResolveBlockNumbersParams): Promise<bigint[]> {\n const { client, timestamps } = params\n\n if (timestamps.length === 0) return []\n\n const latestBlock = await client.getBlock({ blockTag: 'latest', includeTransactions: false })\n const latestNumber = latestBlock.number\n const latestTimestamp = Number(latestBlock.timestamp)\n\n // Cache + in-flight dedup: avoids redundant RPC calls across parallel searches\n const cache = new Map<bigint, number>()\n cache.set(latestNumber, latestTimestamp)\n cache.set(0n, 0) // genesis is always timestamp 0 (close enough)\n\n const inflight = new Map<bigint, Promise<number>>()\n\n function getTimestamp(blockNumber: bigint): Promise<number> {\n const cached = cache.get(blockNumber)\n if (cached !== undefined) return Promise.resolve(cached)\n\n const existing = inflight.get(blockNumber)\n if (existing) return existing\n\n const promise = client.getBlock({ blockNumber, includeTransactions: false }).then((block) => {\n const ts = Number(block.timestamp)\n cache.set(blockNumber, ts)\n inflight.delete(blockNumber)\n return ts\n })\n inflight.set(blockNumber, promise)\n return promise\n }\n\n /**\n * Binary search for the last block whose timestamp <= targetTimestamp.\n */\n async function searchBlock(targetTimestamp: number, low: bigint, high: bigint): Promise<bigint> {\n // Clamp: if target is beyond latest, return latest\n if (targetTimestamp >= latestTimestamp) return latestNumber\n\n while (high - low > 1n) {\n const mid = (low + high) / 2n\n const midTs = await getTimestamp(mid)\n\n if (midTs <= targetTimestamp) {\n low = mid\n } else {\n high = mid\n }\n }\n\n return low\n }\n\n // Run all binary searches in parallel — shared cache deduplicates common midpoints\n const results = await Promise.all(timestamps.map((ts) => searchBlock(ts, 0n, latestNumber)))\n\n return results\n}\n\n/**\n * Parameters for estimateBlockNumbers.\n */\nexport interface EstimateBlockNumbersParams {\n /** viem PublicClient */\n client: PublicClient\n /** Array of Unix timestamps (seconds) to resolve to block numbers */\n timestamps: number[]\n /**\n * Bootstrap block-time used only to pick the anchor block (seconds).\n * The final estimate uses the *measured* rate between latest and anchor,\n * so this only affects which sample point we draw — not accuracy on the\n * sampled window. Default 12 (Ethereum L1).\n */\n fallbackBlockTimeSec?: number\n}\n\n/**\n * Estimate block numbers for the given Unix timestamps using a 2-RPC linear\n * extrapolation. Trades binary-search accuracy (~25 RPCs) for ~2 RPCs.\n *\n * Suitable for chart-style use cases where the consumer plots tens-to-hundreds\n * of evenly-spaced points and a ±N-block error is invisible. Not suitable when\n * exact block correspondence is required (e.g. event log ranges).\n *\n * Algorithm:\n * 1. Fetch `latest` block.\n * 2. Use `fallbackBlockTimeSec` to estimate an anchor block roughly co-temporal\n * with the *earliest* requested timestamp.\n * 3. Fetch the anchor block.\n * 4. Compute the measured average block time over [anchor, latest].\n * 5. Linearly extrapolate every requested timestamp from `latest`.\n *\n * If the sampled window is degenerate (e.g. anchor too close to latest, or\n * timestamps near genesis), falls back to {@link resolveBlockNumbers}.\n */\nexport async function estimateBlockNumbers(params: EstimateBlockNumbersParams): Promise<bigint[]> {\n const { client, timestamps, fallbackBlockTimeSec = 12 } = params\n\n if (timestamps.length === 0) return []\n\n const latest = await client.getBlock({ blockTag: 'latest', includeTransactions: false })\n const latestNum = latest.number\n const latestTs = Number(latest.timestamp)\n\n const earliest = Math.min(...timestamps)\n const secAgoMax = Math.max(0, latestTs - earliest)\n\n // All requested timestamps are now-or-future\n if (secAgoMax === 0) return timestamps.map(() => latestNum)\n\n const blocksBackEst = BigInt(Math.floor(secAgoMax / fallbackBlockTimeSec))\n const anchorNum = blocksBackEst >= latestNum ? 1n : latestNum - blocksBackEst\n const anchor = await client.getBlock({\n blockNumber: anchorNum,\n includeTransactions: false,\n })\n\n const numDelta = latestNum - anchor.number\n const tsDelta = latestTs - Number(anchor.timestamp)\n\n // Degenerate sample window — fall back to exact resolution.\n if (numDelta <= 0n || tsDelta <= 0) {\n return resolveBlockNumbers({ client, timestamps })\n }\n\n const avgBlockTimeSec = tsDelta / Number(numDelta)\n\n return timestamps.map((ts) => {\n const secAgo = latestTs - ts\n if (secAgo <= 0) return latestNum\n const blocksAgo = BigInt(Math.round(secAgo / avgBlockTimeSec))\n return blocksAgo >= latestNum ? 1n : latestNum - blocksAgo\n })\n}\n","/**\n * Multicall utilities for the Panoptic v2 SDK.\n * Uses viem's built-in multicall for same-block consistency.\n * @module v2/clients/multicall\n */\n\nimport type { Abi, Address, ContractFunctionArgs, ContractFunctionName, PublicClient } from 'viem'\n\nimport type { BlockMeta } from '../types'\nimport { getBlockMeta } from './blockMeta'\n\n/**\n * A contract call to include in a multicall batch.\n */\nexport interface MulticallContract<\n TAbi extends Abi = Abi,\n TFunctionName extends ContractFunctionName<TAbi, 'pure' | 'view'> = ContractFunctionName<\n TAbi,\n 'pure' | 'view'\n >,\n> {\n /** Contract address */\n address: Address\n /** Contract ABI */\n abi: TAbi\n /** Function name to call */\n functionName: TFunctionName\n /** Function arguments */\n args?: ContractFunctionArgs<TAbi, 'pure' | 'view', TFunctionName>\n}\n\n/**\n * Parameters for multicallRead.\n */\nexport interface MulticallReadParams<TContracts extends readonly MulticallContract[]> {\n /** viem PublicClient */\n client: PublicClient\n /** Array of contract calls to batch */\n contracts: TContracts\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Whether to allow failures (default: false) */\n allowFailure?: boolean\n}\n\n/**\n * Result type for a single multicall contract result.\n */\nexport type MulticallResult<T> =\n | { status: 'success'; result: T }\n | { status: 'failure'; error: Error }\n\n/**\n * Perform a batched multicall read with block metadata.\n * All calls are executed at the same block for consistency.\n *\n * @param params - The multicall parameters\n * @returns Results array with block metadata\n */\nexport async function multicallRead<TContracts extends readonly MulticallContract[]>(\n params: MulticallReadParams<TContracts>,\n): Promise<{\n results: MulticallResult<unknown>[]\n _meta: BlockMeta\n}> {\n const { client, contracts, blockNumber, allowFailure = false } = params\n\n // Get the block number to use (latest if not specified)\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n // Execute multicall and get block meta in parallel\n const [multicallResults, _meta] = await Promise.all([\n client.multicall({\n contracts: contracts as unknown as Parameters<typeof client.multicall>['0']['contracts'],\n blockNumber: targetBlockNumber,\n allowFailure: true, // Always allow failure internally to handle gracefully\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Map results to our format\n const results: MulticallResult<unknown>[] = multicallResults.map((result) => {\n if (result.status === 'success') {\n return { status: 'success' as const, result: result.result }\n } else {\n // If allowFailure is false and we have a failure, throw\n if (!allowFailure) {\n throw result.error\n }\n return { status: 'failure' as const, error: result.error }\n }\n })\n\n return { results, _meta }\n}\n","/**\n * Factory utility functions for the Panoptic v2 SDK.\n * @module v2/utils/factory\n */\n\n/**\n * Decoded Panoptic NFT metadata from a base64-encoded token URI.\n */\nexport type PanopticNFTMetadata = {\n name: string\n description: string\n attributes: [\n {\n trait_type: 'Rarity'\n value: string\n },\n {\n trait_type: 'Strategy'\n value: string\n },\n {\n trait_type: 'ChainId'\n value: string\n },\n ]\n image: string\n}\n\n/**\n * Decode a base64-encoded Panoptic NFT token URI into metadata.\n *\n * @param tokenURI - The base64-encoded data URI string\n * @returns Parsed NFT metadata object, or undefined if input is invalid\n */\nexport function decodePanopticTokenURI(tokenURI: string): PanopticNFTMetadata | undefined {\n if (tokenURI === undefined || tokenURI === '') {\n return undefined\n }\n const parts = tokenURI.split('data:application/json;base64,')\n if (parts.length < 2 || parts[1] === '') {\n return undefined\n }\n try {\n const decoded = atob(parts[1])\n return JSON.parse(decoded) as PanopticNFTMetadata\n } catch {\n return undefined\n }\n}\n","/**\n * Evenly-spaced block number interpolation utility.\n * @module v2/utils/interpolateBlocks\n */\n\nimport { InvalidHistoryRangeError } from '../errors/sdk'\n\n/**\n * Generate evenly-spaced block numbers between start and end (pure math, no RPC).\n *\n * @param startBlock - First block in the range\n * @param endBlock - Last block in the range\n * @param points - Number of evenly-spaced data points to generate\n * @returns Array of interpolated block numbers\n *\n * @throws {InvalidHistoryRangeError} if startBlock > endBlock or points < 0\n */\nexport function interpolateBlocks(startBlock: bigint, endBlock: bigint, points: number): bigint[] {\n if (!Number.isFinite(points) || !Number.isSafeInteger(points)) {\n throw new InvalidHistoryRangeError(`points must be a finite safe integer, got ${points}`)\n }\n if (points < 0) {\n throw new InvalidHistoryRangeError(`points must be >= 0, got ${points}`)\n }\n if (startBlock > endBlock) {\n throw new InvalidHistoryRangeError(\n `startBlock (${startBlock}) must be <= endBlock (${endBlock})`,\n )\n }\n if (points === 0) return []\n if (points === 1) return [endBlock]\n const range = endBlock - startBlock\n return Array.from(\n { length: points },\n (_, i) => startBlock + (range * BigInt(i)) / BigInt(points - 1),\n )\n}\n","/**\n * Encode SFPM swap calldata (mint + burn wrapped in a single multicall).\n * @module v2/sfpmSwap/calldata\n */\nimport { type Hex, encodeFunctionData } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport type { SfpmSwapPlan } from './types'\n\n/** Encoded calldata for an SFPM swap. */\nexport interface SfpmSwapCalldata {\n /** The `SFPM.multicall(bytes[])` calldata to send to {@link SfpmSwapPlan.sfpmAddress}. */\n multicallData: Hex\n /** The inner `mintTokenizedPosition` calldata (index 0 of the multicall). */\n mintData: Hex\n /** The inner `burnTokenizedPosition` calldata (index 1 of the multicall). */\n burnData: Hex\n}\n\n/**\n * Encode the `multicall([mint, burn])` for a swap plan.\n *\n * The order is always `[mint, burn]` — the ERC1155 must be minted before it is\n * burned. Which call carries the inverted (swap) limits is decided in the plan.\n */\nexport function buildSfpmSwapCalldata(plan: SfpmSwapPlan): SfpmSwapCalldata {\n const mintData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'mintTokenizedPosition',\n args: [\n plan.poolKey,\n plan.tokenId,\n plan.positionSize,\n plan.mintTickLimits[0],\n plan.mintTickLimits[1],\n ],\n })\n const burnData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'burnTokenizedPosition',\n args: [\n plan.poolKey,\n plan.tokenId,\n plan.positionSize,\n plan.burnTickLimits[0],\n plan.burnTickLimits[1],\n ],\n })\n const multicallData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'multicall',\n args: [[mintData, burnData]],\n })\n return { multicallData, mintData, burnData }\n}\n","/**\n * Resolve / ensure a Uniswap v3 pool is registered on the SFPM.\n * @module v2/sfpmSwap/init\n */\nimport type { Address, PublicClient, WalletClient } from 'viem'\nimport { getAddress, zeroAddress } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport { PanopticError, WrongUniswapPoolError } from '../errors'\nimport { DEFAULT_VEGOID } from '../tokenId'\n\nexport interface FetchSfpmV3PoolIdParams {\n client: PublicClient\n sfpmAddress: Address\n token0: Address\n token1: Address\n /** Uniswap fee tier (e.g. 500 for 0.05%). */\n fee: number\n /** Vegoid; defaults to the SDK {@link DEFAULT_VEGOID}. Must match the market's other pools. */\n vegoid?: number\n}\n\n/**\n * Resolve the `uint64` SFPM poolId for a Uniswap v3 pool, initializing it if needed.\n *\n * `initializeAMMPool` is permissionless and idempotent and **returns the poolId**\n * whether or not the pool was already registered, so a `simulateContract` call is\n * enough to learn the id without sending a transaction. Always resolve the id this\n * way rather than encoding it offline — the SFPM can collision-increment ids.\n */\nexport async function fetchSfpmV3PoolId(params: FetchSfpmV3PoolIdParams): Promise<bigint> {\n const { client, sfpmAddress, token0, token1, fee } = params\n const vegoid = params.vegoid ?? Number(DEFAULT_VEGOID)\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'initializeAMMPool',\n args: [token0, token1, fee, vegoid],\n })\n return BigInt(result)\n}\n\nexport interface EnsureSfpmV3PoolInitializedParams extends FetchSfpmV3PoolIdParams {\n wallet: WalletClient\n /** Expected underlying Uniswap v3 pool; if provided, the resolved id is verified against it. */\n expectedPool?: Address\n}\n\nexport interface EnsureSfpmV3PoolInitializedResult {\n poolId: bigint\n /** True if an `initializeAMMPool` transaction was sent (pool was not yet registered). */\n initialized: boolean\n}\n\n/**\n * Ensure a Uniswap v3 pool is registered on the SFPM, sending `initializeAMMPool`\n * only if it is not already registered. Returns the resolved poolId.\n *\n * When `expectedPool` is given, the resolved id is checked to map back to it via\n * `getUniswapV3PoolFromId` — guards against a wrong token/fee triple.\n */\nexport async function ensureSfpmV3PoolInitialized(\n params: EnsureSfpmV3PoolInitializedParams,\n): Promise<EnsureSfpmV3PoolInitializedResult> {\n const { client, wallet, sfpmAddress, token0, token1, fee, expectedPool } = params\n const vegoid = params.vegoid ?? Number(DEFAULT_VEGOID)\n\n const poolId = await fetchSfpmV3PoolId({ client, sfpmAddress, token0, token1, fee, vegoid })\n\n const registered = await client.readContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n\n let initialized = false\n let resolved = registered\n if (getAddress(registered) === zeroAddress) {\n const account = wallet.account\n if (account === undefined) throw new PanopticError('wallet client has no account')\n const hash = await wallet.writeContract({\n account,\n chain: wallet.chain ?? null,\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'initializeAMMPool',\n args: [token0, token1, fee, vegoid],\n })\n await client.waitForTransactionReceipt({ hash })\n initialized = true\n // Re-read only after we sent initializeAMMPool; an already-registered pool\n // reuses the first read.\n resolved = await client.readContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n }\n\n if (expectedPool !== undefined && getAddress(resolved) !== getAddress(expectedPool)) {\n throw new WrongUniswapPoolError(\n new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`),\n )\n }\n\n return { poolId, initialized }\n}\n","/**\n * Build an SFPM off-venue swap plan (tokenId + per-call tick limits).\n * @module v2/sfpmSwap/plan\n */\nimport { encodeAbiParameters } from 'viem'\n\nimport { PanopticError } from '../errors'\nimport { createTokenIdBuilder } from '../tokenId'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport type { SfpmSwapPlan, SfpmSwapPlanParams } from './types'\n\n/** Wide, non-inverted band for the paired (non-swapping) call — never triggers a swap. */\nconst WIDE_LIMITS: [number, number] = [Number(MIN_TICK) + 1, Number(MAX_TICK) - 1]\n\n/**\n * Convert a slippage tolerance in bps to a conservative Uniswap tick distance.\n *\n * Ticks are 1.0001^tick, so each tick ≈ 1 bps. This walks up powers of 1.0001\n * until the cumulative price move covers `slippageBps`, matching the hedger-bot's\n * dispatch-path helper so both swap paths agree on band width.\n */\nexport function slippageBpsToTickDistance(slippageBps: bigint): bigint {\n if (slippageBps < 0n || slippageBps > 1000n) {\n throw new PanopticError(`slippage bps ${slippageBps} out of bounds (0..1000)`)\n }\n if (slippageBps === 0n) return 0n\n let numerator = 1n\n let denominator = 1n\n let ticks = 0n\n while (numerator * 10_000n < denominator * (10_000n + slippageBps)) {\n numerator *= 10_001n\n denominator *= 10_000n\n ticks += 1n\n }\n return ticks\n}\n\n/**\n * Build the swap plan.\n *\n * Mechanism (verified in the Phase 0 fork test):\n * - A single-leg **loan** tokenId (width=0, isLong=false, `asset == tokenType`) moves\n * exactly `positionSize` of the `tokenType` token when its call carries inverted\n * tick limits (`low > high`); the paired call uses a wide band and moves nothing.\n * - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.\n * - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the\n * **output** token index.\n *\n * The inverted band is centered on `currentTick` at ±`slippageBpsToTickDistance`,\n * which the SFPM re-sorts and enforces as an open interval on the post-swap tick.\n */\nexport function buildSfpmSwapPlan(params: SfpmSwapPlanParams): SfpmSwapPlan {\n const { sfpmAddress, poolAddress, poolId, kind, zeroForOne, amount, currentTick, slippageBps } =\n params\n\n if (amount <= 0n) throw new PanopticError(`swap amount must be positive (got ${amount})`)\n\n const distance = slippageBpsToTickDistance(slippageBps)\n if (distance < 1n) {\n // low > high must hold strictly to trigger the swap, and the post-swap tick\n // check is an open interval — a zero-width band can never pass.\n throw new PanopticError(\n `slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`,\n )\n }\n\n // exactIn → tokenType = input token; exactOut → tokenType = output token.\n const tokenType = kind === 'exactIn' ? (zeroForOne ? 0n : 1n) : zeroForOne ? 1n : 0n\n\n const tokenId = createTokenIdBuilder(poolId)\n .addLoan({ asset: tokenType, tokenType, strike: 0n })\n .build()\n\n const d = Number(distance)\n // Inverted (swap-triggering) band: low > high, clamped to the valid tick range\n // so an extreme tolerance near a range extreme can't produce an unrepresentable\n // limit.\n const low = Math.min(Number(MAX_TICK), currentTick + d)\n const high = Math.max(Number(MIN_TICK), currentTick - d)\n if (low <= high) {\n throw new PanopticError(\n `slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`,\n )\n }\n const invertedLimits: [number, number] = [low, high]\n const swapOn: 'mint' | 'burn' = kind === 'exactIn' ? 'mint' : 'burn'\n\n return {\n sfpmAddress,\n poolAddress,\n poolKey: encodeAbiParameters([{ type: 'address' }], [poolAddress]),\n tokenId,\n positionSize: amount,\n mintTickLimits: swapOn === 'mint' ? invertedLimits : WIDE_LIMITS,\n burnTickLimits: swapOn === 'burn' ? invertedLimits : WIDE_LIMITS,\n swapOn,\n kind,\n }\n}\n","/**\n * Quote an SFPM off-venue swap by simulating the actual multicall.\n * @module v2/sfpmSwap/quote\n */\nimport { type Address, type PublicClient, type StateOverride, decodeFunctionResult } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError, parsePanopticError } from '../errors'\nimport type { SimulationResult } from '../types'\nimport { buildSfpmSwapCalldata } from './calldata'\nimport type { SfpmSwapPlan, SfpmSwapQuote } from './types'\n\nconst UINT128 = 1n << 128n\nconst INT128_MAX = (1n << 127n) - 1n\n\n/** Extract the two signed 128-bit slots from a packed `LeftRightSigned` int256. */\nfunction unpackLeftRightSigned(packed: bigint): { right: bigint; left: bigint } {\n const u = packed < 0n ? packed + (1n << 256n) : packed\n const toInt128 = (half: bigint): bigint => (half > INT128_MAX ? half - UINT128 : half)\n return {\n right: toInt128(u & (UINT128 - 1n)), // token0\n left: toInt128((u >> 128n) & (UINT128 - 1n)), // token1\n }\n}\n\n/** Wrap an unknown thrown value as a PanopticError, decoding Panoptic reverts when possible. */\nfunction toPanopticError(err: unknown): PanopticError {\n if (err instanceof PanopticError) return err\n const parsed = parsePanopticError(err)\n if (parsed) return parsed.error\n return new PanopticError(\n err instanceof Error ? err.message : 'SFPM swap simulation failed',\n err instanceof Error ? err : undefined,\n )\n}\n\nexport interface QuoteSfpmSwapParams {\n client: PublicClient\n /** Plan from {@link buildSfpmSwapPlan}. */\n plan: SfpmSwapPlan\n /** Caller executing the swap (the Safe in production); must hold the input token. */\n account: Address\n /**\n * Optional viem state overrides — e.g. to grant the input-token allowance to the\n * SFPM and/or fund the account so the quote works before approvals exist. In\n * production (Safe already approved + funded) this can be omitted.\n */\n stateOverride?: StateOverride\n blockNumber?: bigint\n}\n\n/**\n * Quote a swap by simulating `SFPM.multicall([mint, burn])` and decoding the swap\n * call's `totalMoved` return. Authoritative — captures the width-0 loan-leg wei\n * rounding a raw QuoterV2 quote would miss.\n */\nexport async function quoteSfpmSwap(\n params: QuoteSfpmSwapParams,\n): Promise<SimulationResult<SfpmSwapQuote>> {\n const { client, plan, account, stateOverride, blockNumber } = params\n const { mintData, burnData } = buildSfpmSwapCalldata(plan)\n const _meta = await getBlockMeta({ client, blockNumber })\n\n try {\n const { result } = await client.simulateContract({\n account,\n address: plan.sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'multicall',\n args: [[mintData, burnData]],\n blockNumber,\n stateOverride,\n })\n\n const swapIndex = plan.swapOn === 'mint' ? 0 : 1\n const decoded = decodeFunctionResult({\n abi: sfpmV3Abi,\n functionName: plan.swapOn === 'mint' ? 'mintTokenizedPosition' : 'burnTokenizedPosition',\n data: (result as readonly `0x${string}`[])[swapIndex],\n }) as readonly [readonly bigint[], bigint, number]\n\n const finalTick = Number(decoded[2])\n const { right, left } = unpackLeftRightSigned(decoded[1])\n const inSlot = [right, left].find((s) => s > 0n)\n const outSlot = [right, left].find((s) => s < 0n)\n if (inSlot === undefined || outSlot === undefined) {\n return {\n success: false,\n error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),\n _meta,\n }\n }\n\n return {\n success: true,\n data: { amountIn: inSlot, amountOut: -outSlot, finalTick },\n gasEstimate: 0n,\n _meta,\n }\n } catch (err) {\n return { success: false, error: toPanopticError(err), _meta }\n }\n}\n","/**\n * SFPM read functions — poolId resolution, enforced tick limits, chunk liquidity.\n *\n * @module v2/reads/sfpm\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n semiFungiblePositionManagerV3Abi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { ChunkLimitError } from '../errors'\nimport type { BlockMeta, PoolKey } from '../types'\nimport { MAX_TRACKED_CHUNKS } from '../utils/constants'\n\n// ---------------------------------------------------------------------------\n// getUniswapV3PoolFromId\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link getUniswapV3PoolFromId}.\n */\nexport interface GetUniswapV3PoolFromIdParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManagerV3 address */\n sfpmAddress: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/**\n * Resolve an SFPM poolId to its corresponding Uniswap V3 pool address.\n *\n * Calls `SemiFungiblePositionManagerV3.getUniswapV3PoolFromId(poolId)`.\n */\nexport async function getUniswapV3PoolFromId(\n params: GetUniswapV3PoolFromIdParams,\n): Promise<Address> {\n const { client, sfpmAddress, poolId } = params\n return client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n}\n\n// ---------------------------------------------------------------------------\n// getUniswapV4PoolKeyFromId\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link getUniswapV4PoolKeyFromId}.\n */\nexport interface GetUniswapV4PoolKeyFromIdParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManagerV4 address */\n sfpmAddress: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/**\n * Resolve an SFPM poolId to its corresponding Uniswap V4 pool key.\n *\n * Calls `SemiFungiblePositionManagerV4.getUniswapV4PoolKeyFromId(poolId)`.\n */\nexport async function getUniswapV4PoolKeyFromId(\n params: GetUniswapV4PoolKeyFromIdParams,\n): Promise<PoolKey> {\n const { client, sfpmAddress, poolId } = params\n const raw = await client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getUniswapV4PoolKeyFromId',\n args: [poolId],\n })\n return {\n currency0: raw.currency0,\n currency1: raw.currency1,\n fee: BigInt(raw.fee),\n tickSpacing: BigInt(raw.tickSpacing),\n hooks: raw.hooks,\n }\n}\n\n// ---------------------------------------------------------------------------\n// getEnforcedTickLimits\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getEnforcedTickLimits.\n */\nexport interface GetEnforcedTickLimitsParams {\n /** viem PublicClient */\n client: PublicClient\n /** SFPM address (from getPool().metadata.sfpmAddress) */\n sfpmAddress: Address\n /** Encoded pool ID (from getPool().poolId) */\n poolId: bigint\n}\n\n/**\n * Result from getEnforcedTickLimits.\n */\nexport interface EnforcedTickLimits {\n minEnforcedTick: number\n maxEnforcedTick: number\n}\n\n/**\n * Get the enforced tick limits for a pool from the SFPM.\n *\n * @param params - The parameters\n * @returns The min and max enforced ticks\n */\nexport async function getEnforcedTickLimits(\n params: GetEnforcedTickLimitsParams,\n): Promise<EnforcedTickLimits> {\n const { client, sfpmAddress, poolId } = params\n\n const [minTick, maxTick] = await client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getEnforcedTickLimits',\n args: [poolId],\n })\n\n return {\n minEnforcedTick: minTick,\n maxEnforcedTick: maxTick,\n }\n}\n\n// ---------------------------------------------------------------------------\n// getChunkLiquidities\n// ---------------------------------------------------------------------------\n\nexport interface ChunkInput {\n /** Owner address (panopticPool address for Panoptic chunks) */\n owner: Address\n /** 0 or 1 */\n tokenType: bigint\n tickLower: bigint\n tickUpper: bigint\n}\n\nexport interface ChunkLiquidityResult {\n /** Liquidity currently deployed in Uniswap */\n netLiquidity: bigint\n /** Liquidity removed by long holders */\n removedLiquidity: bigint\n /** Total liquidity deposited by shorts (net + removed) */\n totalLiquidity: bigint\n /** Alias for totalLiquidity (shorts deposited all of it) */\n shortLiquidity: bigint\n /** Alias for removedLiquidity (longs removed this much) */\n longLiquidity: bigint\n}\n\nexport interface GetChunkLiquiditiesParams {\n client: PublicClient\n /** SFPM address */\n sfpmAddress: Address\n /** Pool key bytes (from getPool().metadata.poolKeyBytes) */\n poolKeyBytes: `0x${string}`\n /** Chunks to query */\n chunks: ChunkInput[]\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\nexport interface GetChunkLiquiditiesResult {\n /** One result per input chunk */\n results: ChunkLiquidityResult[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Fetch liquidity breakdown for a batch of chunks via SFPM.getAccountLiquidity().\n *\n * Uses multicall for efficiency. Returns one result per input chunk,\n * along with block metadata for freshness tracking.\n */\nexport async function getChunkLiquidities(\n params: GetChunkLiquiditiesParams,\n): Promise<GetChunkLiquiditiesResult> {\n const { client, sfpmAddress, poolKeyBytes, chunks } = params\n\n if (chunks.length > MAX_TRACKED_CHUNKS) {\n throw new ChunkLimitError(BigInt(chunks.length), 0n)\n }\n\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n\n if (chunks.length === 0) return { results: [], _meta }\n\n // Batch all getAccountLiquidity calls\n const multicallResults = await client.multicall({\n contracts: chunks.map((chunk) => ({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getAccountLiquidity' as const,\n args: [\n poolKeyBytes,\n chunk.owner,\n chunk.tokenType,\n Number(chunk.tickLower),\n Number(chunk.tickUpper),\n ],\n })),\n allowFailure: true,\n })\n\n const results = multicallResults.map((result) => {\n if (result.status === 'failure') {\n return {\n netLiquidity: 0n,\n removedLiquidity: 0n,\n totalLiquidity: 0n,\n shortLiquidity: 0n,\n longLiquidity: 0n,\n }\n }\n\n const packed = result.result as bigint\n // LeftRightUnsigned: right 128 bits = netLiquidity, left 128 bits = removedLiquidity\n const netLiquidity = packed & ((1n << 128n) - 1n)\n const removedLiquidity = packed >> 128n\n const totalLiquidity = netLiquidity + removedLiquidity\n\n return {\n netLiquidity,\n removedLiquidity,\n totalLiquidity,\n shortLiquidity: totalLiquidity,\n longLiquidity: removedLiquidity,\n }\n })\n\n return { results, _meta }\n}\n","/**\n * Factory read functions for the Panoptic v2 SDK.\n *\n * Supports both PanopticFactoryV3 (Uniswap V3) and PanopticFactoryV4 (Uniswap V4).\n *\n * @module v2/reads/factory\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { zeroAddress } from 'viem'\n\nimport { panopticFactoryV3Abi, panopticFactoryV4Abi } from '../../../generated'\nimport type { PoolKey } from '../types'\nimport { getUniswapV3PoolFromId, getUniswapV4PoolKeyFromId } from './sfpm'\n\n// ---------------------------------------------------------------------------\n// Shared reads (identical signature on both V3 and V4)\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getFactoryTokenURI.\n */\nexport interface GetFactoryTokenURIParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** Token ID (encoded pool address) */\n tokenId: bigint\n}\n\n/**\n * Get the token URI from a PanopticFactory NFT.\n */\nexport async function getFactoryTokenURI(params: GetFactoryTokenURIParams): Promise<string> {\n const { client, factoryAddress, version, tokenId } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'tokenURI',\n args: [tokenId],\n })\n}\n\n/**\n * Parameters for getFactoryOwnerOf.\n */\nexport interface GetFactoryOwnerOfParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** Token ID (encoded pool address) */\n tokenId: bigint\n}\n\n/**\n * Get the owner of a PanopticFactory NFT.\n */\nexport async function getFactoryOwnerOf(params: GetFactoryOwnerOfParams): Promise<Address> {\n const { client, factoryAddress, version, tokenId } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'ownerOf',\n args: [tokenId],\n })\n}\n\n/**\n * Parameters for getFactoryConstructMetadata.\n */\nexport interface GetFactoryConstructMetadataParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** PanopticPool address (or predicted address) */\n panopticPoolAddress: Address\n /** Token 0 symbol */\n symbol0: string\n /** Token 1 symbol */\n symbol1: string\n /** Fee tier */\n fee: bigint\n}\n\n/**\n * Construct NFT metadata for a pool via the factory contract.\n */\nexport async function getFactoryConstructMetadata(\n params: GetFactoryConstructMetadataParams,\n): Promise<string> {\n const { client, factoryAddress, version, panopticPoolAddress, symbol0, symbol1, fee } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'constructMetadata',\n args: [panopticPoolAddress, symbol0, symbol1, fee],\n })\n}\n\n// ---------------------------------------------------------------------------\n// V3-specific reads\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getPanopticPoolAddress on a V3 factory.\n */\nexport interface GetPanopticPoolAddressV3Params {\n /** Public client */\n client: PublicClient\n /** PanopticFactoryV3 address */\n factoryAddress: Address\n /** Uniswap V3 pool address */\n univ3pool: Address\n /** Risk engine address */\n riskEngine: Address\n}\n\n/**\n * Parameters for getPanopticPoolAddress on a V4 factory.\n */\nexport interface GetPanopticPoolAddressV4Params {\n /** Public client */\n client: PublicClient\n /** PanopticFactoryV4 address */\n factoryAddress: Address\n /** V4 pool key */\n poolKey: PoolKey\n /** Risk engine address */\n riskEngine: Address\n}\n\n/** Versioned params for {@link getPanopticPoolAddress}. Use `version` to select V3 or V4. */\nexport type GetPanopticPoolAddressParams =\n | ({ version: 'v3' } & GetPanopticPoolAddressV3Params)\n | ({ version: 'v4' } & GetPanopticPoolAddressV4Params)\n\n/**\n * Get the PanopticPool address for a given pool and risk engine.\n */\nexport async function getPanopticPoolAddress(\n params: GetPanopticPoolAddressParams,\n): Promise<Address> {\n const { client, factoryAddress, riskEngine } = params\n\n if (params.version === 'v3') {\n return client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'getPanopticPool',\n args: [params.univ3pool, riskEngine],\n })\n }\n\n return client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'getPanopticPool',\n args: [\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n ],\n })\n}\n\n// ---------------------------------------------------------------------------\n// minePoolAddress\n// ---------------------------------------------------------------------------\n\n/**\n * Common mining parameters shared between V3 and V4.\n */\ninterface MinePoolAddressCommon {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Deployer address (msg.sender for deployment) */\n deployerAddress: Address\n /** Risk engine address */\n riskEngine: Address\n /** Starting salt (uint96) */\n salt: bigint\n /** Number of mining iterations */\n loops: bigint\n /** Minimum rarity target */\n minTargetRarity: bigint\n}\n\nexport interface MinePoolAddressV3Params extends MinePoolAddressCommon {\n /** Uniswap V3 pool address */\n v3Pool: Address\n}\n\nexport interface MinePoolAddressV4Params extends MinePoolAddressCommon {\n /** V4 pool key */\n poolKey: PoolKey\n}\n\n/** Versioned params for {@link minePoolAddress}. Use `version` to select V3 or V4. */\nexport type MinePoolAddressParams =\n | ({ version: 'v3' } & MinePoolAddressV3Params)\n | ({ version: 'v4' } & MinePoolAddressV4Params)\n\n/**\n * Result of pool address mining.\n */\nexport interface MinePoolAddressResult {\n /** Best salt found */\n bestSalt: bigint\n /** Highest rarity achieved */\n highestRarity: bigint\n}\n\n/**\n * Mine for an optimal pool address salt with high rarity.\n */\nexport async function minePoolAddress(\n params: MinePoolAddressParams,\n): Promise<MinePoolAddressResult> {\n const { client, factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } =\n params\n\n let result: readonly [bigint, bigint]\n\n if (params.version === 'v3') {\n result = await client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'minePoolAddress',\n args: [deployerAddress, params.v3Pool, riskEngine, salt, loops, minTargetRarity],\n })\n } else {\n result = await client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'minePoolAddress',\n args: [\n deployerAddress,\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n salt,\n loops,\n minTargetRarity,\n ],\n })\n }\n\n return { bestSalt: BigInt(result[0]), highestRarity: result[1] }\n}\n\n// ---------------------------------------------------------------------------\n// simulateDeployNewPool\n// ---------------------------------------------------------------------------\n\ninterface SimulateDeployNewPoolCommon {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Account address (deployer) */\n account: Address\n /** Risk engine address */\n riskEngine: Address\n /** Salt (uint96) */\n salt: bigint\n}\n\nexport interface SimulateDeployNewPoolV3Params extends SimulateDeployNewPoolCommon {\n /** Token 0 address */\n token0: Address\n /** Token 1 address */\n token1: Address\n /** Fee tier (uint24) */\n fee: bigint\n}\n\nexport interface SimulateDeployNewPoolV4Params extends SimulateDeployNewPoolCommon {\n /** V4 pool key */\n poolKey: PoolKey\n}\n\nexport type SimulateDeployNewPoolParams =\n | ({ version: 'v3' } & SimulateDeployNewPoolV3Params)\n | ({ version: 'v4' } & SimulateDeployNewPoolV4Params)\n\n/**\n * Simulate a pool deployment to get the predicted pool address.\n *\n * Uses `simulateContract` on `deployNewPool` — the return value is the new pool address\n * without actually executing the transaction.\n */\nexport async function simulateDeployNewPool(params: SimulateDeployNewPoolParams): Promise<Address> {\n const { client, factoryAddress, account, riskEngine, salt } = params\n\n if (params.version === 'v3') {\n const { result } = await client.simulateContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'deployNewPool',\n args: [params.token0, params.token1, Number(params.fee), riskEngine, salt],\n account,\n })\n return result\n }\n\n const { result } = await client.simulateContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'deployNewPool',\n args: [\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n salt,\n ],\n account,\n })\n return result\n}\n\n// ---------------------------------------------------------------------------\n// getPanopticPoolFromPoolId\n// ---------------------------------------------------------------------------\n\n/**\n * Common parameters for {@link getPanopticPoolFromPoolId}.\n */\ninterface GetPanopticPoolFromPoolIdCommon {\n /** Public client */\n client: PublicClient\n /** SFPM address */\n sfpmAddress: Address\n /** PanopticFactory address */\n factoryAddress: Address\n /** Risk engine address */\n riskEngine: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/** Versioned params for {@link getPanopticPoolFromPoolId}. */\nexport type GetPanopticPoolFromPoolIdParams =\n | ({ version: 'v3' } & GetPanopticPoolFromPoolIdCommon)\n | ({ version: 'v4' } & GetPanopticPoolFromPoolIdCommon)\n\n/**\n * Resolve an SFPM poolId to its PanopticPool address.\n *\n * Chains two on-chain lookups:\n * 1. SFPM: poolId → Uniswap pool address (V3) or pool key (V4)\n * 2. Factory: Uniswap pool + riskEngine → PanopticPool address\n */\nexport async function getPanopticPoolFromPoolId(\n params: GetPanopticPoolFromPoolIdParams,\n): Promise<Address> {\n const { client, sfpmAddress, factoryAddress, riskEngine, poolId, version } = params\n\n if (version === 'v3') {\n const univ3pool = await getUniswapV3PoolFromId({ client, sfpmAddress, poolId })\n return getPanopticPoolAddress({\n version: 'v3',\n client,\n factoryAddress,\n univ3pool,\n riskEngine,\n })\n }\n\n const poolKey = await getUniswapV4PoolKeyFromId({ client, sfpmAddress, poolId })\n return getPanopticPoolAddress({\n version: 'v4',\n client,\n factoryAddress,\n poolKey,\n riskEngine,\n })\n}\n\n// ---------------------------------------------------------------------------\n// resolvePanopticPoolFromPoolId (version-agnostic)\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link resolvePanopticPoolFromPoolId}.\n */\nexport interface ResolvePanopticPoolFromPoolIdParams {\n /** Public client */\n client: PublicClient\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n /** Risk engine address */\n riskEngine: Address\n /** V3 SFPM + Factory addresses (omit if V3 is not deployed) */\n v3?: {\n sfpmAddress: Address\n factoryAddress: Address\n }\n /** V4 SFPM + Factory addresses (omit if V4 is not deployed) */\n v4?: {\n sfpmAddress: Address\n factoryAddress: Address\n }\n}\n\n/**\n * Result of {@link resolvePanopticPoolFromPoolId}.\n */\nexport interface ResolvePanopticPoolFromPoolIdResult {\n /** The resolved PanopticPool address */\n panopticPoolAddress: Address\n /** Which version matched */\n version: 'v3' | 'v4'\n}\n\n/**\n * Resolve an SFPM poolId to its PanopticPool address without knowing the version.\n *\n * Tries both V3 and V4 lookups in parallel. The factory returns `address(0)` for\n * non-existent pools, so the non-zero result identifies the correct version.\n *\n * At least one of `v3` or `v4` must be provided.\n *\n * @throws {PanopticValidationError} If no version config is provided or neither resolves.\n */\nexport async function resolvePanopticPoolFromPoolId(\n params: ResolvePanopticPoolFromPoolIdParams,\n): Promise<ResolvePanopticPoolFromPoolIdResult> {\n const { client, poolId, riskEngine, v3, v4 } = params\n\n if (!v3 && !v4) {\n throw new Error('At least one of v3 or v4 must be provided')\n }\n\n const isNotFoundError = (err: unknown): boolean => {\n // Contract reverts (e.g. pool not registered) are \"not found\".\n // RPC / ABI / network errors should propagate.\n if (typeof err === 'object' && err !== null && 'name' in err) {\n const name = (err as { name: string }).name\n return name === 'ContractFunctionExecutionError' || name === 'ContractFunctionRevertedError'\n }\n return false\n }\n\n const results = await Promise.all([\n v3\n ? getPanopticPoolFromPoolId({\n version: 'v3',\n client,\n sfpmAddress: v3.sfpmAddress,\n factoryAddress: v3.factoryAddress,\n riskEngine,\n poolId,\n }).catch((err) => {\n if (isNotFoundError(err)) return zeroAddress\n throw err\n })\n : Promise.resolve(zeroAddress),\n v4\n ? getPanopticPoolFromPoolId({\n version: 'v4',\n client,\n sfpmAddress: v4.sfpmAddress,\n factoryAddress: v4.factoryAddress,\n riskEngine,\n poolId,\n }).catch((err) => {\n if (isNotFoundError(err)) return zeroAddress\n throw err\n })\n : Promise.resolve(zeroAddress),\n ])\n\n const [v3Result, v4Result] = results\n\n if (v3Result !== zeroAddress) {\n return { panopticPoolAddress: v3Result, version: 'v3' }\n }\n if (v4Result !== zeroAddress) {\n return { panopticPoolAddress: v4Result, version: 'v4' }\n }\n\n throw new Error(`No PanopticPool found for poolId ${poolId}`)\n}\n","/**\n * Client-side (off-chain) implementation of minePoolAddress.\n *\n * Replicates the on-chain PanopticFactory mining loop entirely in TypeScript,\n * eliminating RPC round-trips. The result is identical to the on-chain computation.\n *\n * Algorithm:\n * For each candidate salt (uint96):\n * 1. Pack a bytes32 salt from deployer, pool identifier, riskEngine, and iteration salt\n * 2. Predict the CREATE3 deployed address (via proxy)\n * 3. Score by leading hex zeros (\"rarity\")\n * 4. Track the best salt; stop early if minTargetRarity is reached\n *\n * @module v2/reads/minePoolAddressLocal\n */\n\nimport type { Address, Hex } from 'viem'\nimport { encodeAbiParameters, keccak256 } from 'viem'\n\nimport { PanopticValidationError } from '../errors'\nimport type { PoolKey } from '../types'\nimport type {\n MinePoolAddressResult,\n MinePoolAddressV3Params,\n MinePoolAddressV4Params,\n} from './factory'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Mining params for PanopticFactoryV3 — no RPC client needed. */\nexport type MinePoolAddressLocalV3Params = Omit<MinePoolAddressV3Params, 'client'>\n\n/** Mining params for PanopticFactoryV4 — no RPC client needed. */\nexport type MinePoolAddressLocalV4Params = Omit<MinePoolAddressV4Params, 'client'>\n\nexport type MinePoolAddressLocalParams =\n | ({ version: 'v3' } & MinePoolAddressLocalV3Params)\n | ({ version: 'v4' } & MinePoolAddressLocalV4Params)\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * keccak256 of the CREATE3 proxy initcode used by ClonesWithImmutableArgs.\n * Source: packages/panoptic-v2-core/lib/clones-with-immutable-args/src/ClonesWithImmutableArgs.sol\n */\nconst CREATE3_PROXY_BYTECODE_HASH =\n '0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f' as Hex\n\nconst MASK_80 = (1n << 80n) - 1n\nconst MASK_40 = (1n << 40n) - 1n\nconst MASK_96 = (1n << 96n) - 1n\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/** Encode a BigInt as a big-endian fixed-length byte array. */\nfunction bigintToBytes(value: bigint, byteLength: number): Uint8Array {\n const bytes = new Uint8Array(byteLength)\n let v = value\n for (let i = byteLength - 1; i >= 0; i--) {\n bytes[i] = Number(v & 0xffn)\n v >>= 8n\n }\n return bytes\n}\n\n/** Parse a 0x-prefixed address into 20 bytes. */\nfunction addressToBytes(addr: Address): Uint8Array {\n const hex = addr.slice(2).padStart(40, '0')\n const bytes = new Uint8Array(20)\n for (let i = 0; i < 20; i++) {\n bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\n/** Parse a 0x-prefixed 32-byte hex string into bytes. */\nfunction hex32ToBytes(hex: Hex): Uint8Array {\n const h = hex.slice(2).padStart(64, '0')\n const bytes = new Uint8Array(32)\n for (let i = 0; i < 32; i++) {\n bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\n/**\n * Compute the CREATE3 deployed address for a given factory and packed salt.\n *\n * Mirrors `ClonesWithImmutableArgs.addressOfClone3(salt)` (with `address(this)` = factory):\n * proxy = CREATE2(factory, salt, PROXY_BYTECODE_HASH)\n * deployed = CREATE1(proxy, nonce=1)\n *\n * Returns the deployed address as a uint160 BigInt.\n */\nfunction addressOfClone3(factory: Address, salt: bigint): bigint {\n const saltBytes = bigintToBytes(salt, 32)\n\n // CREATE2: keccak256(0xff ++ factory ++ salt ++ proxyBytecodeHash) — 85 bytes total\n const create2Input = new Uint8Array(85)\n create2Input[0] = 0xff\n create2Input.set(addressToBytes(factory), 1) // bytes 1–20\n create2Input.set(saltBytes, 21) // bytes 21–52\n create2Input.set(hex32ToBytes(CREATE3_PROXY_BYTECODE_HASH), 53) // bytes 53–84\n\n const proxyHash = keccak256(create2Input, 'bytes')\n const proxyAddress = proxyHash.slice(12) // rightmost 20 bytes\n\n // CREATE1 nonce=1: keccak256(0xd694 ++ proxy ++ 0x01) — 23 bytes total\n const create1Input = new Uint8Array(23)\n create1Input[0] = 0xd6\n create1Input[1] = 0x94\n create1Input.set(proxyAddress, 2) // bytes 2–21\n create1Input[22] = 0x01\n\n const deployedHash = keccak256(create1Input, 'bytes')\n\n // Convert rightmost 20 bytes to uint160 BigInt\n let addr = 0n\n for (let i = 12; i < 32; i++) {\n addr = (addr << 8n) | BigInt(deployedHash[i])\n }\n return addr\n}\n\n/**\n * Count leading hex-zero characters in a 160-bit address value.\n *\n * Mirrors `PanopticMath.numberOfLeadingHexZeros(addr)`.\n * Returns 40 for the zero address.\n */\nexport function numberOfLeadingHexZeros(addrInt: bigint): number {\n if (addrInt === 0n) return 40\n let x = addrInt\n let r = 0\n if (x >= 0x100000000000000000000000000000000n) {\n x >>= 128n\n r += 32\n }\n if (x >= 0x10000000000000000n) {\n x >>= 64n\n r += 16\n }\n if (x >= 0x100000000n) {\n x >>= 32n\n r += 8\n }\n if (x >= 0x10000n) {\n x >>= 16n\n r += 4\n }\n if (x >= 0x100n) {\n x >>= 8n\n r += 2\n }\n if (x >= 0x10n) {\n r += 1\n }\n return 39 - r\n}\n\n/**\n * Construct the bytes32 CREATE3 salt for PanopticFactoryV3.\n *\n * Mirrors:\n * bytes32(abi.encodePacked(\n * uint80(uint160(deployerAddress) >> 80), // bits [159:80] of deployer → 10 bytes\n * uint40(uint160(v3Pool) >> 120), // bits [159:120] of v3Pool → 5 bytes\n * uint40(uint160(riskEngine) >> 120), // bits [159:120] of riskEngine→ 5 bytes\n * salt // uint96 → 12 bytes\n * ))\n */\nfunction computeSaltPrefixV3(\n deployerAddress: Address,\n v3Pool: Address,\n riskEngine: Address,\n): bigint {\n const deployer80 = (BigInt(deployerAddress) >> 80n) & MASK_80\n const pool40 = (BigInt(v3Pool) >> 120n) & MASK_40\n const risk40 = (BigInt(riskEngine) >> 120n) & MASK_40\n return (deployer80 << 176n) | (pool40 << 136n) | (risk40 << 96n)\n}\n\n/**\n * Compute the Uniswap V4 PoolId for a PoolKey.\n *\n * Mirrors `PoolId.toId(key)` = keccak256 of the ABI-encoded PoolKey struct\n * (5 fields × 32 bytes = 160 bytes).\n */\nexport function computePoolIdV4(poolKey: PoolKey): bigint {\n const fee = Number(poolKey.fee)\n if (!Number.isInteger(fee) || fee < 0 || fee >= 2 ** 24) {\n throw new PanopticValidationError(`fee out of uint24 range: ${fee}`)\n }\n const tickSpacing = Number(poolKey.tickSpacing)\n if (!Number.isInteger(tickSpacing) || tickSpacing < -(2 ** 23) || tickSpacing > 2 ** 23 - 1) {\n throw new PanopticValidationError(`tickSpacing out of int24 range: ${tickSpacing}`)\n }\n const encoded = encodeAbiParameters(\n [\n { type: 'address' },\n { type: 'address' },\n { type: 'uint24' },\n { type: 'int24' },\n { type: 'address' },\n ],\n [\n poolKey.currency0,\n poolKey.currency1,\n Number(poolKey.fee),\n Number(poolKey.tickSpacing),\n poolKey.hooks,\n ],\n )\n return BigInt(keccak256(encoded))\n}\n\n/**\n * Construct the bytes32 CREATE3 salt for PanopticFactoryV4.\n *\n * Mirrors:\n * bytes32(abi.encodePacked(\n * uint80(uint160(deployerAddress) >> 80),\n * uint40(uint256(PoolId.unwrap(key.toId())) >> 120), // bits [159:120] of poolId\n * uint40(uint160(riskEngine) >> 120),\n * salt\n * ))\n */\nfunction computeSaltPrefixV4(\n deployerAddress: Address,\n poolKey: PoolKey,\n riskEngine: Address,\n): bigint {\n const deployer80 = (BigInt(deployerAddress) >> 80n) & MASK_80\n const poolId40 = (computePoolIdV4(poolKey) >> 120n) & MASK_40\n const risk40 = (BigInt(riskEngine) >> 120n) & MASK_40\n return (deployer80 << 176n) | (poolId40 << 136n) | (risk40 << 96n)\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Mine for an optimal Panoptic pool address salt, running entirely off-chain.\n *\n * Equivalent to calling `minePoolAddress` on the factory contract but with zero\n * RPC round-trips. The result is identical to the on-chain computation.\n *\n * Iterates `loops` times starting from `salt`, tracking the highest-rarity address\n * found. Stops early when `minTargetRarity` is reached.\n *\n * @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.\n * @returns The best salt found and its rarity (number of leading hex zeros).\n */\nexport function minePoolAddressLocal(params: MinePoolAddressLocalParams): MinePoolAddressResult {\n const { factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params\n\n if (salt < 0n || loops < 0n || minTargetRarity < 0n) {\n throw new PanopticValidationError('salt, loops, and minTargetRarity must be non-negative')\n }\n if (salt + loops > (1n << 96n) - 1n) {\n throw new PanopticValidationError('salt + loops exceeds uint96 range')\n }\n\n let bestSalt = salt\n let highestRarity = 0n\n const maxSalt = salt + loops\n\n // Precompute the invariant high-bit prefix once outside the loop\n const saltPrefix =\n params.version === 'v3'\n ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine)\n : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine)\n\n for (let currentSalt = salt; currentSalt < maxSalt; currentSalt++) {\n const newSalt = saltPrefix | (currentSalt & MASK_96)\n\n const addrInt = addressOfClone3(factoryAddress, newSalt)\n const rarity = BigInt(numberOfLeadingHexZeros(addrInt))\n\n if (rarity > highestRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n }\n\n if (rarity >= minTargetRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n break\n }\n }\n\n return { bestSalt, highestRarity }\n}\n\n// ---------------------------------------------------------------------------\n// Async variant (yields to the event loop between chunks)\n// ---------------------------------------------------------------------------\n\n/** Number of iterations per chunk before yielding back to the event loop. */\nconst CHUNK_SIZE = 5000n\n\n/**\n * Async version of {@link minePoolAddressLocal} that yields to the event loop\n * between chunks of iterations, preventing the browser UI from freezing.\n *\n * @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.\n * @returns The best salt found and its rarity (number of leading hex zeros).\n */\nexport async function minePoolAddressLocalAsync(\n params: MinePoolAddressLocalParams,\n): Promise<MinePoolAddressResult> {\n const { factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params\n\n let bestSalt = salt\n let highestRarity = 0n\n const maxSalt = salt + loops\n\n const saltPrefix =\n params.version === 'v3'\n ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine)\n : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine)\n\n let currentSalt = salt\n while (currentSalt < maxSalt) {\n const chunkEnd = currentSalt + CHUNK_SIZE < maxSalt ? currentSalt + CHUNK_SIZE : maxSalt\n let done = false\n\n for (; currentSalt < chunkEnd; currentSalt++) {\n const newSalt = saltPrefix | (currentSalt & MASK_96)\n const addrInt = addressOfClone3(factoryAddress, newSalt)\n const rarity = BigInt(numberOfLeadingHexZeros(addrInt))\n\n if (rarity > highestRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n }\n\n if (rarity >= minTargetRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n done = true\n break\n }\n }\n\n if (done) break\n\n // Yield to the event loop so the UI stays responsive\n await new Promise<void>((resolve) => setTimeout(resolve, 0))\n }\n\n return { bestSalt, highestRarity }\n}\n","/**\n * Premia read functions for the Panoptic v2 SDK.\n * @module v2/reads/premia\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta, Position, TokenIdLeg } from '../types'\nimport { decodePosition, decodeTickSpacing } from '../utils/option-encoding-v2'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\n\n/**\n * Premia data for an account.\n */\nexport interface AccountPremia {\n /** Total short premium owed to the account for token 0 */\n shortPremium0: bigint\n /** Total short premium owed to the account for token 1 */\n shortPremium1: bigint\n /** Total long premium owed by the account for token 0 */\n longPremium0: bigint\n /** Total long premium owed by the account for token 1 */\n longPremium1: bigint\n /** Whether pending (unsettled) premium was included */\n includePendingPremium: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getAccountPremia.\n */\nexport interface GetAccountPremiaParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds held by the account */\n tokenIds: bigint[]\n /** Whether to include pending (unsettled) premium (default: true) */\n includePendingPremium?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get premia totals for an account.\n *\n * Returns the total short and long premium across all positions.\n * Short premium is owed TO the account (earned from selling options).\n * Long premium is owed BY the account (paid for buying options).\n *\n * @param params - The parameters\n * @returns Premia totals with block metadata\n *\n * @example\n * ```typescript\n * const premia = await getAccountPremia({\n * client,\n * poolAddress,\n * account,\n * tokenIds: [tokenId1, tokenId2],\n * includePendingPremium: true,\n * })\n *\n * console.log('Short premium earned:', premia.shortPremium0, premia.shortPremium1)\n * console.log('Long premium owed:', premia.longPremium0, premia.longPremium1)\n * ```\n */\nexport async function getAccountPremia(params: GetAccountPremiaParams): Promise<AccountPremia> {\n const {\n client,\n poolAddress,\n account,\n tokenIds,\n includePendingPremium = true,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Handle empty position list\n if (tokenIds.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlockNumber }))\n return {\n shortPremium0: 0n,\n shortPremium1: 0n,\n longPremium0: 0n,\n longPremium1: 0n,\n includePendingPremium,\n _meta,\n }\n }\n\n const [[shortPremiumPacked, longPremiumPacked], _meta] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, includePendingPremium, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Decode LeftRightUnsigned values (right = token0, left = token1)\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n return {\n shortPremium0: shortPremium.right,\n shortPremium1: shortPremium.left,\n longPremium0: longPremium.right,\n longPremium1: longPremium.left,\n includePendingPremium,\n _meta,\n }\n}\n\n/**\n * Position with premia data.\n */\nexport interface PositionWithPremia extends Position {\n // Position already has all fields from the base Position interface\n}\n\n/**\n * Result from getPositionsWithPremia.\n */\nexport interface PositionsWithPremiaResult {\n /** Positions with full data */\n positions: PositionWithPremia[]\n /** Total short premium owed to the account for token 0 */\n shortPremium0: bigint\n /** Total short premium owed to the account for token 1 */\n shortPremium1: bigint\n /** Total long premium owed by the account for token 0 */\n longPremium0: bigint\n /** Total long premium owed by the account for token 1 */\n longPremium1: bigint\n /** Whether pending (unsettled) premium was included */\n includePendingPremium: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPositionsWithPremia.\n */\nexport interface GetPositionsWithPremiaParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds held by the account */\n tokenIds: bigint[]\n /** Whether to include pending (unsettled) premium (default: true) */\n includePendingPremium?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get positions with per-position premia data.\n *\n * Uses multicall to batch individual getFullPositionsData calls\n * for each position, giving us per-position premia in a single RPC request.\n *\n * @param params - The parameters\n * @returns Positions with premia and totals with block metadata\n *\n * @example\n * ```typescript\n * const result = await getPositionsWithPremia({\n * client,\n * poolAddress,\n * account,\n * tokenIds: [tokenId1, tokenId2],\n * })\n *\n * for (const position of result.positions) {\n * console.log('Position:', position.tokenId)\n * console.log('Premia:', position.premiaOwed0, position.premiaOwed1)\n * }\n * console.log('Total short premium:', result.shortPremium0, result.shortPremium1)\n * ```\n */\nexport async function getPositionsWithPremia(\n params: GetPositionsWithPremiaParams,\n): Promise<PositionsWithPremiaResult> {\n const {\n client,\n poolAddress,\n account,\n tokenIds,\n includePendingPremium = true,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Handle empty position list\n if (tokenIds.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlockNumber }))\n return {\n positions: [],\n shortPremium0: 0n,\n shortPremium1: 0n,\n longPremium0: 0n,\n longPremium1: 0n,\n includePendingPremium,\n _meta,\n }\n }\n\n // Build multicall contracts - one getFullPositionsData call per tokenId\n // This gives us per-position premia\n const contracts = tokenIds.map((tokenId) => ({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData' as const,\n args: [account, includePendingPremium, [tokenId]] as const,\n }))\n\n // Execute multicall and get block metadata\n const [multicallResults, _meta] = await Promise.all([\n client.multicall({\n contracts,\n blockNumber: targetBlockNumber,\n allowFailure: true,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Build positions and accumulate totals\n const positions: PositionWithPremia[] = []\n let totalShortPremium0 = 0n\n let totalShortPremium1 = 0n\n let totalLongPremium0 = 0n\n let totalLongPremium1 = 0n\n\n for (let i = 0; i < tokenIds.length; i++) {\n const tokenId = tokenIds[i]\n const result = multicallResults[i]\n\n // Skip failed calls\n if (result.status !== 'success') {\n continue\n }\n\n const [shortPremiumPacked, longPremiumPacked, balances] = result.result\n\n // Decode per-position premia\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n // Accumulate totals\n totalShortPremium0 += shortPremium.right\n totalShortPremium1 += shortPremium.left\n totalLongPremium0 += longPremium.right\n totalLongPremium1 += longPremium.left\n\n // Get balance data (should be single element array)\n const balanceData = balances[0]\n if (balanceData === undefined) {\n continue\n }\n\n // Decode the PositionBalance\n const positionSize = balanceData & ((1n << 128n) - 1n)\n\n // Skip positions with zero size\n if (positionSize === 0n) {\n continue\n }\n\n const poolUtilization0 = (balanceData >> 128n) & 0xffffn\n const poolUtilization1 = (balanceData >> 144n) & 0xffffn\n\n // tickAtMint is int24 at bits 160-183\n let tickAtMint = (balanceData >> 160n) & 0xffffffn\n if (tickAtMint > 0x7fffffn) {\n tickAtMint = tickAtMint - 0x1000000n\n }\n\n const timestampAtMint = (balanceData >> 184n) & 0xffffffffn\n const blockAtMint = (balanceData >> 216n) & ((1n << 39n) - 1n)\n const swapAtMint = balanceData >> 255n === 1n\n\n // Decode the tokenId to get legs\n const decoded = decodePosition(tokenId)\n const tickSpacing = decodeTickSpacing(tokenId)\n\n // Convert decoded legs to TokenIdLeg format\n const legs: TokenIdLeg[] = decoded.legs.map((leg) => {\n const width = leg.width\n const strike = leg.strike\n const tickLower = strike - (width * tickSpacing) / 2n\n const tickUpper = strike + (width * tickSpacing) / 2n\n\n return {\n index: BigInt(leg.index),\n asset: leg.asset,\n optionRatio: leg.optionRatio,\n isLong: leg.isLong === 1n,\n tokenType: leg.tokenType,\n riskPartner: leg.riskPartner,\n strike,\n width,\n tickLower,\n tickUpper,\n }\n })\n\n // Calculate net premia for this position\n // Positive = position has earned premium (short), Negative = position owes premium (long)\n const premiaOwed0 = shortPremium.right - longPremium.right\n const premiaOwed1 = shortPremium.left - longPremium.left\n\n positions.push({\n tokenId,\n positionSize,\n owner: account,\n poolAddress,\n legs,\n poolUtilization0AtMint: poolUtilization0,\n poolUtilization1AtMint: poolUtilization1,\n tickAtMint,\n timestampAtMint,\n blockNumberAtMint: blockAtMint,\n swapAtMint,\n premiaOwed0,\n premiaOwed1,\n assetIndex: legs.length > 0 ? legs[0].asset : 0n,\n _meta,\n })\n }\n\n return {\n positions,\n shortPremium0: totalShortPremium0,\n shortPremium1: totalShortPremium1,\n longPremium0: totalLongPremium0,\n longPremium1: totalLongPremium1,\n includePendingPremium,\n _meta,\n }\n}\n","/**\n * Collateral estimation functions for the Panoptic v2 SDK.\n *\n * These functions require the PanopticQuery contract which provides\n * on-chain calculation capabilities for collateral requirements.\n *\n * @module v2/reads/collateralEstimate\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError } from '../errors'\nimport { sqrtPriceX96ToTick, tickToSqrtPriceX96 } from '../formatters/tick'\nimport { type TokenFlow, simulateWithTokenFlow } from '../simulations/tokenFlow'\nimport type { StorageAdapter } from '../storage'\nimport { getTrackedPositionIds } from '../sync/getTrackedPositionIds'\nimport { addLegToTokenId, countLegs, decodeAllLegs } from '../tokenId/encoding'\nimport type { BlockMeta } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\n\n/**\n * Max int24 (2^23 - 1), used as the per-position `effectiveLiquidityLimit` (the\n * 3rd element of the dispatch tickAndSpreadLimits triplet). Passing this lets the\n * contract clamp to its real on-chain `maxSpread()` ceiling, matching the live\n * trade. Passing 0 instead forces the limit to 0, so any long-leg removal reverts\n * with EffectiveLiquidityAboveThreshold and ITM/size measurements silently\n * collapse (see PanopticPool._mintInSFPMAndUpdateCollateral / _checkLiquiditySpread).\n */\nconst MAX_EFFECTIVE_LIQUIDITY_LIMIT = 8388607\n\n/**\n * Collateral estimate result.\n */\nexport interface CollateralEstimate {\n /** Required collateral for token 0 */\n required0: bigint\n /** Required collateral for token 1 */\n required1: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for estimateCollateralRequired.\n */\nexport interface EstimateCollateralRequiredParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to estimate collateral for */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Optional: Tick to calculate collateral at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Maximum value of a Solidity `uint64`. `PanopticQuery.getRequiredBase` computes\n * the requirement for a synthetic position sized at `type(uint64).max`, so the\n * returned value must be scaled down to the caller's actual `positionSize`.\n */\nconst MAX_UINT64 = 2n ** 64n - 1n\n\n/**\n * `getRequiredBase` returns `type(uint128).max` as an error sentinel (invalid\n * tokenId or reverting `getMargin`). Detect it so we don't scale a garbage value.\n */\nexport const REQUIRED_BASE_ERROR_SENTINEL = 2n ** 128n - 1n\n\n/**\n * Estimate the collateral required to open a position.\n *\n * Note: This function uses PanopticQuery.getRequiredBase for estimation, which\n * computes the requirement at `type(uint64).max` size and 0% utilization. Since\n * the requirement is linear in size, the raw result is scaled by\n * `positionSize / type(uint64).max` to yield the requirement for the requested\n * size. Returns collateral requirement in terms of token0.\n *\n * @param params - The parameters\n * @returns Estimated collateral requirements with block metadata\n */\nexport async function estimateCollateralRequired(\n params: EstimateCollateralRequiredParams,\n): Promise<CollateralEstimate> {\n const { client, poolAddress, tokenId, positionSize, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Get current tick if not provided\n let effectiveTick: bigint\n if (atTick !== undefined) {\n effectiveTick = atTick\n } else {\n const currentTickResult = await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n // Bridge type from panopticPoolV2Abi (number | bigint) to bigint\n effectiveTick = BigInt(currentTickResult)\n }\n\n const [required0, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getRequiredBase',\n args: [poolAddress, tokenId, Number(effectiveTick)],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // getRequiredBase computes the requirement at type(uint64).max size. The\n // requirement is linear in size, so scale down to the requested positionSize.\n // Guard against the error sentinel (type(uint128).max) so we don't scale it.\n const scaled0 =\n required0 >= REQUIRED_BASE_ERROR_SENTINEL ? required0 : (required0 * positionSize) / MAX_UINT64\n\n // PanopticQuery.getRequiredBase returns collateral requirement in terms of token0\n // For token1 requirement, would need additional conversion or separate call\n return {\n required0: scaled0,\n required1: 0n, // Not available from getRequiredBase (token0-denominated only)\n _meta,\n }\n}\n\n/**\n * Max position size result.\n */\nexport interface MaxPositionSize {\n /** Refined maximum position size at current market conditions */\n maxSize: bigint\n /** Maximum position size at 0% utilization (best case / upper bound) */\n maxSizeAtMinUtil: bigint\n /** Maximum position size at 100% utilization (worst case / lower bound) */\n maxSizeAtMaxUtil: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getMaxPositionSize.\n */\nexport interface GetMaxPositionSizeParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to check max size for */\n tokenId: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /**\n * Existing position IDs held by the account.\n * - If provided, uses these directly\n * - If not provided but storage + chainId given, fetches from getTrackedPositionIds()\n * - If neither provided, assumes empty array (new account with no positions)\n */\n existingPositionIds?: bigint[]\n /** Storage adapter for auto-fetching positions (requires chainId) */\n storage?: StorageAdapter\n /** Chain ID (required if using storage) */\n chainId?: bigint\n /** Whether to refine with dispatch simulation (default: true) */\n refine?: boolean\n /** Precision for binary search as percentage (default: 1 = 1%) */\n precisionPct?: number\n /** Whether to swap tokens at mint (affects collateral requirements, default: false) */\n swapAtMint?: boolean\n /**\n * Whether the solvency simulation may count accrued premia as collateral. MUST match the\n * mint (which uses `false`) — passing `true` credits premia the mint won't, so the search\n * returns a size larger than the account can actually mint. Defaults to `false`.\n */\n usePremiaAsCollateral?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get the maximum position size an account can open given their current collateral.\n *\n * Uses PanopticQuery.getMaxPositionSizeBounds to get bounds at 0% and 100% utilization,\n * then refines with dispatch simulations to find the exact max at current conditions.\n *\n * @param params - The parameters\n * @returns Maximum position size with bounds and block metadata\n */\nexport async function getMaxPositionSize(\n params: GetMaxPositionSizeParams,\n): Promise<MaxPositionSize> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n queryAddress,\n existingPositionIds,\n storage,\n chainId,\n refine = true,\n precisionPct = 1,\n swapAtMint = false,\n usePremiaAsCollateral = false,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Get existing position IDs\n let positionIds: bigint[]\n if (existingPositionIds !== undefined) {\n // Use explicitly provided position IDs\n positionIds = existingPositionIds\n } else if (storage && chainId !== undefined) {\n // Fetch from local cache via getTrackedPositionIds\n positionIds = await getTrackedPositionIds({\n chainId,\n poolAddress,\n account,\n storage,\n })\n } else {\n // Assume new account with no existing positions\n positionIds = []\n }\n // Get bounds and block meta in parallel\n const [boundsResult, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getMaxPositionSizeBounds',\n args: [poolAddress, positionIds, account, tokenId],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [maxSizeAtMinUtil, maxSizeAtMaxUtil] = boundsResult\n\n // If bounds are equal or very close, or refinement disabled, return conservative estimate\n const precisionDivisor = BigInt(Math.floor(100 / precisionPct))\n if (\n !refine ||\n maxSizeAtMinUtil === maxSizeAtMaxUtil ||\n maxSizeAtMinUtil - maxSizeAtMaxUtil <= maxSizeAtMaxUtil / precisionDivisor\n ) {\n return {\n maxSize: maxSizeAtMaxUtil,\n maxSizeAtMinUtil,\n maxSizeAtMaxUtil,\n _meta,\n }\n }\n\n // Binary search between widened bounds using dispatch simulation\n // Widen by 2x in each direction to account for swapAtMint price impact\n const maxSize = await binarySearchMaxSize({\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds: positionIds,\n low: maxSizeAtMaxUtil / 2n,\n high: maxSizeAtMinUtil * 2n,\n precisionDivisor,\n swapAtMint,\n usePremiaAsCollateral,\n })\n\n return {\n maxSize,\n maxSizeAtMinUtil,\n maxSizeAtMaxUtil,\n _meta,\n }\n}\n\n/**\n * Parallel search to find max position size using dispatch simulation.\n * Tests 5 points per round (sextiles), narrowing the range by 6x each iteration.\n */\nasync function binarySearchMaxSize(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n low: bigint\n high: bigint\n precisionDivisor: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}): Promise<bigint> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n precisionDivisor,\n swapAtMint,\n usePremiaAsCollateral,\n } = params\n let { low, high } = params\n\n const trySize = (positionSize: bigint) =>\n tryDispatchSimulation({\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n positionSize,\n swapAtMint,\n usePremiaAsCollateral,\n })\n\n while (high - low > 1n && high - low > low / precisionDivisor) {\n const range = high - low\n const p1 = low + range / 6n\n const p2 = low + (range * 2n) / 6n\n const p3 = low + (range * 3n) / 6n\n const p4 = low + (range * 4n) / 6n\n const p5 = low + (range * 5n) / 6n\n\n const [s1, s2, s3, s4, s5] = await Promise.all([\n trySize(p1),\n trySize(p2),\n trySize(p3),\n trySize(p4),\n trySize(p5),\n ])\n\n if (s5) {\n low = p5\n } else if (s4) {\n low = p4\n high = p5\n } else if (s3) {\n low = p3\n high = p4\n } else if (s2) {\n low = p2\n high = p3\n } else if (s1) {\n low = p1\n high = p2\n } else {\n high = p1\n }\n }\n\n return low\n}\n\n/**\n * Try to simulate opening a position with the given size.\n */\nasync function tryDispatchSimulation(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n positionSize: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}): Promise<boolean> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n positionSize,\n swapAtMint,\n usePremiaAsCollateral,\n } = params\n\n try {\n // Build final position list (existing + new position)\n const finalPositionIdList = [...existingPositionIds, tokenId]\n\n // Build tick limits based on swapAtMint flag:\n // - swapAtMint=true: descending order (high, low) triggers SFPM swap\n // - swapAtMint=false: ascending order (low, high) no swap\n //\n // The third element is the per-position `effectiveLiquidityLimit`; see the\n // MAX_EFFECTIVE_LIQUIDITY_LIMIT definition for why 0 must not be used here.\n const tickLimits: readonly [number, number, number] = swapAtMint\n ? [887272, -887272, MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n : [-887272, 887272, MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n\n // Encode dispatch call\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId],\n finalPositionIdList,\n [positionSize],\n [tickLimits],\n usePremiaAsCollateral, // must match the mint (default false) so the max is mintable\n 0n, // builderCode\n ],\n })\n\n // Use PanopticPool.multicall to simulate\n await client.simulateContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'multicall',\n args: [[callData]],\n account,\n })\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Parameters for getRequiredCreditForITM.\n */\nexport interface GetRequiredCreditForITMParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to check */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Existing position IDs held by the account (defaults to empty) */\n existingPositionIds?: bigint[]\n /**\n * Whether the position will be minted with a token swap (Zap). Controls the\n * dispatch tickLimit direction and therefore what the measured flow looks like:\n * - `true` (default): descending tickLimits → SFPM swap → flow consolidated to\n * the single token the mint would swap into.\n * - `false`: ascending tickLimits → no swap → the true two-sided flow (both\n * tokens), matching a cover-at-mint open.\n * Must match the swapAtMint used at mint for the measurement to be meaningful.\n */\n swapAtMint?: boolean\n /** Optional block number for simulation */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Result for getRequiredCreditForITM.\n */\nexport interface RequiredCreditForITM {\n /**\n * Required credit in token0 to neutralize ITM exposure.\n * Positive = credit needed (deposit), negative = loan proceeds (receive).\n */\n creditAmount0: bigint\n /**\n * Required credit in token1 to neutralize ITM exposure.\n * Positive = credit needed (deposit), negative = loan proceeds (receive).\n */\n creditAmount1: bigint\n /** The raw token flow from simulation */\n tokenFlow: TokenFlow\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Get the required credit (or loan) amount for an ITM position.\n *\n * Simulates opening the position with swapAtMint=true (descending tickLimits)\n * to get single-sided token flow. The token flow represents the ITM amount\n * that would need to be neutralized with a credit (or loan if negative).\n *\n * @param params - The parameters\n * @returns Required credit amounts with token flow and block metadata\n * @throws PanopticError - If simulation fails\n *\n * @example\n * ```typescript\n * const result = await getRequiredCreditForITM({\n * client,\n * poolAddress,\n * account,\n * tokenId,\n * positionSize: 1n,\n * })\n *\n * if (result.creditAmount0 > 0n) {\n * console.log('Need credit of', result.creditAmount0, 'token0')\n * } else if (result.creditAmount0 < 0n) {\n * console.log('Position yields loan of', -result.creditAmount0, 'token0')\n * }\n * ```\n */\nexport async function getRequiredCreditForITM(\n params: GetRequiredCreditForITMParams,\n): Promise<RequiredCreditForITM> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n positionSize,\n existingPositionIds = [],\n swapAtMint = true,\n blockNumber,\n } = params\n\n // Same-block guarantee: if the caller pins both a blockNumber and a pre-fetched\n // _meta, they must agree — otherwise the simulation (targetBlockNumber) and the\n // returned metadata would describe different blocks.\n if (\n blockNumber !== undefined &&\n params._meta !== undefined &&\n params._meta.blockNumber !== blockNumber\n ) {\n throw new PanopticError(\n 'getRequiredCreditForITM: blockNumber and _meta.blockNumber disagree; cannot guarantee same-block consistency',\n )\n }\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Build final position list (existing + new position)\n const finalPositionIdList = [...existingPositionIds, tokenId]\n\n // Encode dispatch call. The tickLimit direction encodes swapAtMint:\n // - swapAtMint=true (Zap): descending (MAX_TICK > MIN_TICK) triggers the SFPM swap,\n // consolidating the flow into the single token the mint swaps into.\n // - swapAtMint=false (Cover): ascending (MIN_TICK < MAX_TICK) does no swap, giving the\n // true two-sided flow. This must match the mint's swapAtMint for the measured flow to\n // reflect what actually happens at open.\n // The 3rd element is the per-position effectiveLiquidityLimit: use the max so the contract\n // clamps to its real maxSpread() ceiling (matching the live trade). Passing 0 here collapses\n // ITM measurement for positions with a long-leg removal (see MAX_EFFECTIVE_LIQUIDITY_LIMIT).\n const tickTriplet: readonly [number, number, number] = swapAtMint\n ? [Number(MAX_TICK), Number(MIN_TICK), MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n : [Number(MIN_TICK), Number(MAX_TICK), MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId], // positionIdList: positions being minted\n finalPositionIdList,\n [positionSize],\n [tickTriplet],\n false, // usePremiaAsCollateral\n 0n, // builderCode\n ],\n })\n\n // Simulate with token flow measurement and get block meta in parallel\n const [result, _meta] = await Promise.all([\n simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n if (!result.success || !result.tokenFlow) {\n throw new PanopticError(result.error ?? 'Token flow simulation failed')\n }\n\n // The token flow deltas represent the ITM amount:\n // - Negative delta = user deposits (credit needed)\n // - Positive delta = user receives (loan proceeds)\n // We invert the sign so positive = credit needed, negative = loan\n return {\n creditAmount0: -result.tokenFlow.delta0,\n creditAmount1: -result.tokenFlow.delta1,\n tokenFlow: result.tokenFlow,\n _meta,\n }\n}\n\n/**\n * Parameters for getItmAmounts.\n */\nexport interface GetItmAmountsParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticQuery address (holds the getItmAmounts view) */\n queryAddress: Address\n /** PanopticPool address the position would be minted on */\n poolAddress: Address\n /** The option position (may already include width=0 neutralizing legs) */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Optional block number */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getItmAmounts: the net in-the-money amounts a mint of `tokenId` would\n * accumulate in the SFPM before the mint-time netting swap.\n */\nexport interface ItmAmounts {\n /** Net ITM amount of token0 (SFPM sign convention). */\n itm0: bigint\n /** Net ITM amount of token1. */\n itm1: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Read the net `itmAmounts` a mint of `tokenId` would produce, via\n * `PanopticQuery.getItmAmounts`. This is the swap-independent, per-leg-linear\n * projection that drives the SFPM's mint-time netting swap: the swap only fires\n * when `itmAmounts != 0`. Sizing width=0 legs so the combined tokenId returns\n * (~0, ~0) here makes the mint swap dust — regardless of Zap vs cover.\n *\n * @param params - The parameters\n * @returns The net itm0/itm1 with block metadata\n */\nexport async function getItmAmounts(params: GetItmAmountsParams): Promise<ItmAmounts> {\n const { client, queryAddress, poolAddress, tokenId, positionSize, blockNumber } = params\n\n // Same-block guarantee (see getRequiredCreditForITM): a pinned blockNumber and a\n // pre-fetched _meta must describe the same block.\n if (\n blockNumber !== undefined &&\n params._meta !== undefined &&\n params._meta.blockNumber !== blockNumber\n ) {\n throw new PanopticError(\n 'getItmAmounts: blockNumber and _meta.blockNumber disagree; cannot guarantee same-block consistency',\n )\n }\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getItmAmounts',\n args: [poolAddress, tokenId, positionSize],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [itm0, itm1] = result as readonly [bigint, bigint]\n return { itm0, itm1, _meta }\n}\n\n/**\n * Dust threshold (token1 value units) below which an itm amount is treated as\n * zero — negligible token flow not worth a neutralizing leg. token0 amounts are\n * converted to token1 value at the current tick before comparison so a tiny\n * high-decimal amount can't masquerade as real flow.\n */\nconst FLOW_NEUTRAL_DUST_THRESHOLD = 1000n\n\nconst Q192 = 1n << 192n\nconst POOL_ID_MASK = (1n << 64n) - 1n\n\n/**\n * Floor integer square root for bigints (Newton's method). Exact for all\n * non-negative inputs — no float precision loss for values above 2^53.\n */\nfunction isqrt(value: bigint): bigint {\n if (value < 0n) throw new PanopticError('isqrt of negative number')\n if (value < 2n) return value\n let x = value\n let y = (x + 1n) >> 1n\n while (y < x) {\n x = y\n y = (x + value / x) >> 1n\n }\n return x\n}\n\n/**\n * Solve a single width=0 neutralizing leg sized to offset a token's signed itm.\n *\n * The leg moves `tokenIndex`'s token (`tokenType = tokenIndex`) and is denominated\n * in the opposite asset (`asset = 1 - tokenIndex`) so `asset ≠ tokenType` and the\n * notional scales continuously by strike: `notional ≈ positionSize · 1.0001^signed`.\n * `signedAmount` is the itm to cancel (the leg's itm contribution is `-signedAmount`):\n * positive itm ⇒ a short LOAN leg (isLong=0), negative itm ⇒ a long CREDIT leg (isLong=1).\n *\n * Width=0 legs never mint Uniswap liquidity (see SFPM `_createPositionInAMM`), so their\n * strike is NOT grid-constrained — we use full 1-tick granularity for the tightest sizing.\n * The closed form `positionSize·1.0001^strike` matches the contract's width-2-chunk\n * `getAmountsMoved` to within ~dust, so no correction loop is needed.\n * Throws `PanopticError` if the required strike leaves the valid (exclusive) tick range.\n */\nfunction buildNeutralLeg(\n tokenIndex: 0n | 1n,\n signedAmount: bigint,\n positionSize: bigint,\n): NeutralLeg {\n const absAmount = signedAmount < 0n ? -signedAmount : signedAmount\n const legAsset = tokenIndex === 0n ? 1n : 0n\n const legIsLong = signedAmount < 0n\n\n // 1.0001^signedStrike = absAmount / positionSize\n // sqrtKrawX96 = sqrt(absAmount / positionSize) · 2^96 = isqrt(absAmount · 2^192 / positionSize)\n const sqrtKrawX96 = isqrt((absAmount * Q192) / positionSize)\n\n let signedTick: bigint\n try {\n signedTick = sqrtPriceX96ToTick(sqrtKrawX96)\n } catch {\n throw new PanopticError(\n 'Cannot create flow-neutral position: neutralizing strike out of bounds',\n )\n }\n\n // TokenId.validate() rejects strike == MIN_TICK/MAX_TICK, so keep strictly inside.\n if (signedTick <= MIN_TICK || signedTick >= MAX_TICK) {\n throw new PanopticError(\n 'Cannot create flow-neutral position: neutralizing strike out of bounds',\n )\n }\n\n // signedStrike = (asset === 0 ? strike : -strike) — invert to recover the encoded\n // strike (mirrors getLegValueWidth0's convention).\n const strike = legAsset === 0n ? signedTick : -signedTick\n\n return {\n strike,\n asset: legAsset,\n tokenType: tokenIndex,\n isCredit: legIsLong,\n }\n}\n\n/**\n * Assemble a tokenId with the neutralizing legs (self-partnered, width=0) placed either\n * BEFORE or AFTER the base legs.\n *\n * The leg at index 0 sets the position's swap frame (the token the Zap sources) and the\n * canonical `positionSize` denomination, so placement is asset-directed:\n * - `prepend=false` (default, e.g. PUTs): base legs keep their indices (option leg stays\n * at index 0); neutral legs are appended at `baseLegCount..`.\n * - `prepend=true` (e.g. CALLs): neutral legs occupy indices `0..k-1` and the base legs\n * shift by `k` (riskPartner remapped: self-partners follow their new index, cross\n * partners +k). This puts the credit leg first so the mint swap is asset-token\n * friendly for a call.\n */\nfunction assembleNeutralTokenId(\n poolId: bigint,\n baseTokenId: bigint,\n neutralLegs: NeutralLeg[],\n prepend: boolean,\n): bigint {\n let out = poolId\n const baseLegs = decodeAllLegs(baseTokenId)\n const k = BigInt(neutralLegs.length)\n const shift = prepend ? k : 0n\n\n if (prepend) {\n neutralLegs.forEach((leg, i) => {\n const index = BigInt(i)\n out = addLegToTokenId(out, {\n index,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: 1n,\n isLong: leg.isCredit ? 1n : 0n,\n riskPartner: index,\n strike: leg.strike,\n width: 0n,\n })\n })\n }\n\n for (const leg of baseLegs) {\n const newIndex = leg.index + shift\n const newRiskPartner = leg.riskPartner === leg.index ? newIndex : leg.riskPartner + shift\n out = addLegToTokenId(out, {\n index: newIndex,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: leg.optionRatio,\n isLong: leg.isLong ? 1n : 0n,\n riskPartner: newRiskPartner,\n strike: leg.strike,\n width: leg.width,\n })\n }\n\n if (!prepend) {\n const base = BigInt(baseLegs.length)\n neutralLegs.forEach((leg, i) => {\n const index = base + BigInt(i)\n out = addLegToTokenId(out, {\n index,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: 1n,\n isLong: leg.isCredit ? 1n : 0n,\n riskPartner: index,\n strike: leg.strike,\n width: 0n,\n })\n })\n }\n\n return out\n}\n\n/**\n * Parameters for createFlowNeutralTokenId.\n */\nexport interface CreateFlowNeutralTokenIdParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address the position would be minted on */\n poolAddress: Address\n /** Account address (whose collateral flow the neutralization targets) */\n account: Address\n /** The base tokenId (without neutralizing legs) */\n tokenId: bigint\n /** Position size (number of contracts) — unchanged by this function */\n positionSize: bigint\n /**\n * PanopticQuery address. When provided, the position's true intrinsic (`getItmAmounts`)\n * gates neutralization: an OTM position (no ITM) gets NO leg, even though its realized\n * flow is non-zero from the open commission. Without it, OTM detection falls back to the\n * commission-inclusive realized flow, which spuriously neutralizes the fee.\n */\n queryAddress?: Address\n /** Existing position IDs held by the account (defaults to empty) */\n existingPositionIds?: bigint[]\n /**\n * Whether the position will be minted with a token swap (Zap). Must match the\n * mint: the neutralization targets the NET token flow under this swap mode, so a\n * mismatch would neutralize the wrong quantity. Defaults to `true`.\n */\n swapAtMint?: boolean\n /**\n * Size at which to MEASURE the base flow that sizes the neutralizing leg(s). The leg\n * strikes are position-size-independent (the flow is linear in size), so measuring at a\n * small affordable reference and reusing the result for `positionSize` yields the same\n * legs. Set this below `positionSize` to avoid the un-neutralized base dispatch reverting\n * with NotEnoughTokens at large sizes under Cover (the gross ITM would exceed the\n * account's balance even though the neutralized mint nets ~0). Defaults to `positionSize`;\n * clamped to `positionSize` if larger.\n */\n referenceSize?: bigint\n /** Optional block number (pins base + verify measurements to one block) */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * A single width=0 neutralizing leg emitted by {@link createFlowNeutralTokenId}.\n */\nexport interface NeutralLeg {\n /** The encoded strike of the leg (sign follows the `asset === 0 ? +t : -t` convention). */\n strike: bigint\n /** Asset (0n or 1n) of the leg. Always `1n - tokenType` (asset ≠ tokenType, so it is strike-tunable). */\n asset: bigint\n /** Token type (0n or 1n) — the token this leg neutralizes (its itm slot). */\n tokenType: bigint\n /** true = credit leg (isLong, offsets negative itm), false = loan leg (short, offsets positive itm). */\n isCredit: boolean\n}\n\n/**\n * Result of createFlowNeutralTokenId.\n */\nexport interface FlowNeutralTokenId {\n /**\n * New tokenId with the neutralizing legs appended after the base legs (base legs keep\n * their original indices, so the option leg stays at index 0). Equals the original\n * tokenId when OTM (`neutralLegs` empty).\n */\n tokenId: bigint\n /**\n * Position size to use when opening this tokenId. Always equal to the input\n * `positionSize` — neutralizing legs are sized via their strike, not by\n * rescaling the position.\n */\n positionSize: bigint\n /**\n * The neutralizing legs added, appended after the base legs. 0 entries = OTM/no leg;\n * 1 = the single dominant-token neutralizing leg (single-leg neutralization).\n */\n neutralLegs: NeutralLeg[]\n /** The BASE position's net-flow measurement (what the legs offset). */\n originalCredit: RequiredCreditForITM\n /**\n * The COMBINED (neutralized) position's actual token flow under the mint's swap,\n * from a verify re-measurement. Use this for the Account-Balances display and to\n * gate the mint — its `delta0/delta1` are the residual net transfer (≈ dust).\n */\n neutralizedTokenFlow: TokenFlow\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Create a flow-neutral tokenId by adding width=0 credit/loan leg(s) that zero the\n * position's NET token transfer at mint — the amount the user would otherwise send/receive\n * (and be surprised by at burn).\n *\n * Each leg is sized against the **realized net flow**, measured by\n * {@link getRequiredCreditForITM} under the mint's own `swapAtMint`. Verified on-chain: a\n * width=0 leg's marginal effect on its token's flow is LINEAR and 1:1 with its notional\n * (`positionSize · 1.0001^strike`, matching the contract's `getAmountsMoved`). So sizing the\n * notional to `|net flow|` and solving the strike directly drives the residual to ~dust in\n * ONE shot — no fixed-point loop. (Example: flow 122.08 USDC → strike −228275 → residual\n * −0.032 USDC.)\n *\n * How many legs, keyed on swap mode:\n * - **Zap** (`swapAtMint=true`): the mint swap consolidates the flow into ONE token and a\n * width=0 leg can only move the asset axis afterwards, so we add a single leg on the\n * dominant token; the smaller side is a swap artifact left as dust.\n * - **Cover** (`swapAtMint=false`): no swap, so the flow is genuinely two-sided and each\n * token's flow is independent — we add one leg PER token above dust (up to 2), each\n * sized 1:1 to its own side. This neutralizes both sides of e.g. a two-leg straddle.\n * Each width=0 leg has `asset ≠ tokenType` (strike-tunable):\n * - token0 flow ← width=0 call leg (tokenType0, asset1)\n * - token1 flow ← width=0 put leg (tokenType1, asset0)\n * `creditAmount = −delta`: a positive amount (user would deposit) → a short LOAN leg;\n * negative (user would receive) → a long CREDIT leg. `neutralizedTokenFlow` is a single\n * verify measurement of the combined position under the ACTUAL mint swap mode.\n *\n * Neutral legs (self-partnered, width=0) are placed so index 0 carries the correct swap\n * frame: for a single-leg CALL (option `tokenType === asset`) they are PREPENDED so the\n * credit leg leads and the mint swap is asset-token friendly; for a PUT (and any multi-leg\n * base) they are APPENDED so the option leg stays at index 0. `positionSize` is never\n * modified.\n *\n * @param params - The parameters\n * @returns The flow-neutral tokenId, the neutralizing legs, the base net-flow\n * measurement, and the combined position's residual flow. `neutralLegs` is empty\n * when the position is OTM (input tokenId returned unchanged).\n * @throws PanopticError if positionSize <= 0, base legs + 1 > 4, the current tick\n * is unavailable, or a neutralizing strike falls outside the valid tick range.\n */\nexport async function createFlowNeutralTokenId(\n params: CreateFlowNeutralTokenIdParams,\n): Promise<FlowNeutralTokenId> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n positionSize,\n existingPositionIds,\n swapAtMint = true,\n referenceSize,\n queryAddress,\n blockNumber,\n } = params\n\n if (positionSize <= 0n) {\n throw new PanopticError('positionSize must be positive to create flow-neutral position')\n }\n\n // Measure the base flow at a (possibly smaller) reference size to keep the un-neutralized\n // dispatch affordable; strikes are size-independent so the legs are identical. Verify runs\n // on the neutralized position at the full positionSize (which nets ~0, so it's affordable).\n const measureSize =\n referenceSize !== undefined && referenceSize > 0n && referenceSize < positionSize\n ? referenceSize\n : positionSize\n\n const legCount = countLegs(tokenId)\n if (legCount >= 4n) {\n throw new PanopticError('Cannot append neutralizing leg: tokenId already has 4 legs')\n }\n\n const poolId = tokenId & POOL_ID_MASK\n\n // Leg-0 placement of the neutral leg is asset-directed (it sets the mint's swap frame /\n // positionSize denomination). For a single-leg CALL (option leg's tokenType === asset)\n // the credit leg must lead so the swap sources the asset token; for a PUT the option leg\n // stays at index 0 and the neutral leg is appended. Multi-leg bases always append (their\n // neutralization is handled in a separate commit).\n const baseLegs = decodeAllLegs(tokenId)\n const prependNeutral = baseLegs.length === 1 && baseLegs[0].tokenType === baseLegs[0].asset\n\n // Size the neutral leg against the REALIZED (post-swap) net flow, measured by dispatch\n // under the mint's own `swapAtMint`. Empirically (verified on-chain against a live pool)\n // the leg's marginal effect on this flow is LINEAR and 1:1 with its notional: a width=0\n // leg of notional N (positionSize·1.0001^strike) shifts the measured net flow by exactly\n // N in that token. So sizing notional = |base net flow| and computing the strike directly\n // drives the residual to ~dust in ONE shot — no fixed-point loop.\n // creditAmount = −delta: positive = user deposits, negative = user receives.\n const credit = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId,\n positionSize: measureSize,\n existingPositionIds,\n swapAtMint,\n blockNumber,\n _meta: params._meta,\n })\n\n const tickBefore = credit.tokenFlow.tickBefore\n if (tickBefore === null) {\n throw new PanopticError('Cannot create flow-neutral position: current tick unavailable')\n }\n // Value-aware compare: convert a token0 amount into token1 at the current price\n // (P = 1.0001^tick = sqrtP^2 / 2^192) so token0/token1 flows compare in one unit.\n const sqrtPX96 = tickToSqrtPriceX96(tickBefore)\n const valueAbs = (index: 0n | 1n, amount: bigint): bigint => {\n const abs = amount < 0n ? -amount : amount\n return index === 0n ? (abs * sqrtPX96 * sqrtPX96) / Q192 : abs\n }\n const flowFor = (index: 0n | 1n): bigint =>\n index === 0n ? credit.creditAmount0 : credit.creditAmount1\n\n // OTM gate on true INTRINSIC (getItmAmounts), not the realized flow. The realized\n // getAssetsOf flow includes the open commission, so an OTM position shows non-zero flow\n // (a fee, not ITM) — neutralizing it builds a spurious leg and moves tokens the mint\n // wouldn't. `getItmAmounts` is 0 for an OTM position, so this correctly skips it. Falls\n // back to the realized-flow dust check when no queryAddress is supplied.\n if (queryAddress !== undefined) {\n const itm = await getItmAmounts({\n client,\n queryAddress,\n poolAddress,\n tokenId,\n positionSize: measureSize,\n blockNumber: blockNumber ?? credit._meta.blockNumber,\n _meta: credit._meta,\n })\n if (\n valueAbs(0n, itm.itm0) <= FLOW_NEUTRAL_DUST_THRESHOLD &&\n valueAbs(1n, itm.itm1) <= FLOW_NEUTRAL_DUST_THRESHOLD\n ) {\n return {\n tokenId,\n positionSize,\n neutralLegs: [],\n originalCredit: credit,\n neutralizedTokenFlow: credit.tokenFlow,\n _meta: credit._meta,\n }\n }\n }\n\n // OTM — no net flow to neutralize (both sides negligible). This guard only avoids\n // building a leg with an out-of-bounds (log of ~0) strike; it is NOT a convergence\n // threshold.\n if (\n valueAbs(0n, credit.creditAmount0) <= FLOW_NEUTRAL_DUST_THRESHOLD &&\n valueAbs(1n, credit.creditAmount1) <= FLOW_NEUTRAL_DUST_THRESHOLD\n ) {\n return {\n tokenId,\n positionSize,\n neutralLegs: [],\n originalCredit: credit,\n neutralizedTokenFlow: credit.tokenFlow,\n _meta: credit._meta,\n }\n }\n\n // Which token(s) get a neutralizing leg:\n // - Zap (swapAtMint=true): the mint swap consolidates the flow to ONE token, and a\n // width=0 leg can only move the asset axis afterwards, so we neutralize just the\n // SINGLE dominant token; the smaller side is a swap artifact left as dust.\n // - Cover (swapAtMint=false): there is NO swap, so the flow is genuinely two-sided and\n // each token's flow is independent — neutralize EACH side above dust (up to 2 legs),\n // every leg sized 1:1 to its own token's net flow.\n const indices: (0n | 1n)[] = swapAtMint\n ? [valueAbs(0n, credit.creditAmount0) >= valueAbs(1n, credit.creditAmount1) ? 0n : 1n]\n : ([0n, 1n] as const).filter((i) => valueAbs(i, flowFor(i)) > FLOW_NEUTRAL_DUST_THRESHOLD)\n\n if (legCount + BigInt(indices.length) > 4n) {\n throw new PanopticError(\n `Cannot add ${indices.length} neutralizing leg(s): tokenId would exceed 4 legs`,\n )\n }\n\n // Legs sized from the flow measured at `measureSize`; strikes are size-independent so\n // they hold at the full positionSize.\n const neutralLegs = indices.map((i) => buildNeutralLeg(i, flowFor(i), measureSize))\n const combined = assembleNeutralTokenId(poolId, tokenId, neutralLegs, prependNeutral)\n\n // Verify/display: measure the COMBINED (neutralized) position's residual flow under the\n // ACTUAL mint swap mode at the FULL positionSize so the Account-Balances display and mint\n // gating reflect what the user will experience. The neutralized position nets ~0, so this\n // is affordable even when the un-neutralized base at full size would not be. If it still\n // reverts (edge: sits exactly at the solvency limit), fall back to the reference-size\n // measurement so we return a valid tokenId rather than throwing.\n const pinnedBlock = blockNumber ?? credit._meta.blockNumber\n let residual: RequiredCreditForITM\n try {\n residual = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId: combined,\n positionSize,\n existingPositionIds,\n swapAtMint,\n blockNumber: pinnedBlock,\n _meta: credit._meta,\n })\n } catch {\n residual = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId: combined,\n positionSize: measureSize,\n existingPositionIds,\n swapAtMint,\n blockNumber: pinnedBlock,\n _meta: credit._meta,\n })\n }\n\n return {\n tokenId: combined,\n positionSize,\n neutralLegs,\n originalCredit: credit,\n neutralizedTokenFlow: residual.tokenFlow,\n _meta: credit._meta,\n }\n}\n\n/**\n * Parameters for getMaxWithdrawable.\n */\nexport interface GetMaxWithdrawableParams {\n /** viem PublicClient */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Position IDs held by the account (required for solvency-checked withdraw) */\n positionIdList: bigint[]\n /** Upper bound for the binary search (e.g. user's total assets in this tracker) */\n totalAssets: bigint\n /** Whether to use premia as collateral (default: false) */\n usePremiaAsCollateral?: boolean\n /** Precision for binary search as percentage (default: 1 = 1%) */\n precisionPct?: number\n}\n\n/**\n * Find the maximum withdrawable amount from a CollateralTracker using binary search.\n *\n * When a user has open positions, the standard `maxWithdraw()` returns 0 because\n * the basic ERC4626 withdraw doesn't check solvency. The overloaded\n * `withdraw(assets, receiver, owner, positionIdList, usePremiaAsCollateral)` does\n * check solvency, so we binary search for the largest amount that doesn't revert.\n *\n * @param params - The parameters\n * @returns Maximum withdrawable amount in underlying asset units\n */\nexport async function getMaxWithdrawable(\n params: GetMaxWithdrawableParams,\n): Promise<{ maxWithdrawable: bigint; _meta: BlockMeta }> {\n const {\n client,\n collateralTrackerAddress,\n account,\n positionIdList,\n totalAssets,\n usePremiaAsCollateral = false,\n precisionPct = 1,\n } = params\n\n const _meta = await getBlockMeta({ client })\n\n if (totalAssets <= 0n || positionIdList.length === 0) {\n // No positions: use the standard maxWithdraw\n const maxWithdraw = await client.readContract({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxWithdraw',\n args: [account],\n })\n return { maxWithdrawable: maxWithdraw, _meta }\n }\n\n const precisionDivisor = BigInt(Math.floor(100 / precisionPct))\n let low = 0n\n let high = totalAssets\n\n while (high - low > 1n && high - low > low / precisionDivisor) {\n const mid = low + (high - low) / 2n\n\n const success = await tryWithdrawSimulation({\n client,\n collateralTrackerAddress,\n account,\n assets: mid,\n positionIdList,\n usePremiaAsCollateral,\n })\n\n if (success) {\n low = mid\n } else {\n high = mid\n }\n }\n\n return { maxWithdrawable: low, _meta }\n}\n\n/**\n * Parameters for getMaxRedeem.\n */\nexport interface GetMaxRedeemParams {\n /** viem PublicClient */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Read the maximum number of shares an account can redeem from a CollateralTracker.\n *\n * This is the ERC4626 `maxRedeem(owner)`, i.e. `min(availableShares, balanceOf(owner))`,\n * and returns 0 when the account has open positions (legs). Redeeming exactly this many\n * shares burns the account's full (available) share balance, so a MAX withdraw leaves no\n * rounding dust — unlike an assets-based `withdraw`, which round-trips shares↔assets.\n *\n * @param params - The parameters\n * @returns Maximum redeemable shares with block metadata\n */\nexport async function getMaxRedeem(\n params: GetMaxRedeemParams,\n): Promise<{ maxRedeem: bigint; _meta: BlockMeta }> {\n const { client, collateralTrackerAddress, account, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [maxRedeem, _meta] = await Promise.all([\n client.readContract({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxRedeem',\n args: [account],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { maxRedeem, _meta }\n}\n\n/**\n * Try to simulate a solvency-checked withdraw with the given amount.\n */\nasync function tryWithdrawSimulation(params: {\n client: PublicClient\n collateralTrackerAddress: Address\n account: Address\n assets: bigint\n positionIdList: bigint[]\n usePremiaAsCollateral: boolean\n}): Promise<boolean> {\n const {\n client,\n collateralTrackerAddress,\n account,\n assets,\n positionIdList,\n usePremiaAsCollateral,\n } = params\n\n try {\n await client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'withdraw',\n args: [assets, account, account, positionIdList, usePremiaAsCollateral],\n account,\n })\n return true\n } catch {\n return false\n }\n}\n","/**\n * ERC4626 vault preview functions for the Panoptic v2 SDK.\n *\n * The CollateralTracker contract implements ERC4626, providing standard\n * vault functionality for depositing/withdrawing collateral.\n *\n * @module v2/reads/erc4626\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Parameters for ERC4626 preview functions.\n */\nexport interface ERC4626PreviewParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Which token's collateral tracker to query (0 or 1) */\n tokenIndex: 0 | 1\n /** Amount to preview */\n amount: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched collateral tracker address */\n collateralTrackerAddress?: Address\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * ERC4626 preview result.\n */\nexport interface ERC4626PreviewResult {\n /** The resulting amount (shares or assets depending on function) */\n result: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Helper to get collateral tracker address.\n */\nasync function getCollateralTrackerAddress(\n client: PublicClient,\n poolAddress: Address,\n tokenIndex: 0 | 1,\n providedAddress?: Address,\n): Promise<Address> {\n if (providedAddress) return providedAddress\n\n return client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: tokenIndex === 0 ? 'collateralToken0' : 'collateralToken1',\n })\n}\n\n/**\n * Preview the amount of shares that would be minted for a deposit.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewDeposit(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewDeposit',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of assets that would be returned for a withdrawal.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewWithdraw(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewWithdraw',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of assets required for a mint.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewMint(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewMint',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of shares that would be burned for a redeem.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewRedeem(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewRedeem',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Convert an amount of assets to shares.\n *\n * @param params - The parameters\n * @returns Conversion result with block metadata\n */\nexport async function convertToShares(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'convertToShares',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Convert an amount of shares to assets.\n *\n * @param params - The parameters\n * @returns Conversion result with block metadata\n */\nexport async function convertToAssets(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'convertToAssets',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n","/**\n * PanopticGuardian read functions for the Panoptic v2 SDK.\n *\n * The Guardian can lock a pool into close-only mode. Unlocking is a two-step\n * timelocked flow: `requestUnlock(pool)` schedules an unlock ETA, and after the\n * ETA matures `executeUnlock(pool)` clears the lock. This module reads the\n * pending-unlock state so the UI can surface a countdown while a pool is locked.\n *\n * @module v2/reads/guardian\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticGuardianAbi, panopticPoolV2Abi, riskEngineAbi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Parameters for getGuardianUnlockState.\n */\nexport interface GetGuardianUnlockStateParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Optional RiskEngine address (skips the pool.riskEngine() read) */\n riskEngineAddress?: Address\n /** Optional PanopticGuardian address (skips the riskEngine.GUARDIAN() read) */\n guardianAddress?: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Guardian pool-unlock state.\n */\nexport interface GuardianUnlockState {\n /** Resolved PanopticGuardian contract address */\n guardianAddress: Address\n /** Unlock ETA as a Unix timestamp (seconds); 0n when no unlock is pending */\n unlockEta: bigint\n /** True when an unlock has been requested but not yet executed */\n hasPendingUnlock: boolean\n /** True when the pending unlock's timelock has elapsed and it can be executed */\n isReady: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Read the Guardian pending-unlock state for a pool.\n *\n * Resolves the Guardian address from the pool's RiskEngine when not provided,\n * then reads `unlockEta` and `isPoolUnlockReady` from the PanopticGuardian in a\n * single multicall pinned to the same block.\n *\n * @param params - The parameters\n * @returns Guardian unlock state with block metadata\n */\nexport async function getGuardianUnlockState(\n params: GetGuardianUnlockStateParams,\n): Promise<GuardianUnlockState> {\n const { client, poolAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Only reuse caller-supplied metadata when it matches the block we read at,\n // otherwise data and metadata would come from different blocks.\n const reusableMeta =\n params._meta && params._meta.blockNumber === targetBlockNumber ? params._meta : undefined\n\n // Resolve the RiskEngine (immutable) unless caller supplied it.\n const riskEngineAddress =\n params.riskEngineAddress ??\n (await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'riskEngine',\n blockNumber: targetBlockNumber,\n }))\n\n // Resolve the Guardian (immutable) unless caller supplied it.\n const guardianAddress =\n params.guardianAddress ??\n (await client.readContract({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n functionName: 'GUARDIAN',\n blockNumber: targetBlockNumber,\n }))\n\n const [results, _meta] = await Promise.all([\n client.multicall({\n contracts: [\n {\n address: guardianAddress,\n abi: panopticGuardianAbi,\n functionName: 'unlockEta',\n args: [poolAddress],\n },\n {\n address: guardianAddress,\n abi: panopticGuardianAbi,\n functionName: 'isPoolUnlockReady',\n args: [poolAddress],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n }),\n reusableMeta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [unlockEta, isReady] = results\n\n return {\n guardianAddress,\n unlockEta,\n hasPendingUnlock: unlockEta > 0n,\n isReady,\n _meta,\n }\n}\n","/**\n * Safe mode check functions for the Panoptic v2 SDK.\n *\n * Safe mode is a protective mechanism that activates when pool conditions\n * become dangerous (e.g., extreme price movements or liquidity issues).\n *\n * @module v2/reads/safeMode\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta, SafeModeState as OracleSafeModeState } from '../types'\n\n/**\n * Safe mode status values.\n */\nexport const SafeModeStatus = {\n /** Pool is operating normally */\n NORMAL: 0n,\n /** No new leveraged positions allowed */\n NO_LEVERAGE: 1n,\n /** No swaps allowed */\n NO_SWAP: 2n,\n /** Close-only mode */\n CLOSE_ONLY: 3n,\n} as const\n\nexport type SafeModeStatusValue = (typeof SafeModeStatus)[keyof typeof SafeModeStatus]\n\n/**\n * Safe mode state for bot preflight and operation guards.\n */\nexport type SafeModeState = OracleSafeModeState\n\n/**\n * Parameters for getSafeMode.\n */\nexport interface GetSafeModeParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get the current safe mode status of a pool.\n *\n * Safe mode is activated when:\n * - Pool liquidity drops below safe thresholds\n * - Price volatility exceeds safe limits\n * - Administrative pause is triggered\n *\n * @param params - The parameters\n * @returns Safe mode state with block metadata\n */\nexport async function getSafeMode(params: GetSafeModeParams): Promise<SafeModeState> {\n const { client, poolAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [safeModeRaw, _meta] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'isSafeMode',\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // isSafeMode returns uint8:\n // 0 = normal, 1 = no leverage, 2 = no swap, 3 = close only\n const status = BigInt(safeModeRaw) as SafeModeStatusValue\n\n switch (status) {\n case SafeModeStatus.NO_LEVERAGE:\n return {\n mode: 'restricted',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: true,\n reason: 'All positions require 100% collateral',\n _meta,\n }\n case SafeModeStatus.NO_SWAP:\n return {\n mode: 'restricted',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: false,\n reason: 'Swaps are disabled',\n _meta,\n }\n case SafeModeStatus.CLOSE_ONLY:\n return {\n mode: 'emergency',\n canMint: false,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: false,\n reason: 'Pool is in close-only mode',\n _meta,\n }\n default:\n return {\n mode: 'normal',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: true,\n _meta,\n }\n }\n}\n","/**\n * Additional utility functions using PanopticQuery contract.\n *\n * These functions provide enhanced analysis capabilities for portfolio management,\n * risk visualization, and TokenId optimization.\n *\n * @module v2/reads/queryUtils\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Portfolio value result (without premia).\n */\nexport interface PortfolioValue {\n /** Value in token 0 */\n value0: bigint\n /** Value in token 1 */\n value1: bigint\n /** Tick at which value was calculated */\n atTick: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPortfolioValue.\n */\nexport interface GetPortfolioValueParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** Optional: Tick to calculate value at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get portfolio value (NAV) without premia.\n *\n * This calculates the net asset value of the portfolio based on Uniswap liquidity\n * at a given tick, excluding accumulated premia. Useful for PnL tracking separate\n * from liquidation value.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Portfolio value with block metadata\n */\nexport async function getPortfolioValue(params: GetPortfolioValueParams): Promise<PortfolioValue> {\n const { client, poolAddress, account, tokenIds, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Skip getCurrentTick RPC call when atTick is provided\n const [currentTickResult, _meta] = await Promise.all([\n atTick != null\n ? Promise.resolve(atTick)\n : client\n .readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n .then((r) => BigInt(r)),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const effectiveTick = currentTickResult\n\n const result = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue',\n args: [poolAddress, account, Number(effectiveTick), tokenIds],\n blockNumber: targetBlockNumber,\n })\n\n const [value0, value1] = result\n\n return {\n value0,\n value1,\n atTick: effectiveTick,\n _meta,\n }\n}\n\n/**\n * Collateral data point across tick range.\n */\nexport interface CollateralDataPoint {\n /** Tick value */\n tick: bigint\n /** Collateral balance at this tick */\n balance: bigint\n /** Required collateral at this tick */\n required: bigint\n}\n\n/**\n * Collateral analysis across tick range result.\n */\nexport interface CollateralAcrossTicks {\n /** Array of data points (301 points from liquidation range) */\n dataPoints: CollateralDataPoint[]\n /** Liquidation price below current (null if none) */\n liquidationPriceDown: bigint | null\n /** Liquidation price above current (null if none) */\n liquidationPriceUp: bigint | null\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for checkCollateralAcrossTicks.\n */\nexport interface CheckCollateralAcrossTicksParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Check collateral balance vs requirement across a range of ticks.\n *\n * This function returns 301 data points spanning a range around the current price,\n * including liquidation prices. Perfect for charting liquidation risk in a UI.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Collateral analysis across ticks with block metadata\n */\nexport async function checkCollateralAcrossTicks(\n params: CheckCollateralAcrossTicksParams,\n): Promise<CollateralAcrossTicks> {\n const { client, poolAddress, account, tokenIds, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'checkCollateralListOutput',\n args: [poolAddress, account, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [balanceRequired, tickData, liquidationPrices] = result\n\n // MIN_TICK and MAX_TICK indicate no liquidation at that boundary\n const MIN_TICK = -887272n\n const MAX_TICK = 887272n\n\n // Convert to data points\n const dataPoints: CollateralDataPoint[] = balanceRequired.map((point, index) => ({\n tick: BigInt(tickData[index]),\n balance: point[0],\n required: point[1],\n }))\n\n // Convert from number (abitype default for int24) to bigint (viem runtime type)\n const liqPriceDown = BigInt(liquidationPrices[0])\n const liqPriceUp = BigInt(liquidationPrices[1])\n\n return {\n dataPoints,\n liquidationPriceDown: liqPriceDown === MIN_TICK ? null : liqPriceDown,\n liquidationPriceUp: liqPriceUp === MAX_TICK ? null : liqPriceUp,\n _meta,\n }\n}\n\n/**\n * Parameters for optimizeTokenIdRiskPartners.\n */\nexport interface OptimizeTokenIdRiskPartnersParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** TokenId to optimize */\n tokenId: bigint\n /** Optional: Tick to optimize at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Optimize risk partner assignments for a TokenId.\n *\n * Tests all valid risk partner permutations and returns the TokenId with\n * the lowest collateral requirement. Useful when building positions to\n * maximize capital efficiency.\n *\n * ## Same-Block Guarantee\n * Optimization is performed at a single block.\n *\n * Note: Only works for tokenIds with 2+ legs. Single-leg positions return unchanged.\n *\n * @param params - The parameters\n * @returns Optimized TokenId\n */\nexport async function optimizeTokenIdRiskPartners(\n params: OptimizeTokenIdRiskPartnersParams,\n): Promise<bigint> {\n const { client, poolAddress, tokenId, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n // Get current tick if not provided\n let effectiveTick: bigint\n if (atTick !== undefined) {\n effectiveTick = atTick\n } else {\n const currentTickResult = await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n // Bridge type from panopticPoolV2Abi (number | bigint) to bigint\n effectiveTick = BigInt(currentTickResult)\n }\n\n const optimizedTokenId = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'optimizeRiskPartners',\n args: [poolAddress, Number(effectiveTick), tokenId],\n blockNumber: targetBlockNumber,\n })\n\n return optimizedTokenId\n}\n","/**\n * Pool liquidity distribution read function using PanopticQuery.\n *\n * @module v2/reads/liquidity\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Result of getPoolLiquidities.\n */\nexport interface PoolLiquidities {\n /** Tick values for each data point */\n ticks: bigint[]\n /** Net liquidity at each tick */\n liquidityNets: bigint[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPoolLiquidities.\n */\nexport interface GetPoolLiquiditiesParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery address */\n queryAddress: Address\n /** Starting tick of the range */\n startTick: bigint\n /** Number of ticks to query */\n nTicks: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get cumulative liquidity distribution across a tick range.\n *\n * Wraps `PanopticQuery.getTickNets()` to return tick data and net liquidity\n * for each tick in the specified range.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Tick data and liquidity nets with block metadata\n */\nexport async function getPoolLiquidities(\n params: GetPoolLiquiditiesParams,\n): Promise<PoolLiquidities> {\n const { client, poolAddress, queryAddress, startTick, nTicks, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNets',\n args: [poolAddress, Number(startTick), nTicks],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [tickData, liquidityNets] = result\n\n return {\n ticks: [...tickData],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n","/**\n * Percentage and ratio formatters.\n *\n * All formatters require explicit precision - no hidden defaults.\n *\n * @module v2/formatters/percentage\n */\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n if (denominator === 0n) {\n return '0'\n }\n\n const isNegative = numerator < 0n !== denominator < 0n\n const absNumerator = numerator < 0n ? -numerator : numerator\n const absDenominator = denominator < 0n ? -denominator : denominator\n\n const scale = TEN ** precision\n const scaled = (absNumerator * scale + absDenominator / 2n) / absDenominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n const sign = isNegative ? '-' : ''\n\n if (precision === 0n) {\n return `${sign}${integerPart}`\n }\n\n return `${sign}${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Format basis points as a percentage string.\n * 100 bps = 1%\n *\n * @param bps - Basis points value\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatBps(50n, 2n) // \"0.50%\"\n * formatBps(50n, 1n) // \"0.5%\"\n * formatBps(100n, 2n) // \"1.00%\"\n * formatBps(1500n, 2n) // \"15.00%\"\n * formatBps(-50n, 2n) // \"-0.50%\"\n * ```\n */\nexport function formatBps(bps: bigint, precision: bigint): string {\n const isNegative = bps < 0n\n const absBps = isNegative ? -bps : bps\n\n // bps to percentage: divide by 100\n // Scale up for precision, then divide\n const scaleFactor = 10n ** precision\n const scaled = (absBps * scaleFactor) / 100n\n const integerPart = scaled / scaleFactor\n const fractionalPart = scaled % scaleFactor\n\n const fractionalStr = fractionalPart.toString().padStart(Number(precision), '0')\n const sign = isNegative ? '-' : ''\n\n return precision > 0n ? `${sign}${integerPart}.${fractionalStr}%` : `${sign}${integerPart}%`\n}\n\n/**\n * Format utilization as a percentage string.\n * Utilization is stored as 0n-10000n, where 10000n = 100%.\n *\n * @param util - Utilization value (0-10000)\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatUtilization(7500n, 2n) // \"75.00%\"\n * formatUtilization(7500n, 0n) // \"75%\"\n * formatUtilization(10000n, 2n) // \"100.00%\"\n * formatUtilization(123n, 2n) // \"1.23%\"\n * ```\n */\nexport function formatUtilization(util: bigint, precision: bigint): string {\n // util is in basis points (10000 = 100%)\n return formatBps(util, precision)\n}\n\n/**\n * Parse a percentage string to basis points.\n *\n * @param percent - Percentage string (e.g., \"1.5%\" or \"1.5\")\n * @returns Basis points value\n *\n * @example\n * ```typescript\n * parseBps(\"1.5%\") // 150n\n * parseBps(\"1.5\") // 150n\n * parseBps(\"100%\") // 10000n\n * parseBps(\"0.5%\") // 50n\n * ```\n */\nexport function parseBps(percent: string): bigint {\n // Remove % suffix if present\n const cleaned = percent.trim().replace(/%$/, '')\n const isNegative = cleaned.startsWith('-')\n const absValue = isNegative ? cleaned.slice(1) : cleaned\n\n const [integerStr, fractionalStr = ''] = absValue.split('.')\n\n // Convert to basis points: multiply by 100\n // Handle up to 2 decimal places in the percentage\n const paddedFractional = fractionalStr.padEnd(2, '0').slice(0, 2)\n\n const integerPart = BigInt(integerStr || '0') * 100n\n const fractionalPart = BigInt(paddedFractional || '0')\n\n const result = integerPart + fractionalPart\n return isNegative ? -result : result\n}\n\n/**\n * Format a ratio as a percentage string.\n *\n * @param numerator - Numerator of the ratio\n * @param denominator - Denominator of the ratio\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatRatioPercent(1n, 4n, 1n) // \"25.0%\"\n * formatRatioPercent(3n, 4n, 2n) // \"75.00%\"\n * ```\n */\nexport function formatRatioPercent(\n numerator: bigint,\n denominator: bigint,\n precision: bigint,\n): string {\n const scaledNumerator = numerator * 100n\n return `${formatRatio(scaledNumerator, denominator, precision)}%`\n}\n","/**\n * Pool-bound formatters factory.\n *\n * Creates formatter functions that capture pool context (token decimals)\n * for less verbose call sites in single-pool UI components.\n *\n * @module v2/formatters/poolFormatters\n */\n\nimport { formatTokenAmount, parseTokenAmount } from './amount'\nimport { priceToTick, tickToPrice, tickToPriceDecimalScaled } from './tick'\n\n/**\n * Pool-bound formatters interface.\n *\n * These formatters capture the pool's token decimals, so you don't need\n * to pass them at every call site.\n */\nexport interface PoolFormatters {\n /** Token0 decimals */\n readonly decimals0: bigint\n /** Token1 decimals */\n readonly decimals1: bigint\n\n /**\n * Convert tick to raw price (1.0001^tick).\n */\n tickToPrice(tick: bigint): string\n\n /**\n * Convert tick to decimal-scaled price (token1 per token0).\n */\n tickToPriceScaled(tick: bigint, precision: bigint): string\n\n /**\n * Convert tick to decimal-scaled inverse price (token0 per token1).\n */\n tickToInversePriceScaled(tick: bigint, precision: bigint): string\n\n /**\n * Convert a price (token1 per token0) to tick.\n */\n priceToTick(price: string): bigint\n\n /**\n * Format token0 amount with specified precision.\n */\n formatAmount0(amount: bigint, precision: bigint): string\n\n /**\n * Format token1 amount with specified precision.\n */\n formatAmount1(amount: bigint, precision: bigint): string\n\n /**\n * Parse token0 amount string to raw units.\n */\n parseAmount0(amount: string): bigint\n\n /**\n * Parse token1 amount string to raw units.\n */\n parseAmount1(amount: string): bigint\n}\n\n/**\n * Pool metadata required to create pool-bound formatters.\n */\nexport interface PoolFormatterConfig {\n /** Token0 decimals */\n decimals0: bigint\n /** Token1 decimals */\n decimals1: bigint\n}\n\n/**\n * Create pool-bound formatters that capture token decimals.\n *\n * Use this factory when working with a single pool to avoid passing\n * decimals at every call site.\n *\n * @param config - Pool configuration with token decimals\n * @returns Pool-bound formatter functions\n *\n * @example\n * ```typescript\n * // Get pool data\n * const pool = await getPool({ client, poolAddress })\n *\n * // Create formatters bound to this pool\n * const fmt = createPoolFormatters({\n * decimals0: pool.token0Decimals,\n * decimals1: pool.token1Decimals,\n * })\n *\n * // Now use without passing decimals each time\n * const priceStr = fmt.tickToPriceScaled(position.currentTick, 4n)\n * const amount0Str = fmt.formatAmount0(collateral.assets, 4n)\n * const amount1Str = fmt.formatAmount1(premia.token1, 2n)\n *\n * // Parse user input\n * const rawAmount0 = fmt.parseAmount0(\"1.5\")\n * const rawAmount1 = fmt.parseAmount1(\"3000\")\n * ```\n */\nexport function createPoolFormatters(config: PoolFormatterConfig): PoolFormatters {\n const { decimals0, decimals1 } = config\n\n return {\n decimals0,\n decimals1,\n\n tickToPrice(tick: bigint): string {\n return tickToPrice(tick)\n },\n\n tickToPriceScaled(tick: bigint, precision: bigint): string {\n return tickToPriceDecimalScaled(tick, decimals0, decimals1, precision)\n },\n\n tickToInversePriceScaled(tick: bigint, precision: bigint): string {\n // Swap decimals for inverse price\n return tickToPriceDecimalScaled(tick, decimals1, decimals0, precision)\n },\n\n priceToTick(price: string): bigint {\n return priceToTick(price, decimals0, decimals1)\n },\n\n formatAmount0(amount: bigint, precision: bigint): string {\n return formatTokenAmount(amount, decimals0, precision)\n },\n\n formatAmount1(amount: bigint, precision: bigint): string {\n return formatTokenAmount(amount, decimals1, precision)\n },\n\n parseAmount0(amount: string): bigint {\n return parseTokenAmount(amount, decimals0)\n },\n\n parseAmount1(amount: string): bigint {\n return parseTokenAmount(amount, decimals1)\n },\n }\n}\n","/**\n * Token list integration utilities.\n *\n * Provides helpers for integrating with standard token lists\n * (e.g., Uniswap token list, CoinGecko token list).\n *\n * @module v2/formatters/tokenList\n */\n\nimport type { Address } from 'viem'\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n const scale = TEN ** precision\n const scaled = (numerator * scale + denominator / 2n) / denominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n\n if (precision === 0n) {\n return integerPart.toString()\n }\n\n return `${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Generate a token list ID for external token list integration.\n *\n * Token lists use a standardized format: `chainId:address`\n * This is compatible with most token list standards.\n *\n * @param chainId - The chain ID\n * @param address - The token address\n * @returns Token list ID string\n *\n * @example\n * ```typescript\n * getTokenListId(1n, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')\n * // \"1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\"\n *\n * getTokenListId(11155111n, '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14')\n * // \"11155111:0xfff9976782d46cc05630d1f6ebab18b2324d6b14\"\n * ```\n */\nexport function getTokenListId(chainId: bigint, address: Address): string {\n return `${chainId}:${address.toLowerCase()}`\n}\n\n/**\n * Parse a token list ID back to chain ID and address.\n *\n * @param tokenListId - The token list ID string\n * @returns Object with chainId and address\n *\n * @example\n * ```typescript\n * parseTokenListId(\"1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\")\n * // { chainId: 1n, address: \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\" }\n * ```\n */\nexport function parseTokenListId(tokenListId: string): {\n chainId: bigint\n address: Address\n} {\n const [chainIdStr, address] = tokenListId.split(':')\n if (!chainIdStr || !address) {\n throw new Error(`Invalid token list ID: ${tokenListId}`)\n }\n return {\n chainId: BigInt(chainIdStr),\n address: address as Address,\n }\n}\n\n/**\n * Generate a pool ID string for display purposes.\n *\n * @param token0Symbol - Symbol of token0\n * @param token1Symbol - Symbol of token1\n * @param feeBps - Fee in basis points (e.g., 500n for 0.05%)\n * @returns Pool ID string\n *\n * @example\n * ```typescript\n * getPoolDisplayId('WETH', 'USDC', 500n)\n * // \"WETH/USDC 0.05%\"\n *\n * getPoolDisplayId('WBTC', 'ETH', 3000n)\n * // \"WBTC/ETH 0.30%\"\n * ```\n */\nexport function getPoolDisplayId(\n token0Symbol: string,\n token1Symbol: string,\n feeBps: bigint,\n): string {\n return `${token0Symbol}/${token1Symbol} ${formatFeeTier(feeBps)}`\n}\n\n/**\n * Format a fee tier for display.\n *\n * @param feeBps - Fee in basis points (e.g., 500n for 0.05%)\n * @returns Fee tier string\n *\n * @example\n * ```typescript\n * formatFeeTier(500n) // \"0.05%\"\n * formatFeeTier(3000n) // \"0.30%\"\n * formatFeeTier(10000n) // \"1.0%\"\n * ```\n */\nexport function formatFeeTier(feeBps: bigint): string {\n const precision = feeBps < 10000n ? 2n : 1n\n const feeStr = formatRatio(feeBps, 10_000n, precision)\n return `${feeStr}%`\n}\n","/**\n * General display formatters for UI components.\n *\n * These are utility formatters for common display needs like\n * addresses, timestamps, and durations.\n *\n * @module v2/formatters/display\n */\n\nimport { formatTokenAmount } from './amount'\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n const scale = TEN ** precision\n const scaled = (numerator * scale + denominator / 2n) / denominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n\n if (precision === 0n) {\n return integerPart.toString()\n }\n\n return `${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Truncate an address for display.\n *\n * @param address - Full address\n * @param chars - Characters to show on each side (default: 4)\n * @returns Truncated address like \"0x1234...5678\"\n *\n * @example\n * ```typescript\n * truncateAddress('0x1234567890abcdef1234567890abcdef12345678')\n * // \"0x1234...5678\"\n *\n * truncateAddress('0x1234567890abcdef1234567890abcdef12345678', 6)\n * // \"0x123456...345678\"\n * ```\n */\nexport function truncateAddress(address: string, chars = 4): string {\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(address.length) <= minLength) return address\n return `${address.slice(0, Number(charsBig + 2n))}...${address.slice(-Number(charsBig))}`\n}\n\n/**\n * Format a Unix timestamp as an ISO date string (YYYY-MM-DD).\n *\n * @param timestamp - Unix timestamp in seconds\n * @returns ISO date string\n *\n * @example\n * ```typescript\n * formatTimestamp(1700000000n) // \"2023-11-14\"\n * ```\n */\nexport function formatTimestamp(timestamp: bigint): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toISOString().split('T')[0]\n}\n\n/**\n * Format a Unix timestamp as an ISO datetime string.\n *\n * @param timestamp - Unix timestamp in seconds\n * @returns ISO datetime string\n *\n * @example\n * ```typescript\n * formatDatetime(1700000000n) // \"2023-11-14T22:13:20.000Z\"\n * ```\n */\nexport function formatDatetime(timestamp: bigint): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toISOString()\n}\n\n/**\n * Format a Unix timestamp as a locale-aware date string.\n *\n * @param timestamp - Unix timestamp in seconds\n * @param locale - Locale string (default: system locale)\n * @param options - Intl.DateTimeFormat options\n * @returns Formatted date string\n *\n * @example\n * ```typescript\n * formatTimestampLocale(1700000000n)\n * // \"11/14/2023\" (US locale)\n *\n * formatTimestampLocale(1700000000n, 'de-DE')\n * // \"14.11.2023\" (German locale)\n * ```\n */\nexport function formatTimestampLocale(\n timestamp: bigint,\n locale?: string,\n options?: Intl.DateTimeFormatOptions,\n): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toLocaleDateString(locale, options)\n}\n\n/**\n * Format a duration in milliseconds as a human-readable string.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted duration string\n *\n * @example\n * ```typescript\n * formatDuration(1500n) // \"1.5s\"\n * formatDuration(150n) // \"150ms\"\n * formatDuration(90000n) // \"1m 30s\"\n * formatDuration(3661000n) // \"1h 1m\"\n * ```\n */\nexport function formatDuration(ms: bigint): string {\n const isNegative = ms < 0n\n const absMs = isNegative ? -ms : ms\n const sign = isNegative ? '-' : ''\n\n if (absMs < 1000n) {\n return `${sign}${absMs}ms`\n }\n\n if (absMs < 60000n) {\n const tenthsTotal = (absMs + 50n) / 100n\n const seconds = tenthsTotal / 10n\n const tenths = tenthsTotal % 10n\n return `${sign}${seconds}.${tenths}s`\n }\n\n if (absMs < 3600000n) {\n const minutes = absMs / 60000n\n const seconds = ((absMs % 60000n) + 500n) / 1000n\n return seconds > 0n ? `${sign}${minutes}m ${seconds}s` : `${sign}${minutes}m`\n }\n\n const hours = absMs / 3600000n\n const minutes = ((absMs % 3600000n) + 30000n) / 60000n\n return minutes > 0n ? `${sign}${hours}h ${minutes}m` : `${sign}${hours}h`\n}\n\n/**\n * Format a duration in seconds as a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @returns Formatted duration string\n */\nexport function formatDurationSeconds(seconds: bigint): string {\n return formatDuration(seconds * 1000n)\n}\n\n/**\n * Format a block number for display.\n *\n * @param blockNumber - The block number\n * @returns Formatted block number with commas\n *\n * @example\n * ```typescript\n * formatBlockNumber(18000000n) // \"18,000,000\"\n * ```\n */\nexport function formatBlockNumber(blockNumber: bigint): string {\n return blockNumber.toLocaleString()\n}\n\n/**\n * Format a gas amount for display.\n *\n * @param gas - Gas units\n * @returns Formatted gas string\n */\nexport function formatGas(gas: bigint): string {\n return gas.toLocaleString()\n}\n\n/**\n * Format a transaction hash for display (truncated).\n *\n * @param hash - Full transaction hash\n * @param chars - Characters to show on each side (default: 6)\n * @returns Truncated hash like \"0x123456...abcdef\"\n *\n * @example\n * ```typescript\n * formatTxHash('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef')\n * // \"0x123456...abcdef\"\n * ```\n */\nexport function formatTxHash(hash: string, chars = 6): string {\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(hash.length) <= minLength) return hash\n return `${hash.slice(0, Number(charsBig + 2n))}...${hash.slice(-Number(charsBig))}`\n}\n\nfunction formatHex(value: bigint): string {\n return `0x${value.toString(16)}`\n}\n\n/**\n * Format a TokenId as a hex string.\n *\n * @param tokenId - TokenId value\n * @returns Hex string representation\n */\nexport function formatTokenIdHex(tokenId: bigint): string {\n return formatHex(tokenId)\n}\n\n/**\n * Format a PoolId as a hex string.\n *\n * @param poolId - PoolId value\n * @returns Hex string representation\n */\nexport function formatPoolIdHex(poolId: bigint): string {\n return formatHex(poolId)\n}\n\n/**\n * Format a TokenId as a shortened hex string.\n *\n * @param tokenId - TokenId value\n * @param chars - Characters to show on each side (default: 4)\n * @returns Truncated hex string like \"0x1234...abcd\"\n */\nexport function formatTokenIdShort(tokenId: bigint, chars = 4): string {\n const hex = formatHex(tokenId)\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(hex.length) <= minLength) return hex\n return `${hex.slice(0, Number(charsBig + 2n))}...${hex.slice(-Number(charsBig))}`\n}\n\n/**\n * Format a large number with K/M/B suffixes.\n *\n * @param value - The numeric value\n * @param precision - Number of decimal places (default: 1n)\n * @returns Formatted string with suffix\n *\n * @example\n * ```typescript\n * formatCompact(1234n) // \"1.2K\"\n * formatCompact(1234567n) // \"1.2M\"\n * formatCompact(1234567890n) // \"1.2B\"\n * formatCompact(999n) // \"999\"\n * ```\n */\nexport function formatCompact(value: bigint, precision: bigint = 1n): string {\n const isNegative = value < 0n\n const absValue = isNegative ? -value : value\n\n let formatted: string\n\n if (absValue < 1000n) {\n formatted = absValue.toString()\n } else if (absValue < 1_000_000n) {\n formatted = `${formatRatio(absValue, 1000n, precision)}K`\n } else if (absValue < 1_000_000_000n) {\n formatted = `${formatRatio(absValue, 1_000_000n, precision)}M`\n } else {\n formatted = `${formatRatio(absValue, 1_000_000_000n, precision)}B`\n }\n\n return isNegative ? `-${formatted}` : formatted\n}\n\n/**\n * Format a wei amount as a display string.\n *\n * @param wei - Amount in wei\n * @returns Formatted string with unit\n */\nexport function formatWei(wei: bigint): string {\n return `${wei} wei`\n}\n\n/**\n * Format a wei amount as gwei.\n *\n * @param wei - Amount in wei\n * @param precision - Number of decimal places to display\n * @returns Formatted string with unit\n */\nexport function formatGwei(wei: bigint, precision: bigint): string {\n return `${formatTokenAmount(wei, 9n, precision)} gwei`\n}\n","/**\n * Account greeks calculation using stored position data.\n *\n * This module provides functions to calculate account-level greeks\n * using position data stored by syncPositions(). Only the current tick\n * is fetched via RPC - all other data comes from storage.\n *\n * @module v2/reads/accountGreeks\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError, StorageDataNotFoundError } from '../errors'\nimport { tickToSqrtPriceX96 } from '../formatters'\nimport {\n type PositionGreeksResult,\n calculatePositionDelta,\n calculatePositionGamma,\n calculatePositionValue,\n} from '../greeks'\nimport type { StorageAdapter } from '../storage'\nimport { getPoolMetaKey, getPositionMetaKey, getPositionsKey, jsonSerializer } from '../storage'\nimport type { BlockMeta, StoredPoolMeta, StoredPositionData } from '../types'\nimport { type CollateralAddresses, getAccountCollateral } from './account'\n\nconst Q192 = 1n << 192n\n\n/**\n * Parameters for getAccountGreeks.\n */\nexport interface GetAccountGreeksParams {\n /** viem PublicClient (only used to fetch current tick) */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Storage adapter containing synced position data */\n storage: StorageAdapter\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /**\n * When true, include collateral token balance as linear delta.\n * Requires `assetIndex` to specify which token is the asset.\n */\n includeCollateral?: boolean\n /**\n * Which token is the \"asset\" (the directional exposure token).\n * 0n = token0 is asset, 1n = token1 is asset.\n * Required when `includeCollateral` is true.\n */\n assetIndex?: 0n | 1n\n /** Optional pre-fetched collateral addresses (used when includeCollateral is true) */\n collateralAddresses?: CollateralAddresses\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getAccountGreeks.\n *\n * Returns both granular breakdown (positions vs collateral) and computed totals.\n * - `positionsDelta` / `positionsValue`: Options exposure only\n * - `collateralDelta` / `collateralValue`: Collateral in the pool\n * - `totalDelta` / `totalValue`: Sum of both (use for net portfolio greeks)\n *\n * All values are in natural token smallest units (no WAD scaling).\n * - Value/gamma: numeraire token smallest units\n * - Delta: asset token smallest units\n */\nexport interface AccountGreeksResult {\n // --- Position greeks (options only) ---\n /** Sum of position values (numeraire smallest units, options only) */\n positionsValue: bigint\n /** Sum of position deltas (asset smallest units, options only) */\n positionsDelta: bigint\n /** Sum of position gammas (numeraire smallest units) */\n positionsGamma: bigint\n\n // --- Collateral greeks ---\n /**\n * Value of collateral holdings: asset balance × price + numeraire balance.\n * In numeraire smallest units. 0n when includeCollateral is not set.\n */\n collateralValue: bigint\n /**\n * Linear delta from the asset token's collateral balance (asset smallest units).\n * 0n when includeCollateral is not set.\n */\n collateralDelta: bigint\n\n // --- Computed totals ---\n /** Total portfolio value = positionsValue + collateralValue */\n totalValue: bigint\n /** Total portfolio delta = positionsDelta + collateralDelta */\n totalDelta: bigint\n\n // --- Metadata ---\n /** Number of positions included */\n positionCount: bigint\n /** Per-position greeks breakdown */\n positions: Array<{\n tokenId: bigint\n greeks: PositionGreeksResult\n }>\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Calculate account-level greeks using stored position data.\n *\n * This function reads position data from storage (populated by syncPositions)\n * and calculates greeks client-side. Only the current tick is fetched via RPC.\n *\n * @param params - The parameters\n * @returns Account greeks with per-position breakdown\n * @throws StorageDataNotFoundError if required data is not in storage\n * @throws PanopticError if includeCollateral is true but assetIndex is not provided\n *\n * @example\n * ```typescript\n * // First sync positions to populate storage\n * await syncPositions({ client, chainId, poolAddress, account, storage })\n *\n * // Then calculate greeks from stored data\n * const greeks = await getAccountGreeks({\n * client,\n * chainId,\n * poolAddress,\n * account,\n * storage,\n * })\n *\n * console.log('Positions delta:', greeks.positionsDelta)\n * ```\n */\nexport async function getAccountGreeks(\n params: GetAccountGreeksParams,\n): Promise<AccountGreeksResult> {\n const {\n client,\n chainId,\n poolAddress,\n account,\n storage,\n blockNumber,\n includeCollateral,\n assetIndex,\n collateralAddresses,\n } = params\n\n // 0. Validate: includeCollateral requires assetIndex\n if (includeCollateral && assetIndex === undefined) {\n throw new PanopticError('assetIndex is required when includeCollateral is true')\n }\n\n // 1. Read pool metadata from storage\n const poolMetaKey = getPoolMetaKey(chainId, poolAddress)\n const poolMetaRaw = await storage.get(poolMetaKey)\n if (!poolMetaRaw) {\n throw new StorageDataNotFoundError('poolMeta', poolMetaKey)\n }\n const poolMeta = jsonSerializer.parse(poolMetaRaw) as StoredPoolMeta\n\n // 2. Read position IDs from storage\n const positionsKey = getPositionsKey(chainId, poolAddress, account)\n const positionsRaw = await storage.get(positionsKey)\n if (!positionsRaw) {\n throw new StorageDataNotFoundError('positions', positionsKey)\n }\n const positionIds = jsonSerializer.parse(positionsRaw) as bigint[]\n\n // 3. If no positions and no collateral requested, return zeros\n if (positionIds.length === 0 && !includeCollateral) {\n const targetBlock = blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlock }))\n\n return {\n positionsValue: 0n,\n positionsDelta: 0n,\n positionsGamma: 0n,\n collateralValue: 0n,\n collateralDelta: 0n,\n totalValue: 0n,\n totalDelta: 0n,\n positionCount: 0n,\n positions: [],\n _meta,\n }\n }\n\n // 4. Read position metadata for each position from storage\n const storedPositions = await Promise.all(\n positionIds.map(async (tokenId) => {\n const posMetaKey = getPositionMetaKey(chainId, poolAddress, tokenId)\n const posMetaRaw = await storage.get(posMetaKey)\n if (!posMetaRaw) {\n throw new StorageDataNotFoundError('positionMeta', posMetaKey)\n }\n return jsonSerializer.parse(posMetaRaw) as StoredPositionData\n }),\n )\n\n // 5. Fetch current tick (+ collateral if requested) from RPC\n const targetBlock = blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [currentTick, _meta, collateral] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlock,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlock }),\n includeCollateral\n ? getAccountCollateral({\n client,\n poolAddress,\n account,\n blockNumber: targetBlock,\n collateralAddresses,\n _meta: params._meta,\n })\n : undefined,\n ])\n\n // 6. Calculate greeks for each position\n let positionsValue = 0n\n let positionsDelta = 0n\n let positionsGamma = 0n\n const positions: AccountGreeksResult['positions'] = []\n\n for (const pos of storedPositions) {\n const input = {\n legs: pos.legs,\n currentTick: BigInt(currentTick),\n mintTick: pos.tickAtMint,\n positionSize: pos.positionSize,\n poolTickSpacing: poolMeta.tickSpacing,\n assetIndex,\n }\n\n const value = calculatePositionValue(input)\n const delta = calculatePositionDelta(input)\n const gamma = calculatePositionGamma(input)\n\n positionsValue += value\n positionsDelta += delta\n positionsGamma += gamma\n\n positions.push({\n tokenId: pos.tokenId,\n greeks: { value, delta, gamma },\n })\n }\n\n // 7. Collateral value and delta\n let collateralValue = 0n\n let collateralDelta = 0n\n\n if (collateral) {\n const isAssetToken0 = assetIndex === 0n\n const assetBal = isAssetToken0 ? collateral.token0.assets : collateral.token1.assets\n const otherBal = isAssetToken0 ? collateral.token1.assets : collateral.token0.assets\n const sqrtPriceX96 = tickToSqrtPriceX96(BigInt(currentTick))\n\n // assetBal * price converts asset smallest units to numeraire smallest units\n // otherBal is already in numeraire smallest units\n if (isAssetToken0) {\n // price = token1/token0 = sqrtPriceX96² / 2¹⁹²\n collateralValue = (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192 + otherBal\n } else {\n // price = token0/token1 = 2¹⁹² / sqrtPriceX96²\n collateralValue = (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96) + otherBal\n }\n collateralDelta = assetBal\n }\n\n return {\n positionsValue,\n positionsDelta,\n positionsGamma,\n collateralValue,\n collateralDelta,\n totalValue: positionsValue + collateralValue,\n totalDelta: positionsDelta + collateralDelta,\n positionCount: BigInt(positionIds.length),\n positions,\n _meta,\n }\n}\n\n/**\n * Parameters for calculateAccountGreeksPure.\n */\nexport interface CalculateAccountGreeksPureParams {\n /** Stored position data */\n positions: StoredPositionData[]\n /** Pool tick spacing */\n tickSpacing: bigint\n /** Ticks at which to evaluate greeks (one or more) */\n atTicks: bigint[]\n /**\n * Collateral balances [token0Assets, token1Assets] in token smallest units.\n * When provided, both tokens are included in totalValue and the\n * asset token's balance is added to totalDelta.\n */\n collateralAssets?: [bigint, bigint]\n /** Override for leg.asset on all legs (0n = token0 is asset, 1n = token1). Defaults to 0n. */\n assetIndex?: bigint\n}\n\n/**\n * Result of calculateAccountGreeksPure.\n *\n * Arrays are parallel to the input `atTicks` — index i corresponds to `atTicks[i]`.\n * Totals include both position greeks and collateral contributions.\n * All values in natural token smallest units (no WAD scaling).\n */\nexport interface AccountGreeksCurveResult {\n /** Total value at each tick: positions + collateral (numeraire smallest units) */\n totalValue: bigint[]\n /** Total delta at each tick: positions + asset collateral (asset smallest units) */\n totalDelta: bigint[]\n /** Total gamma at each tick: positions only (numeraire smallest units, collateral has zero gamma) */\n totalGamma: bigint[]\n /** Number of positions included */\n positionCount: bigint\n /** Per-position greeks curves (arrays parallel to atTicks) */\n positions: Array<{\n tokenId: bigint\n greeks: {\n value: bigint[]\n delta: bigint[]\n gamma: bigint[]\n }\n }>\n}\n\n/**\n * Pure function to calculate portfolio greeks across a range of ticks.\n *\n * No RPC calls — useful for plotting value/delta/gamma curves on a chart.\n * All returned arrays are parallel to the input `atTicks`.\n *\n * When `collateralAssets` is provided, both token balances are included in\n * `totalValue` (asset balance × price + numeraire balance) and\n * the asset token's balance is added to `totalDelta`.\n *\n * @param params - The parameters\n * @returns Portfolio greeks curves and per-position breakdown\n */\nexport function calculateAccountGreeksPure(\n params: CalculateAccountGreeksPureParams,\n): AccountGreeksCurveResult {\n const { positions, tickSpacing, atTicks, collateralAssets, assetIndex } = params\n const n = atTicks.length\n const isAssetToken0 = assetIndex === undefined || assetIndex === 0n\n\n // Collateral balances (already in token smallest units)\n const assetBal = collateralAssets ? collateralAssets[isAssetToken0 ? 0 : 1] : 0n\n const otherBal = collateralAssets ? collateralAssets[isAssetToken0 ? 1 : 0] : 0n\n\n if (positions.length === 0) {\n const totalValue: bigint[] = []\n const totalDelta: bigint[] = []\n for (let i = 0; i < n; i++) {\n const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i])\n const assetValueInNumeraire = isAssetToken0\n ? (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192\n : (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96)\n totalValue.push(assetValueInNumeraire + otherBal)\n totalDelta.push(assetBal)\n }\n return {\n totalValue,\n totalDelta,\n totalGamma: new Array<bigint>(n).fill(0n),\n positionCount: 0n,\n positions: [],\n }\n }\n\n const totalValue = new Array<bigint>(n).fill(0n)\n const totalDelta = new Array<bigint>(n).fill(0n)\n const totalGamma = new Array<bigint>(n).fill(0n)\n const positionResults: AccountGreeksCurveResult['positions'] = []\n\n for (const pos of positions) {\n const posValues: bigint[] = []\n const posDeltas: bigint[] = []\n const posGammas: bigint[] = []\n\n for (let i = 0; i < n; i++) {\n const input = {\n legs: pos.legs,\n currentTick: atTicks[i],\n mintTick: pos.tickAtMint,\n positionSize: pos.positionSize,\n poolTickSpacing: tickSpacing,\n assetIndex,\n }\n\n const v = calculatePositionValue(input)\n const d = calculatePositionDelta(input)\n const g = calculatePositionGamma(input)\n\n posValues.push(v)\n posDeltas.push(d)\n posGammas.push(g)\n\n totalValue[i] += v\n totalDelta[i] += d\n totalGamma[i] += g\n }\n\n positionResults.push({\n tokenId: pos.tokenId,\n greeks: { value: posValues, delta: posDeltas, gamma: posGammas },\n })\n }\n\n // Add collateral contributions at each tick\n for (let i = 0; i < n; i++) {\n const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i])\n const assetValueInNumeraire = isAssetToken0\n ? (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192\n : (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96)\n totalValue[i] += assetValueInNumeraire + otherBal\n totalDelta[i] += assetBal\n }\n\n return {\n totalValue,\n totalDelta,\n totalGamma,\n positionCount: BigInt(positions.length),\n positions: positionResults,\n }\n}\n","/**\n * Margin buffer and distance-to-liquidation convenience function.\n *\n * Sources current and required margin directly from\n * `PanopticPool.getFullPositionsData` + `CollateralTracker.assetsOf`,\n * rather than `PanopticQuery.checkCollateral`.\n *\n * Why: `checkCollateral` returns a `currentMargin` already netted of the\n * borrowing obligation of width=0 short (\"loan\") tokenIds, and a\n * `requiredMargin` that does NOT include the loan's collateral requirement.\n * That makes buying-power usage read 0% for accounts whose collateral\n * comes mostly from a loan, and double-subtracts the loan from Net Liq\n * when downstream callers add the position MtM (which already values the\n * loan at `-notional`).\n *\n * `getFullPositionsData.collateralRequirements[]` attributes the loan as\n * a margin requirement (the accurate primitive), and `assetsOf` returns\n * the gross collateral (deposits + borrowed shares) — pairing them yields\n * a consistent gross-collateral / gross-requirement view.\n *\n * @module v2/reads/margin\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { tickToSqrtPriceX96 } from '../formatters/tick'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { type MulticallBlockCall, readBlockAndAggregate, requireReturnData } from './multicallBlock'\n\n// Sentinel ticks used by PanopticQuery to indicate \"no liquidation at this boundary\"\nconst MIN_TICK = -887272n\nconst MAX_TICK = 887272n\n\nconst FP96 = 1n << 96n\nconst Q128 = 1n << 128n\n\n/** Cap for a usage ratio with no collateral behind it. */\nconst MAX_USAGE_BPS = 1_000_000n\n\nconst bigintMax = (a: bigint, b: bigint): bigint => (a > b ? a : b)\nconst bigintMin = (a: bigint, b: bigint): bigint => (a < b ? a : b)\n\n/**\n * `RiskEngine.BP_DECREASE_BUFFER` over `PanopticPool.NO_BUFFER` — the extra\n * margin the solvency check demands at mint (and on collateral withdrawal),\n * above the maintenance requirement that governs liquidation.\n */\nconst MINT_BUFFER = 10_666_667n\nconst MINT_BUFFER_DENOMINATOR = 10_000_000n\n\n/**\n * Convert a token0 amount to its token1-equivalent at the given sqrtPriceX96.\n *\n * Matches the on-chain `PanopticMath.convert0to1` truncation, with an\n * overflow-safe branch when `sqrtPriceX96^2` would not fit in uint256.\n */\nfunction convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n // amount * (sqrtPriceX96 * sqrtPriceX96 >> 64n) >> 128n\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\n/**\n * Convert a token1 amount to its token0-equivalent at the given sqrtPriceX96.\n */\nfunction convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Parameters for {@link getMarginBuffer}.\n */\nexport interface GetMarginBufferParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions (loan/credit width=0 legs included) */\n tokenIds: bigint[]\n /** PanopticQuery address (required for liquidation prices) */\n queryAddress: Address\n /**\n * Optional pre-fetched collateral tracker addresses (saves an RPC).\n * If omitted, they are fetched from the pool.\n */\n collateralAddresses?: { collateralToken0: Address; collateralToken1: Address }\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Margin buffer result with distance-to-liquidation.\n *\n * **Denomination**: Both slots are populated with the account total\n * cross-converted into a single token denomination so they can be\n * compared directly.\n *\n * - `currentMargin0` / `requiredMargin0` / `buffer0` are denominated in **token0**.\n * - `currentMargin1` / `requiredMargin1` / `buffer1` are denominated in **token1**.\n *\n * `denominatedInToken` indicates which of the two pairs is \"preferred\":\n * 0 when `currentTick < 0`, 1 otherwise — matching the historical\n * `checkCollateral` convention so downstream consumers keep working\n * without changes.\n */\nexport interface MarginBuffer {\n /** Excess margin in token0 units (positive = safe, negative = shortfall) */\n buffer0: bigint\n /** Excess margin in token1 units (positive = safe, negative = shortfall) */\n buffer1: bigint\n /** Buffer as percentage of required margin in bps (slot 0). null if no requirement. */\n bufferPercent0: bigint | null\n /** Buffer as percentage of required margin in bps (slot 1). null if no requirement. */\n bufferPercent1: bigint | null\n /** Current (gross) account collateral, denominated in token0 */\n currentMargin0: bigint\n /** Current (gross) account collateral, denominated in token1 */\n currentMargin1: bigint\n /**\n * Sum of per-position collateral requirements from\n * `getFullPositionsData.collateralRequirements[]`, denominated in token0.\n * Loans/credits (width=0) contribute correctly.\n */\n requiredMargin0: bigint\n /** Same, denominated in token1 */\n requiredMargin1: bigint\n /**\n * Which token the \"preferred\" margin values are denominated in.\n * 0 = token0 (when currentTick < 0), 1 = token1 (when currentTick >= 0).\n */\n denominatedInToken: 0 | 1\n /** Tick distance to nearest liquidation boundary (null if no liquidation boundaries) */\n liquidationDistance: bigint | null\n /** Lower liquidation tick (null if safe at MIN_TICK) */\n lowerLiquidationTick: bigint | null\n /** Upper liquidation tick (null if safe at MAX_TICK) */\n upperLiquidationTick: bigint | null\n /**\n * Collateral usage against the constraint that actually liquidates, in bps\n * (10000 = at the liquidation threshold). Null when the account holds no\n * positions.\n *\n * NOT `requiredMargin / currentMargin`. That ratio pools both collateral\n * tokens into one number, which silently assumes cross-collateral is credited\n * at 100%. It is only credited at `RiskEngine.crossBufferRatio(utilization,\n * CROSS_BUFFER_n)`, which decays linearly from the configured buffer to ZERO\n * between 90% and 95% pool utilization. Measured on mainnet with\n * CROSS_BUFFER = 100% and the token0 tracker at 91.98% utilization, only\n * 60.4% of the token0 surplus counted toward the token1 requirement — the\n * pooled ratio read 40% while this one read ~90% and liquidation was 8.7%\n * away.\n *\n * Sourced from `PanopticQuery.checkCollateral` at the current tick, which\n * applies the live cross-buffer, and reported for whichever token side is\n * tighter. Solvency requires both to hold.\n */\n crossMarginUsageBps: bigint | null\n /** Usage of the token0 side alone, in bps. Null when no positions. */\n usageBps0: bigint | null\n /** Usage of the token1 side alone, in bps. Null when no positions. */\n usageBps1: bigint | null\n /**\n * Collateral still deployable before the mint solvency check would fail,\n * in `denominatedInToken` units. Null when the account holds no positions.\n *\n * The tighter of `balance - required * BP_DECREASE_BUFFER` across the two\n * token sides, from `checkCollateral` at the current tick. NOT\n * `currentMargin - requiredMargin * buffer`, which pools both collateral\n * tokens and so credits cross-collateral at 100% regardless of the live\n * `crossBufferRatio`. On a mainnet account that pooled figure read ~24,000\n * USDC of headroom while the binding side had ~890 — and a mint requiring\n * ~2,700 USDC duly reverted with AccountInsolvent.\n */\n mintableMarginBinding: bigint | null\n /** Current tick */\n currentTick: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Get margin buffer and distance-to-liquidation for an account.\n *\n * Reads, all pinned to the same block:\n * - `getCurrentTick` (sequencing dependency for sqrtPrice conversion)\n * - `getFullPositionsData(account, true, tokenIds)` → collateralRequirements\n * - `CollateralTracker.assetsOf(account)` on both trackers → gross collateral\n * - `PanopticQuery.getLiquidationPrices(...)` → liquidation boundaries\n *\n * @param params - The parameters\n * @returns Margin buffer with liquidation distance and block metadata\n */\nexport async function getMarginBuffer(params: GetMarginBufferParams): Promise<MarginBuffer> {\n const { client, poolAddress, account, tokenIds, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Resolve collateral tracker addresses (immutable; cache-friendly).\n let collateralToken0: Address\n let collateralToken1: Address\n if (params.collateralAddresses) {\n collateralToken0 = params.collateralAddresses.collateralToken0\n collateralToken1 = params.collateralAddresses.collateralToken1\n } else {\n const addrs = await client.multicall({\n contracts: [\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken0' },\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken1' },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n })\n collateralToken0 = addrs[0]\n collateralToken1 = addrs[1]\n }\n\n const hasPositions = tokenIds.length > 0\n const calls: MulticallBlockCall[] = [\n {\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n }),\n },\n {\n target: collateralToken0,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n {\n target: collateralToken1,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n ]\n\n const positionDataIndex = hasPositions ? calls.length : null\n if (positionDataIndex !== null) {\n calls.push({\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, tokenIds],\n }),\n })\n }\n\n const liqPricesIndex = hasPositions ? calls.length : null\n if (liqPricesIndex !== null) {\n calls.push({\n target: queryAddress,\n callData: encodeFunctionData({\n abi: panopticQueryAbi,\n functionName: 'getLiquidationPrices',\n args: [poolAddress, account, tokenIds],\n }),\n })\n }\n\n // 3-arg overload: evaluates at (currentTick, fastOracleTick, slowOracleTick,\n // latestObservation) so it needs no tick input and fits this same multicall.\n // We read index 0 (currentTick) to stay consistent with the liquidation price\n // and the risk chart, which are also anchored there.\n const checkCollateralIndex = hasPositions ? calls.length : null\n if (checkCollateralIndex !== null) {\n calls.push({\n target: queryAddress,\n callData: encodeFunctionData({\n abi: panopticQueryAbi,\n functionName: 'checkCollateral',\n args: [poolAddress, account, tokenIds],\n }),\n })\n }\n\n const { _meta, results } = await readBlockAndAggregate({\n client,\n calls,\n blockNumber: targetBlockNumber,\n })\n\n const currentTickResult = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n data: requireReturnData(results, 0, 'PanopticPool.getCurrentTick'),\n })\n const currentTick = BigInt(currentTickResult)\n const assets0 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 1, 'CollateralTracker.assetsOf token0'),\n })\n const assets1 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 2, 'CollateralTracker.assetsOf token1'),\n })\n const positionDataResult =\n positionDataIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data: requireReturnData(results, positionDataIndex, 'PanopticPool.getFullPositionsData'),\n }) as readonly [bigint, bigint, readonly bigint[], readonly bigint[], readonly bigint[]])\n const liqPricesResult =\n liqPricesIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticQueryAbi,\n functionName: 'getLiquidationPrices',\n data: requireReturnData(results, liqPricesIndex, 'PanopticQuery.getLiquidationPrices'),\n }) as readonly [number, number])\n\n const checkCollateralResult =\n checkCollateralIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticQueryAbi,\n functionName: 'checkCollateral',\n data: requireReturnData(results, checkCollateralIndex, 'PanopticQuery.checkCollateral'),\n }) as readonly [readonly bigint[], readonly bigint[], readonly bigint[], readonly bigint[]])\n\n // Usage against the binding constraint, at the current tick (index 0).\n // checkCollateral has already applied the live cross-buffer, so this reflects\n // how much of the surplus in one token genuinely counts toward the other.\n let usageBps0: bigint | null = null\n let usageBps1: bigint | null = null\n let crossMarginUsageBps: bigint | null = null\n let mintableMarginBinding: bigint | null = null\n if (checkCollateralResult) {\n const [balances0, requireds0, balances1, requireds1] = checkCollateralResult\n const ratio = (required: bigint | undefined, balance: bigint | undefined): bigint | null => {\n if (required === undefined || balance === undefined) return null\n // No balance but a requirement is maximally used, not undefined.\n if (balance === 0n) return required > 0n ? MAX_USAGE_BPS : 0n\n return (required * 10_000n) / balance\n }\n usageBps0 = ratio(requireds0[0], balances0[0])\n usageBps1 = ratio(requireds1[0], balances1[0])\n if (usageBps0 !== null || usageBps1 !== null) {\n crossMarginUsageBps =\n usageBps0 === null\n ? usageBps1\n : usageBps1 === null\n ? usageBps0\n : bigintMax(usageBps0, usageBps1)\n }\n\n // Collateral still deployable before the mint solvency check would fail.\n // Per side: balance - required * mintBuffer, then the tighter of the two,\n // because the mint must satisfy BOTH. Both sides are already in\n // `denominatedInToken` units (checkCollateral branches on the same\n // sqrtPriceX96 < FP96 test), so the min is well defined.\n const mintable = (balance: bigint | undefined, required: bigint | undefined): bigint | null => {\n if (balance === undefined || required === undefined) return null\n const requiredAtMint =\n (required * MINT_BUFFER + MINT_BUFFER_DENOMINATOR - 1n) / MINT_BUFFER_DENOMINATOR\n return balance > requiredAtMint ? balance - requiredAtMint : 0n\n }\n const mintable0 = mintable(balances0[0], requireds0[0])\n const mintable1 = mintable(balances1[0], requireds1[0])\n if (mintable0 !== null || mintable1 !== null) {\n mintableMarginBinding =\n mintable0 === null\n ? mintable1\n : mintable1 === null\n ? mintable0\n : bigintMin(mintable0, mintable1)\n }\n }\n\n // Sum collateral requirements across all positions, per token.\n let required0Native = 0n\n let required1Native = 0n\n if (positionDataResult) {\n const collateralRequirements = positionDataResult[3]\n for (const packed of collateralRequirements) {\n const decoded = decodeLeftRightUnsigned(packed)\n required0Native += decoded.right // token0\n required1Native += decoded.left // token1\n }\n }\n\n // Cross-convert into a single denomination at current tick.\n // The conversion mirrors PanopticQuery.checkCollateral's effective-balance\n // shape so downstream callers keep their existing per-slot interpretation.\n const sqrtPriceX96 = tickToSqrtPriceX96(currentTick)\n const denominatedInToken: 0 | 1 = sqrtPriceX96 < FP96 ? 0 : 1\n\n // Token0-denominated totals\n const currentMargin0 = assets0 + convert1to0(assets1, sqrtPriceX96)\n const requiredMargin0 = required0Native + convert1to0(required1Native, sqrtPriceX96)\n // Token1-denominated totals\n const currentMargin1 = assets1 + convert0to1(assets0, sqrtPriceX96)\n const requiredMargin1 = required1Native + convert0to1(required0Native, sqrtPriceX96)\n\n const buffer0 = currentMargin0 - requiredMargin0\n const buffer1 = currentMargin1 - requiredMargin1\n const bufferPercent0 = requiredMargin0 === 0n ? null : (buffer0 * 10000n) / requiredMargin0\n const bufferPercent1 = requiredMargin1 === 0n ? null : (buffer1 * 10000n) / requiredMargin1\n\n // Liquidation prices: present only when the account has positions.\n let lowerLiquidationTick: bigint | null = null\n let upperLiquidationTick: bigint | null = null\n let liquidationDistance: bigint | null = null\n if (liqPricesResult) {\n const liqPriceDown = BigInt(liqPricesResult[0])\n const liqPriceUp = BigInt(liqPricesResult[1])\n lowerLiquidationTick = liqPriceDown === MIN_TICK ? null : liqPriceDown\n upperLiquidationTick = liqPriceUp === MAX_TICK ? null : liqPriceUp\n if (lowerLiquidationTick !== null && upperLiquidationTick !== null) {\n const distLower = currentTick - lowerLiquidationTick\n const distUpper = upperLiquidationTick - currentTick\n liquidationDistance = distLower < distUpper ? distLower : distUpper\n } else if (lowerLiquidationTick !== null) {\n liquidationDistance = currentTick - lowerLiquidationTick\n } else if (upperLiquidationTick !== null) {\n liquidationDistance = upperLiquidationTick - currentTick\n }\n }\n\n return {\n buffer0,\n buffer1,\n bufferPercent0,\n bufferPercent1,\n currentMargin0,\n currentMargin1,\n requiredMargin0,\n requiredMargin1,\n denominatedInToken,\n liquidationDistance,\n lowerLiquidationTick,\n upperLiquidationTick,\n crossMarginUsageBps,\n usageBps0,\n usageBps1,\n mintableMarginBinding,\n currentTick,\n _meta,\n }\n}\n","/**\n * Delta hedging utilities for the Panoptic v2 SDK.\n *\n * Provides functions to calculate loan parameters needed\n * to achieve a target delta for option positions.\n *\n * @module v2/reads/hedge\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticValidationError } from '../errors/sdk'\nimport { calculatePositionDelta } from '../greeks'\nimport { decodeTokenId } from '../tokenId'\nimport type { LegConfig } from '../tokenId/builder'\nimport type { BlockMeta } from '../types'\nimport { getPool } from './pool'\n\n/**\n * Parameters for getDeltaHedgeParams.\n */\nexport interface GetDeltaHedgeParamsInput {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Chain ID */\n chainId: bigint\n /**\n * TokenId of the option position to hedge.\n * Optional when both `currentDelta` and `asset` are provided (whole-portfolio hedging).\n */\n tokenId?: bigint\n /**\n * Position size in contracts.\n * Optional when both `currentDelta` and `asset` are provided.\n */\n positionSize?: bigint\n /** Target delta (WAD-scaled, 0n for delta-neutral) */\n targetDelta: bigint\n /** Optional: current delta if adjusting existing position (WAD-scaled) */\n currentDelta?: bigint\n /**\n * Primary asset index (0n or 1n). Used to determine hedge direction.\n * Required when `tokenId` is not provided; ignored when `tokenId` is provided.\n */\n asset?: bigint\n /** Optional: tick at mint (defaults to current tick if not provided) */\n mintTick?: bigint\n /** Optional: block number for historical queries */\n blockNumber?: bigint\n /** Optional: current tick (skips getPool() when both currentTick and tickSpacing are provided) */\n currentTick?: bigint\n /** Optional: pool tick spacing (skips getPool() when both currentTick and tickSpacing are provided) */\n tickSpacing?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n\n // --- Simulation convergence options ---\n\n /**\n * Simulate the hedge swap and return the post-swap tick.\n * When provided (along with `computeDeltaAtTick`), an iterative loop refines\n * the hedge size to account for AMM price impact.\n */\n simulateSwap?: (hedgeAmount: bigint, hedgeLeg: LegConfig) => Promise<{ tickAfter: bigint } | null>\n\n /**\n * Recompute portfolio delta at a given tick.\n * Required when `simulateSwap` is provided.\n */\n computeDeltaAtTick?: (tick: bigint) => bigint\n\n /** Total position size — used for convergence check (sizeDelta * 10000 / totalPositionSize) */\n totalPositionSize?: bigint\n\n /** Max simulation iterations (default 5) */\n maxSimIterations?: number\n\n /** Convergence threshold in bps (default 10). Loop stops when size change < this. */\n convergenceThresholdBps?: bigint\n}\n\n/**\n * Result of getDeltaHedgeParams.\n */\nexport interface DeltaHedgeResult {\n /** LegConfig to add to the position for hedging */\n hedgeLeg: LegConfig\n /** The hedge amount (in position size units) */\n hedgeAmount: bigint\n /** Always 'loan' — the tokenType determines the delta direction */\n hedgeType: 'loan' | 'credit'\n /** Whether the hedge position should be opened with swapAtMint */\n swapAtMint: boolean\n /** Current position delta (WAD-scaled) */\n currentDelta: bigint\n /** Target delta (WAD-scaled) */\n targetDelta: bigint\n /** Delta adjustment needed (WAD-scaled) */\n deltaAdjustment: bigint\n /** Block metadata */\n _meta: BlockMeta\n /** Number of simulation iterations used (0 if no simulateSwap) */\n simulationIterations: number\n /** Post-swap tick from final simulation (undefined if no simulation) */\n simulatedTickAfter?: bigint\n /** Whether the convergence loop converged within threshold */\n converged: boolean\n}\n\n/**\n * Calculate loan parameters to achieve target delta via swapAtMint.\n *\n * Both delta directions use loans with swapAtMint — the tokenType\n * determines whether delta is added or removed:\n *\n * - **Need positive delta** (e.g. hedging a short call):\n * Loan with tokenType = numeraire + swapAtMint.\n * Borrows numeraire (e.g. USDC), swaps to asset (e.g. ETH).\n * Net: +asset exposure → positive delta.\n *\n * - **Need negative delta** (e.g. hedging a short put):\n * Loan with tokenType = asset + swapAtMint.\n * Borrows asset (e.g. ETH), swaps to numeraire (e.g. USDC).\n * Net: −asset exposure → negative delta.\n *\n * ## Example: Delta-neutral short call\n * ```typescript\n * const hedge = await getDeltaHedgeParams({\n * client, poolAddress, chainId,\n * tokenId: shortCallTokenId,\n * positionSize: 1000000000000000n,\n * targetDelta: 0n,\n * })\n *\n * // Open the hedge as a separate position with swapAtMint\n * const hedgeTokenId = builder\n * .addLoan({ tokenType: hedge.hedgeLeg.tokenType, strike: hedge.hedgeLeg.strike })\n * .build()\n *\n * await openPosition({ ..., tokenId: hedgeTokenId,\n * positionSize: hedge.hedgeAmount, swapAtMint: hedge.swapAtMint })\n * ```\n *\n * @param params - The parameters\n * @returns Delta hedge result with LegConfig (always a loan)\n */\nexport async function getDeltaHedgeParams(\n params: GetDeltaHedgeParamsInput,\n): Promise<DeltaHedgeResult> {\n const {\n client,\n poolAddress,\n chainId,\n tokenId,\n positionSize,\n targetDelta,\n currentDelta: providedCurrentDelta,\n asset: providedAsset,\n mintTick: providedMintTick,\n blockNumber,\n currentTick: providedCurrentTick,\n tickSpacing: providedTickSpacing,\n } = params\n\n // Validate: need either tokenId or (currentDelta + asset)\n const hasTokenId = tokenId !== undefined\n const hasDirectDelta = providedCurrentDelta !== undefined && providedAsset !== undefined\n\n if (!hasTokenId && !hasDirectDelta) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams requires either `tokenId` or both `currentDelta` and `asset`',\n )\n }\n\n // Validate simulateSwap and computeDeltaAtTick are provided together\n if ((params.simulateSwap !== undefined) !== (params.computeDeltaAtTick !== undefined)) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams: simulateSwap and computeDeltaAtTick must be provided together',\n )\n }\n\n // If both currentTick and tickSpacing are provided, skip the full getPool() call\n let currentTick: bigint\n let tickSpacing: bigint\n let poolMeta: BlockMeta\n\n if (providedCurrentTick !== undefined && providedTickSpacing !== undefined) {\n currentTick = providedCurrentTick\n tickSpacing = providedTickSpacing\n poolMeta =\n params._meta ??\n (await getBlockMeta({ client, blockNumber: blockNumber ?? (await client.getBlockNumber()) }))\n } else {\n const pool = await getPool({\n client,\n poolAddress,\n chainId,\n blockNumber,\n })\n currentTick = pool.currentTick\n tickSpacing = pool.tickSpacing\n poolMeta = pool._meta\n }\n\n // Determine primary asset and current delta\n let primaryAsset: bigint\n let currentDelta: bigint\n\n if (hasTokenId) {\n // Decode the tokenId to get legs\n const decoded = decodeTokenId(tokenId)\n primaryAsset = decoded.legs.length > 0 ? decoded.legs[0].asset : 0n\n\n // Use provided mintTick or default to currentTick\n const mintTick = providedMintTick ?? currentTick\n\n // Calculate position delta if not provided\n currentDelta =\n providedCurrentDelta ??\n calculatePositionDelta({\n legs: decoded.legs,\n currentTick,\n mintTick,\n positionSize: positionSize!,\n poolTickSpacing: tickSpacing,\n })\n } else {\n // Direct delta + asset mode (whole-portfolio hedging)\n if (providedAsset !== 0n && providedAsset !== 1n) {\n throw new PanopticValidationError(\n `getDeltaHedgeParams: asset must be 0n or 1n, got ${providedAsset}`,\n )\n }\n primaryAsset = providedAsset\n currentDelta = providedCurrentDelta!\n }\n\n // deltaAdjustment = targetDelta - currentDelta\n // Positive → need to add positive delta; Negative → need to add negative delta.\n const deltaAdjustment = targetDelta - currentDelta\n\n // Delta is in asset smallest units. A loan+swapAtMint of size X gives\n // effective delta ≈ ±X (in asset smallest units). So hedgeAmount = |deltaAdjustment|.\n const absDeltaAdjustment = deltaAdjustment < 0n ? -deltaAdjustment : deltaAdjustment\n let hedgeAmount = absDeltaAdjustment\n\n const numeraire = primaryAsset === 0n ? 1n : 0n\n\n // Both directions use a loan + swapAtMint. The tokenType determines direction:\n // deltaAdjustment > 0 (need +delta): loan numeraire → swap to asset → +asset exposure\n // deltaAdjustment < 0 (need −delta): loan asset → swap to numeraire → −asset exposure\n const needPositiveDelta = deltaAdjustment > 0n\n const hedgeTokenType = needPositiveDelta ? numeraire : primaryAsset\n\n const hedgeLeg: LegConfig = {\n asset: primaryAsset,\n optionRatio: 1n,\n isLong: false, // Always a loan\n tokenType: hedgeTokenType,\n strike: (currentTick / tickSpacing) * tickSpacing, // Round to tick spacing\n width: 0n, // Loan/credit indicator\n }\n\n // --- Simulation convergence loop ---\n const {\n simulateSwap,\n computeDeltaAtTick,\n totalPositionSize,\n maxSimIterations = 5,\n convergenceThresholdBps = 10n,\n } = params\n\n let simulationIterations = 0\n let simulatedTickAfter: bigint | undefined\n let converged = true\n\n if (simulateSwap && computeDeltaAtTick) {\n if (totalPositionSize === undefined || totalPositionSize === 0n) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams: totalPositionSize is required and must be > 0 when simulateSwap is provided',\n )\n }\n\n converged = false\n\n for (let i = 0; i < maxSimIterations; i++) {\n simulationIterations = i + 1\n\n const simResult = await simulateSwap(hedgeAmount, hedgeLeg)\n if (simResult == null) break\n\n simulatedTickAfter = simResult.tickAfter\n\n // Recompute portfolio delta at the post-swap tick\n const adjustedDelta = computeDeltaAtTick(simResult.tickAfter)\n const newAdjustment = targetDelta - adjustedDelta\n const newAmount = newAdjustment < 0n ? -newAdjustment : newAdjustment\n\n // Convergence check\n const sizeDelta = newAmount > hedgeAmount ? newAmount - hedgeAmount : hedgeAmount - newAmount\n const sizeChangeBps = (sizeDelta * 10000n) / totalPositionSize\n\n hedgeAmount = newAmount\n\n if (sizeChangeBps <= convergenceThresholdBps || sizeDelta === 0n) {\n converged = true\n break\n }\n }\n }\n\n return {\n hedgeLeg,\n hedgeAmount,\n hedgeType: 'loan',\n swapAtMint: true,\n currentDelta,\n targetDelta,\n deltaAdjustment,\n _meta: poolMeta,\n simulationIterations,\n simulatedTickAfter,\n converged,\n }\n}\n","/**\n * Collateral share price read for the Panoptic v2 SDK.\n *\n * Reads totalAssets and totalSupply from two CollateralTracker contracts\n * to compute share prices. Designed for APY calculations at historical blocks.\n *\n * @module v2/reads/collateralSharePrice\n */\n\nimport type { Address, Client } from 'viem'\nimport { ContractFunctionExecutionError } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\n\n/**\n * Raw share price data for a single collateral tracker.\n */\nexport interface CollateralSharePriceData {\n totalAssets: bigint\n totalSupply: bigint\n}\n\n/**\n * Get totalAssets and totalSupply for two CollateralTracker contracts in a single multicall.\n *\n * Consumers can compute share price as `totalAssets / totalSupply` using their\n * preferred precision library (e.g. Decimal.js).\n *\n * If the collateral tracker reverts (e.g. uninitialized), returns zeros.\n *\n * @param collateralAddresses - Tuple of [token0 tracker, token1 tracker] addresses\n * @param blockNumber - Block number to query at\n * @param client - viem Client\n * @returns Tuple of raw share price data\n */\nexport async function getCollateralSharePrices(\n collateralAddresses: [Address, Address],\n blockNumber: bigint,\n client: Client,\n): Promise<[CollateralSharePriceData, CollateralSharePriceData]> {\n try {\n const results = await multicall(client, {\n contracts: [\n {\n address: collateralAddresses[0],\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets',\n },\n {\n address: collateralAddresses[0],\n abi: collateralTrackerV2Abi,\n functionName: 'totalSupply',\n },\n {\n address: collateralAddresses[1],\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets',\n },\n {\n address: collateralAddresses[1],\n abi: collateralTrackerV2Abi,\n functionName: 'totalSupply',\n },\n ],\n blockNumber,\n allowFailure: false,\n })\n\n const [assets0, supply0, assets1, supply1] = results\n\n return [\n { totalAssets: assets0, totalSupply: supply0 },\n { totalAssets: assets1, totalSupply: supply1 },\n ]\n } catch (e: unknown) {\n if (e instanceof ContractFunctionExecutionError) {\n return [\n { totalAssets: 0n, totalSupply: 0n },\n { totalAssets: 0n, totalSupply: 0n },\n ]\n }\n throw e\n }\n}\n","/**\n * Batch read of CollateralTracker.totalAssets() for multiple trackers.\n *\n * @module v2/reads/collateralTotalAssets\n */\n\nimport type { Address, Client } from 'viem'\nimport { getAddress, zeroAddress } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\n\n/**\n * Get totalAssets for multiple CollateralTracker contracts in a single multicall.\n *\n * @param client - viem Client\n * @param collateralTrackerAddresses - Array of CollateralTracker addresses\n * @param chainId - Chain ID (for multicall routing)\n * @param blockNumber - Optional block number for historical queries\n * @returns Array of totalAssets (bigint) in the same order as input addresses\n */\nexport async function getCollateralTotalAssetsBatch(\n client: Client,\n collateralTrackerAddresses: Address[],\n chainId: number,\n blockNumber?: bigint,\n): Promise<bigint[]> {\n if (collateralTrackerAddresses.length === 0) return []\n\n try {\n const contracts = collateralTrackerAddresses.map((address) => ({\n address: getAddress(address ?? zeroAddress),\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets' as const,\n chainId,\n }))\n\n const results = await multicall(client, {\n contracts,\n blockNumber,\n allowFailure: false,\n })\n\n return results.map((result) => BigInt(result ?? 0))\n } catch (error) {\n console.error('Error reading collateral total assets:', error)\n return collateralTrackerAddresses.map(() => 0n)\n }\n}\n","/**\n * Account buying power read function for the Panoptic v2 SDK.\n *\n * Sources gross collateral from `CollateralTracker.assetsOf` and per-position\n * required margin from `PanopticPool.getFullPositionsData.collateralRequirements[]`,\n * cross-converted to both token denominations at the current tick.\n *\n * This replaces the prior `PanopticQuery.checkCollateral` (3-arg, oracle-ticks\n * overload) implementation that netted loan tokenId debt out of the balance\n * and excluded loans from required-collateral, causing buying-power readouts\n * to be wildly wrong for any account that had borrowed.\n *\n * @module v2/reads/buyingPower\n */\n\nimport type { Address, Client } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { tickToSqrtPriceX96 } from '../formatters/tick'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { type MulticallBlockCall, readBlockAndAggregate, requireReturnData } from './multicallBlock'\n\nconst Q128 = 1n << 128n\n\nfunction convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\nfunction convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Parameters for getAccountBuyingPower.\n */\nexport interface GetAccountBuyingPowerParams {\n /** viem Client (PublicClient or basic Client with transport) */\n client: Client\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** PanopticQuery address (kept for backwards compatibility; unused). */\n queryAddress?: Address\n /**\n * Optional pre-fetched collateral tracker addresses (saves an RPC).\n * If omitted, they are fetched from the pool.\n */\n collateralAddresses?: { collateralToken0: Address; collateralToken1: Address }\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips block metadata fetch) */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getAccountBuyingPower.\n *\n * Both per-token values are the **gross** account total cross-converted\n * into the respective single-token denomination at the current tick:\n * - `collateralBalance0` / `requiredCollateral0` are in token0 units\n * - `collateralBalance1` / `requiredCollateral1` are in token1 units\n */\nexport interface AccountBuyingPower {\n /** Gross collateral (deposits + borrowed shares), denominated in token0 */\n collateralBalance0: bigint\n /** Sum of per-position collateral requirements, denominated in token0 */\n requiredCollateral0: bigint\n /** Gross collateral (deposits + borrowed shares), denominated in token1 */\n collateralBalance1: bigint\n /** Sum of per-position collateral requirements, denominated in token1 */\n requiredCollateral1: bigint\n /** Block metadata for the Multicall3 aggregate read */\n _meta: BlockMeta\n}\n\n/**\n * Get account-level buying power.\n *\n * Uses {@link https://github.com/panoptic-xyz CollateralTracker.assetsOf} for\n * gross collateral and `PanopticPool.getFullPositionsData.collateralRequirements[]`\n * for the per-position required margin — so loan tokenIds (width=0 shorts)\n * contribute to the requirement instead of being netted out of the balance.\n *\n * Accepts a plain viem `Client` (not just `PublicClient`) so it works with wagmi's\n * `useClient()` without needing a cast.\n *\n * @param params - The parameters\n * @returns Account buying power data with optional block metadata\n */\nexport async function getAccountBuyingPower(\n params: GetAccountBuyingPowerParams,\n): Promise<AccountBuyingPower> {\n const { client, poolAddress, account, tokenIds } = params\n const blockNumber = params.blockNumber ?? params._meta?.blockNumber\n\n // Resolve collateral tracker addresses (immutable; cache-friendly).\n let collateralToken0: Address\n let collateralToken1: Address\n if (params.collateralAddresses) {\n collateralToken0 = params.collateralAddresses.collateralToken0\n collateralToken1 = params.collateralAddresses.collateralToken1\n } else {\n const addrs = await multicall(client, {\n contracts: [\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken0' },\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken1' },\n ],\n blockNumber,\n allowFailure: false,\n })\n collateralToken0 = addrs[0]\n collateralToken1 = addrs[1]\n }\n\n const calls: MulticallBlockCall[] = [\n {\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n }),\n },\n {\n target: collateralToken0,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n {\n target: collateralToken1,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n ]\n\n const positionDataIndex = tokenIds.length > 0 ? calls.length : null\n if (positionDataIndex !== null) {\n calls.push({\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, tokenIds],\n }),\n })\n }\n\n const { _meta, results } = await readBlockAndAggregate({ client, calls, blockNumber })\n\n const currentTickResult = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n data: requireReturnData(results, 0, 'PanopticPool.getCurrentTick'),\n })\n const assets0 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 1, 'CollateralTracker.assetsOf token0'),\n })\n const assets1 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 2, 'CollateralTracker.assetsOf token1'),\n })\n const currentTick = BigInt(currentTickResult)\n const positionDataResult =\n positionDataIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data: requireReturnData(results, positionDataIndex, 'PanopticPool.getFullPositionsData'),\n }) as readonly [bigint, bigint, readonly bigint[], readonly bigint[], readonly bigint[]])\n\n // Sum collateral requirements across positions, per token.\n let required0Native = 0n\n let required1Native = 0n\n if (positionDataResult) {\n const collateralRequirements = positionDataResult[3]\n for (const packed of collateralRequirements) {\n const decoded = decodeLeftRightUnsigned(packed)\n required0Native += decoded.right // token0\n required1Native += decoded.left // token1\n }\n }\n\n // Cross-convert into each single-token denomination at current tick.\n const sqrtPriceX96 = tickToSqrtPriceX96(currentTick)\n const collateralBalance0 = assets0 + convert1to0(assets1, sqrtPriceX96)\n const requiredCollateral0 = required0Native + convert1to0(required1Native, sqrtPriceX96)\n const collateralBalance1 = assets1 + convert0to1(assets0, sqrtPriceX96)\n const requiredCollateral1 = required1Native + convert0to1(required0Native, sqrtPriceX96)\n\n return {\n collateralBalance0,\n requiredCollateral0,\n collateralBalance1,\n requiredCollateral1,\n _meta,\n }\n}\n","/**\n * Shared construction for dispatches wrapped in a temporary width=0 **credit**\n * leg, used to move token flow from one collateral token to the other inside a\n * single `dispatch()`.\n *\n * A credit rather than a loan: a credit pays into the pool instead of borrowing\n * from it, so it requires zero buying power, never touches `s_assetsInAMM`, and\n * can never be capped by a collateral tracker's utilization.\n *\n * @module v2/simulations/creditWrap\n */\n\nimport type { BatchDispatchArgs } from '../batch/types'\nimport type { TickAndSpreadLimits } from '../writes/position'\n\n/**\n * Pre-encoded `dispatch()` arguments a credit wrap is applied to.\n *\n * Alias of {@link BatchDispatchArgs} — the two are the same concept.\n */\nexport type DispatchIntent = BatchDispatchArgs\n\n/**\n * Which side of the swap is exact.\n *\n * - `exact-out`: the credit **sources** a known amount of its token, paying a\n * swapped amount of the counter-token. Mint carries `swapAtMint=true`.\n * - `exact-in`: the credit **sells** a known amount of its token, receiving a\n * swapped amount of the counter-token. Burn carries `swapAtMint=true`.\n */\nexport type CreditWrapDirection = 'exact-in' | 'exact-out'\n\n/**\n * Where the two credit legs sit relative to the user's own operations.\n *\n * - `straddle`: mint first, user ops, burn last. Required for `exact-out`, where\n * the sourced token must be available while the user's ops run.\n * - `append`: both legs after the user's ops. Required for `exact-in`, where the\n * token being sold does not exist until those ops have run.\n */\nexport type CreditWrapPlacement = 'append' | 'straddle'\n\nexport interface BuildCreditWrappedDispatchParams {\n dispatch: DispatchIntent\n /** The temporary width=0 credit leg. */\n creditTokenId: bigint\n /** Size of the mint leg. The burn leg always passes `0n` (= burn all). */\n creditPositionSize: bigint\n tickLimitLow: bigint\n tickLimitHigh: bigint\n direction: CreditWrapDirection\n placement: CreditWrapPlacement\n}\n\n/**\n * Wrap a dispatch with a temporary credit leg that is opened and closed in the\n * same transaction, netting to a swap.\n *\n * `swapAtMint` is not a calldata flag — it is the ORDER of the tick-limit pair:\n * descending `[high, low]` turns the swap on, ascending `[low, high]` leaves it\n * off. Exactly one of the two legs carries it, and which one is what makes the\n * swap exact-in vs exact-out.\n */\nexport function buildCreditWrappedDispatch(\n params: BuildCreditWrappedDispatchParams,\n): DispatchIntent {\n const { dispatch, creditTokenId, creditPositionSize, direction, placement } = params\n const low =\n params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitLow : params.tickLimitHigh\n const high =\n params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitHigh : params.tickLimitLow\n\n const swapping: TickAndSpreadLimits = [high, low, 0n]\n const notSwapping: TickAndSpreadLimits = [low, high, 0n]\n const mintLimits = direction === 'exact-out' ? swapping : notSwapping\n const burnLimits = direction === 'exact-out' ? notSwapping : swapping\n\n const wrapped: DispatchIntent = {\n positionIdList:\n placement === 'straddle'\n ? [creditTokenId, ...dispatch.positionIdList, creditTokenId]\n : [...dispatch.positionIdList, creditTokenId, creditTokenId],\n finalPositionIdList: [...dispatch.finalPositionIdList],\n positionSizes:\n placement === 'straddle'\n ? [creditPositionSize, ...dispatch.positionSizes, 0n]\n : [...dispatch.positionSizes, creditPositionSize, 0n],\n tickAndSpreadLimits:\n placement === 'straddle'\n ? [mintLimits, ...dispatch.tickAndSpreadLimits, burnLimits]\n : [...dispatch.tickAndSpreadLimits, mintLimits, burnLimits],\n usePremiaAsCollateral: dispatch.usePremiaAsCollateral,\n builderCode: dispatch.builderCode,\n }\n return wrapped\n}\n","/**\n * Dispatch simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateDispatch\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { DispatchSimulation, SimulationResult, TokenFlow } from '../types'\nimport type { TickAndSpreadLimits } from '../writes/position'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating dispatch.\n */\nexport interface SimulateDispatchParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /**\n * Operation list passed to `dispatch()` — one tokenId per batch item, in\n * operation order. Mints reference NEW tokenIds the user doesn't yet own,\n * so this list is NOT safe to read against pre-dispatch storage.\n */\n positionIdList: bigint[]\n /** Final position ID list after operations */\n finalPositionIdList: bigint[]\n /**\n * The user's actual on-chain `positionIdList` BEFORE dispatch. Required to\n * populate `preMarginExcess0/1` (read via a pre-dispatch\n * `getFullPositionsData` chained in the same multicall). When omitted,\n * `preMarginExcess0/1` are returned as `null`.\n */\n existingPositionIdList?: bigint[]\n /** Position sizes for each operation */\n positionSizes: bigint[]\n /** Tick and spread limits for each operation */\n tickAndSpreadLimits: TickAndSpreadLimits[]\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Builder code */\n builderCode?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a raw dispatch operation.\n *\n * Uses PanopticPool.multicall with getAssetsOf-dispatch-getAssetsOf pattern\n * to measure exact collateral asset movements.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with dispatch data or error\n */\nexport async function simulateDispatch(\n params: SimulateDispatchParams,\n): Promise<SimulationResult<DispatchSimulation>> {\n const {\n client,\n poolAddress,\n account,\n positionIdList,\n finalPositionIdList,\n positionSizes,\n tickAndSpreadLimits,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n existingPositionIdList,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Encode dispatch call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n positionIdList,\n finalPositionIdList,\n positionSizes,\n tickAndSpreadLimits.map(\n (t) => [Number(t[0]), Number(t[1]), Number(t[2])] as readonly [number, number, number],\n ),\n usePremiaAsCollateral,\n builderCode,\n ],\n })\n\n // Encode getFullPositionsData against the pre-dispatch (caller-supplied\n // existing list) and post-dispatch (finalPositionIdList) position lists.\n // Running both in the same multicall — pre-call before dispatch, post-call\n // after — lets the simulation report margin excess (= assets - required\n // collateral) on both sides atomically. Required collateral is summed\n // across the per-position LeftRightUnsigned entries.\n //\n // The pre-call uses `existingPositionIdList` (the user's actual storage\n // list), NOT `positionIdList` (the operation list, which contains\n // not-yet-minted tokenIds and would revert with PositionNotOwned).\n const preFullPositionsCallData =\n existingPositionIdList !== undefined\n ? encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, existingPositionIdList],\n })\n : undefined\n const postFullPositionsCallData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, finalPositionIdList],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n preCallData: preFullPositionsCallData ? [preFullPositionsCallData] : undefined,\n postCallData: [postFullPositionsCallData],\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Determine which positions were created/closed by diffing the post-dispatch\n // list against the pre-dispatch on-chain snapshot. `positionIdList` is the\n // operation list (which contains not-yet-minted tokenIds and excludes\n // unaffected pre-existing ones), so it can't be used as the \"before\" set.\n const preSnapshot = existingPositionIdList ?? []\n const positionsCreated = finalPositionIdList.filter((id) => !preSnapshot.includes(id))\n const positionsClosed = preSnapshot.filter((id) => !finalPositionIdList.includes(id))\n\n // Sum collateralRequirements across all entries from one\n // getFullPositionsData multicall slot. Each entry is a LeftRightUnsigned\n // packed as right=token0, left=token1. Returns null on decode failure so\n // callers fall back gracefully (the type is bigint | null).\n const sumCollateralReq = (data: Hex | undefined): { token0: bigint; token1: bigint } | null => {\n if (!data) return null\n try {\n const decoded = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data,\n })\n const reqs = decoded[3] // collateralRequirements\n let token0 = 0n\n let token1 = 0n\n for (const packed of reqs) {\n const r = decodeLeftRightUnsigned(packed)\n token0 += r.right\n token1 += r.left\n }\n return { token0, token1 }\n } catch {\n return null\n }\n }\n\n const preReq = sumCollateralReq(flowResult.preCallResults?.[0])\n const postReq = sumCollateralReq(flowResult.postCallResults?.[0])\n\n const _meta = await metaPromise\n\n // Build simulation result with actual token flow data\n const data: DispatchSimulation = {\n netAmount0: tokenFlow.delta0,\n netAmount1: tokenFlow.delta1,\n positionsCreated,\n positionsClosed,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n preMarginExcess0: preReq ? tokenFlow.balanceBefore0 - preReq.token0 : null,\n preMarginExcess1: preReq ? tokenFlow.balanceBefore1 - preReq.token1 : null,\n postMarginExcess0: postReq ? tokenFlow.balanceAfter0 - postReq.token0 : null,\n postMarginExcess1: postReq ? tokenFlow.balanceAfter1 - postReq.token1 : null,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","import type { Address, PublicClient } from 'viem'\n\nimport { NotEnoughTokensError, PanopticError, parsePanopticError } from '../errors'\nimport { getPool } from '../reads/pool'\nimport type { BlockMeta, DispatchSimulation, SimulationResult, TokenFlow } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport { buildUniqueCredit } from '../writes/loanUtils'\nimport { type DispatchIntent, buildCreditWrappedDispatch } from './creditWrap'\nimport { simulateDispatch } from './simulateDispatch'\n\nconst BPS_DENOMINATOR = 10_000n\nconst MAX_RECOVERY_QUOTE_ATTEMPTS = 8\n\nexport type { DispatchIntent }\n\nexport interface TokenShortfallRecoveryQuoteParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n chainId: bigint\n existingPositionIds: bigint[]\n dispatch: DispatchIntent\n error: unknown\n /**\n * Slippage tolerance for the recovery swap, in **basis points** (1% = 100).\n * Applied to `estimatedAmountIn` to produce `maximumAmountIn`.\n * Values above `10_000` (100%) are rejected as `invalid-slippage`.\n */\n slippageBps: bigint\n /**\n * Price bound for the temporary credit legs. Defaults to the full tick range —\n * the recovery swap is protected economically by `maximumAmountIn`, not by a\n * price band, and the user's own operations keep their own limits.\n */\n tickLimitLow?: bigint\n /** See {@link TokenShortfallRecoveryQuoteParams.tickLimitLow}. */\n tickLimitHigh?: bigint\n blockNumber?: bigint\n}\n\nexport interface TokenShortfallRecoveryQuote {\n tokenIn: Address\n tokenOut: Address\n /**\n * Exact amount of `tokenOut` the temporary credit sources. Covers the whole\n * dispatch, not just the first charge that reverted — a batch charges\n * commission/premia per operation, so the total needed is usually larger\n * than the `assetsRequested - assetBalance` of the first failure.\n */\n amountOut: bigint\n estimatedAmountIn: bigint\n maximumAmountIn: bigint\n slippageBps: bigint\n /**\n * Signed net change of `tokenIn` across the ENTIRE wrapped transaction —\n * the user's own operations plus the recovery swap. This is what a wallet\n * simulation shows, and it is not the same as `-estimatedAmountIn`, which\n * prices the swap leg alone.\n */\n netTokenInChange: bigint\n /** Signed net change of `tokenOut` across the entire wrapped transaction. */\n netTokenOutChange: bigint\n /** The temporary width=0 credit leg used to source the shortfall. */\n creditTokenId: bigint\n dispatch: DispatchIntent\n simulation: SimulationResult<DispatchSimulation> & { success: true }\n tokenFlow: TokenFlow\n _meta: BlockMeta\n}\n\nexport type TokenShortfallRecoveryUnavailableReason =\n | 'not-token-shortfall'\n | 'invalid-shortfall'\n | 'invalid-slippage'\n | 'unsupported-token'\n | 'invalid-tick-limits'\n | 'swap-unavailable'\n | 'recovery-unavailable'\n\nexport type TokenShortfallRecoveryResult =\n | { available: true; quote: TokenShortfallRecoveryQuote }\n | {\n available: false\n reason: TokenShortfallRecoveryUnavailableReason\n /** Human-readable description of the sub-step that failed, for diagnostics. */\n detail?: string\n error?: PanopticError\n }\n\nexport interface BuildTokenShortfallRecoveryDispatchParams {\n dispatch: DispatchIntent\n /** The temporary width=0 credit leg that sources the missing token. */\n creditTokenId: bigint\n creditPositionSize: bigint\n tickLimitLow: bigint\n tickLimitHigh: bigint\n}\n\n/**\n * Wrap a dispatch with a temporary credit leg that sources the shortfall.\n *\n * Exact-output construction: mint the credit with `swapAtMint=true` (paying a\n * swapped amount of the token the account has), run the user's operations, then\n * burn it with `swapAtMint=false` to receive exactly the missing token.\n *\n * A credit rather than a loan so the recovery is never capped by the shortfall\n * token's utilization — the case that fails today on a >94% utilized tracker.\n */\nexport function buildTokenShortfallRecoveryDispatch(\n params: BuildTokenShortfallRecoveryDispatchParams,\n): DispatchIntent {\n return buildCreditWrappedDispatch({ ...params, direction: 'exact-out', placement: 'straddle' })\n}\n\n/**\n * Extract a fully-decoded `NotEnoughTokens` revert from an arbitrary error.\n *\n * Returns `null` when the error is something else, or when only the 4-byte\n * selector could be matched (the parser's fallback path constructs the error\n * with undefined args, which is not actionable).\n */\nexport function getNotEnoughTokensError(error: unknown): NotEnoughTokensError | null {\n let candidate: NotEnoughTokensError | null = null\n if (error instanceof NotEnoughTokensError) {\n candidate = error\n } else {\n const parsed = parsePanopticError(error)\n if (parsed?.error instanceof NotEnoughTokensError) candidate = parsed.error\n }\n if (candidate === null) return null\n // Selector-only decodes yield undefined args at runtime despite the types.\n const args: Partial<\n Pick<NotEnoughTokensError, 'tokenAddress' | 'assetsRequested' | 'assetBalance'>\n > = candidate\n if (\n args.tokenAddress === undefined ||\n args.assetsRequested === undefined ||\n args.assetBalance === undefined\n ) {\n return null\n }\n return candidate\n}\n\nfunction maximumAmountIn(estimatedAmountIn: bigint, slippageBps: bigint): bigint {\n if (slippageBps < 0n) {\n throw new PanopticError('slippageBps must be non-negative')\n }\n return (\n (estimatedAmountIn * (BPS_DENOMINATOR + slippageBps) + BPS_DENOMINATOR - 1n) / BPS_DENOMINATOR\n )\n}\n\nfunction getInputAmount(tokenFlow: TokenFlow, tokenInIndex: 0n | 1n): bigint {\n const delta = tokenInIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n return delta < 0n ? -delta : delta\n}\n\nfunction getBalanceBefore(tokenFlow: TokenFlow, tokenIndex: 0n | 1n): bigint {\n return tokenIndex === 0n ? tokenFlow.balanceBefore0 : tokenFlow.balanceBefore1\n}\n\nfunction getOutputAmount(tokenFlow: TokenFlow, tokenOutIndex: 0n | 1n): bigint {\n const delta = tokenOutIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n return delta > 0n ? delta : 0n\n}\n\nexport async function quoteTokenShortfallRecovery(\n params: TokenShortfallRecoveryQuoteParams,\n): Promise<TokenShortfallRecoveryResult> {\n const shortfallError = getNotEnoughTokensError(params.error)\n if (shortfallError === null) {\n return { available: false, reason: 'not-token-shortfall' }\n }\n\n let amountOut = shortfallError.assetsRequested - shortfallError.assetBalance\n if (amountOut <= 0n) {\n return {\n available: false,\n reason: 'invalid-shortfall',\n detail: `requested=${shortfallError.assetsRequested} <= balance=${shortfallError.assetBalance}`,\n }\n }\n if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR) {\n return {\n available: false,\n reason: 'invalid-slippage',\n detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR}]`,\n }\n }\n // The credit legs default to the full tick range: the swap is bounded\n // economically by maximumAmountIn, and the user's own ops keep their limits.\n const tickLimitLow = params.tickLimitLow ?? MIN_TICK\n const tickLimitHigh = params.tickLimitHigh ?? MAX_TICK\n if (tickLimitLow >= tickLimitHigh) {\n return {\n available: false,\n reason: 'invalid-tick-limits',\n detail: `tickLimitLow=${tickLimitLow} >= tickLimitHigh=${tickLimitHigh}`,\n }\n }\n\n const targetBlockNumber = params.blockNumber ?? (await params.client.getBlockNumber())\n const pool = await getPool({\n client: params.client,\n poolAddress: params.poolAddress,\n chainId: params.chainId,\n blockNumber: targetBlockNumber,\n })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const normalizedShortfallToken = shortfallError.tokenAddress.toLowerCase()\n const isToken0Shortfall =\n normalizedShortfallToken === token0.toLowerCase() ||\n normalizedShortfallToken === pool.collateralTracker0.address.toLowerCase()\n const isToken1Shortfall =\n normalizedShortfallToken === token1.toLowerCase() ||\n normalizedShortfallToken === pool.collateralTracker1.address.toLowerCase()\n const tokenOutIndex = isToken0Shortfall ? 0n : isToken1Shortfall ? 1n : null\n if (tokenOutIndex === null) {\n return {\n available: false,\n reason: 'unsupported-token',\n detail: `${shortfallError.tokenAddress} is neither collateral token of ${params.poolAddress}`,\n }\n }\n\n const tokenInIndex = tokenOutIndex === 0n ? 1n : 0n\n const tokenOut = tokenOutIndex === 0n ? token0 : token1\n const tokenIn = tokenInIndex === 0n ? token0 : token1\n const collisionIds = Array.from(\n new Set([\n ...params.existingPositionIds,\n ...params.dispatch.positionIdList,\n ...params.dispatch.finalPositionIdList,\n ]),\n )\n for (let attempt = 0; attempt < MAX_RECOVERY_QUOTE_ATTEMPTS; attempt++) {\n // asset === tokenType === tokenOutIndex: the credit is denominated in the\n // token being sourced. Passing tokenInIndex as tokenType is the loan\n // convention and reverses the flow (pays the shortfall token instead of\n // receiving it).\n const credit = buildUniqueCredit(\n pool.poolId,\n tokenOutIndex,\n tokenOutIndex,\n pool.currentTick,\n pool.tickSpacing,\n collisionIds,\n amountOut,\n )\n const recoveredDispatch = buildTokenShortfallRecoveryDispatch({\n dispatch: params.dispatch,\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n })\n const swapDispatch = buildTokenShortfallRecoveryDispatch({\n dispatch: {\n positionIdList: [],\n finalPositionIdList: [...params.existingPositionIds],\n positionSizes: [],\n tickAndSpreadLimits: [],\n usePremiaAsCollateral: false,\n builderCode: 0n,\n },\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n })\n\n const swapSimulation = await simulateDispatch({\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n ...swapDispatch,\n blockNumber: targetBlockNumber,\n })\n if (!swapSimulation.success || swapSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: swapSimulation.success\n ? 'swap-only simulation returned no token flow'\n : `swap-only simulation reverted: ${swapSimulation.error.message}`,\n error: swapSimulation.success ? undefined : swapSimulation.error,\n }\n }\n const estimatedAmountIn = getInputAmount(swapSimulation.tokenFlow, tokenInIndex)\n const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps)\n const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex)\n const sourceBalance = getBalanceBefore(swapSimulation.tokenFlow, tokenInIndex)\n if (swapOutput < amountOut || sourceBalance < maxAmountIn) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail:\n swapOutput < amountOut\n ? `swap output ${swapOutput} < required ${amountOut}`\n : `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,\n error: new PanopticError('Insufficient source collateral for the recovery swap'),\n }\n }\n\n const recoverySimulation = await simulateDispatch({\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n ...recoveredDispatch,\n blockNumber: targetBlockNumber,\n })\n if (recoverySimulation.success) {\n if (recoverySimulation.tokenFlow !== undefined) {\n return {\n available: true,\n quote: {\n tokenIn,\n tokenOut,\n amountOut,\n estimatedAmountIn,\n maximumAmountIn: maxAmountIn,\n slippageBps: params.slippageBps,\n netTokenInChange:\n tokenInIndex === 0n\n ? recoverySimulation.tokenFlow.delta0\n : recoverySimulation.tokenFlow.delta1,\n netTokenOutChange:\n tokenOutIndex === 0n\n ? recoverySimulation.tokenFlow.delta0\n : recoverySimulation.tokenFlow.delta1,\n creditTokenId: credit.tokenId,\n dispatch: recoveredDispatch,\n simulation: {\n ...recoverySimulation,\n tokenFlow: recoverySimulation.tokenFlow,\n },\n tokenFlow: recoverySimulation.tokenFlow,\n _meta: recoverySimulation._meta,\n },\n }\n }\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: 'wrapped dispatch simulation returned no token flow',\n error: new PanopticError('Recovery simulation did not return token flow'),\n }\n }\n\n const remainingShortfall = getNotEnoughTokensError(recoverySimulation.error)\n if (\n remainingShortfall === null ||\n remainingShortfall.tokenAddress.toLowerCase() !== normalizedShortfallToken\n ) {\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: `wrapped dispatch reverted with a non-shortfall error: ${recoverySimulation.error.message}`,\n error: recoverySimulation.error,\n }\n }\n // Grow by the residual the contract just reported. If that residual is\n // non-positive (assetsRequested <= assetBalance, e.g. the shortfall moved to\n // a rounding/fee boundary the revert no longer quantifies), fall back to\n // reusing amountOut — i.e. DOUBLE the target each retry. Bounded by\n // MAX_RECOVERY_QUOTE_ATTEMPTS and by the source-balance check above, so a\n // runaway size fails as swap-unavailable rather than looping.\n const decodedShortfall = remainingShortfall.assetsRequested - remainingShortfall.assetBalance\n const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut\n amountOut += additionalAmountOut\n }\n\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: `still short after ${MAX_RECOVERY_QUOTE_ATTEMPTS} sizing attempts (last target ${amountOut})`,\n error: new PanopticError('Could not cover recovery swap costs within the quote attempt limit'),\n }\n}\n","/**\n * Open position preview — combines buying power check with open position simulation.\n *\n * @module v2/reads/openPositionPreview\n */\n\nimport type { Address, Client, PublicClient } from 'viem'\n\nimport type { NotEnoughTokensError } from '../errors'\nimport { AccountInsolventError } from '../errors'\nimport { parsePanopticError } from '../errors/parser'\nimport type { SimulateOpenPositionParams } from '../simulations/simulateOpenPosition'\nimport { simulateOpenPosition } from '../simulations/simulateOpenPosition'\nimport { getNotEnoughTokensError } from '../simulations/tokenShortfallRecovery'\nimport type { OpenPositionSimulation, SimulationResult } from '../types'\nimport type { AccountBuyingPower } from './buyingPower'\nimport { getAccountBuyingPower } from './buyingPower'\n\n/**\n * Parameters for getOpenPositionPreview.\n */\nexport interface GetOpenPositionPreviewParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Existing position IDs held by the account (before this mint) */\n existingPositionIds: bigint[]\n /** TokenId of position to open */\n tokenId: bigint\n /** Position size */\n positionSize: bigint\n /** PanopticQuery address */\n queryAddress: Address\n /** Lower tick limit */\n tickLimitLow: bigint\n /** Upper tick limit */\n tickLimitHigh: bigint\n /** Spread limit (default 0n) */\n spreadLimit?: bigint\n /** Whether to swap at mint */\n swapAtMint?: boolean\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Chain ID (for greeks calculation) */\n chainId?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Result of getOpenPositionPreview.\n */\nexport interface OpenPositionPreview {\n /** Current buying power (from checkCollateral on existing positions) */\n currentBuyingPower: AccountBuyingPower\n /** Simulation result (from dry-run dispatch) */\n simulation: SimulationResult<OpenPositionSimulation>\n /**\n * Whether the account has enough *buying power* for the position.\n *\n * False only for a genuine `AccountInsolvent` revert. A token shortfall is\n * reported separately via {@link OpenPositionPreview.tokenShortfall} — the two\n * have different remedies (lower the size vs. source the missing token), so\n * do not collapse them back into one flag.\n */\n isSolvent: boolean\n /**\n * Set when the mint reverted because one collateral tracker lacked tokens,\n * not because the account is short on margin. The account may hold plenty of\n * value in the *other* token, in which case a collateral swap resolves it.\n */\n tokenShortfall: NotEnoughTokensError | null\n /** Token 0 amount required (negative delta = deposit). Null if simulation failed. */\n amount0Required: bigint | null\n /** Token 1 amount required. Null if simulation failed. */\n amount1Required: bigint | null\n /** Collateral balance in token 0 after mint. Null if simulation failed. */\n postCollateral0: bigint | null\n /** Collateral balance in token 1 after mint. Null if simulation failed. */\n postCollateral1: bigint | null\n /** Post-mint collateral requirement in token0 (per-token, not cross-margined). Null if sim failed. */\n postMintCollateralReqToken0: bigint | null\n /** Post-mint collateral requirement in token1 (per-token, not cross-margined). Null if sim failed. */\n postMintCollateralReqToken1: bigint | null\n /**\n * Collateral requirement for the new position only (last entry of perPositionCollateralReqs).\n * Use this for \"Margin Used\" display — postMintCollateralReqToken0/1 includes existing positions too.\n * Null if simulation failed or perPositionCollateralReqs is empty.\n */\n newPositionCollateralReqToken0: bigint | null\n /** Collateral requirement for the new position only, token1. Null if sim failed. */\n newPositionCollateralReqToken1: bigint | null\n}\n\n/**\n * Get a preview of opening a position.\n *\n * Composes two calls:\n * 1. `getAccountBuyingPower` — current margin state for existing positions\n * 2. `simulateOpenPosition` — dry-run dispatch to check feasibility & token flows\n *\n * @param params - Preview parameters\n * @returns Preview with buying power, simulation result, and derived convenience fields\n */\nexport async function getOpenPositionPreview(\n params: GetOpenPositionPreviewParams,\n): Promise<OpenPositionPreview> {\n const {\n client,\n poolAddress,\n account,\n existingPositionIds,\n tokenId,\n positionSize,\n queryAddress,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit,\n swapAtMint,\n usePremiaAsCollateral,\n chainId,\n blockNumber,\n } = params\n\n // Run both calls in parallel\n const [currentBuyingPower, simulation] = await Promise.all([\n getAccountBuyingPower({\n client: client as Client,\n poolAddress,\n account,\n tokenIds: existingPositionIds,\n queryAddress,\n blockNumber,\n }),\n simulateOpenPosition({\n client,\n poolAddress,\n account,\n existingPositionIds,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit,\n swapAtMint,\n usePremiaAsCollateral,\n chainId,\n blockNumber,\n } satisfies SimulateOpenPositionParams),\n ])\n\n // Two distinct failures, kept apart because they have different remedies:\n // AccountInsolvent -> not enough buying power; the size must come down.\n // NotEnoughTokens -> one tracker is short tokens; the account may still be\n // well within its buying power, just holding the wrong\n // token, so sourcing it (swap / loan leg) resolves it.\n // Everything else (PriceBoundFail, EffectiveLiquidityAboveThreshold, …) is\n // neither, and must not read as a collateral problem.\n let isSolvent = true\n let tokenShortfall: NotEnoughTokensError | null = null\n if (!simulation.success) {\n const parsed = parsePanopticError(simulation.error)\n const err = parsed?.error ?? simulation.error\n isSolvent = !(err instanceof AccountInsolventError)\n tokenShortfall = getNotEnoughTokensError(err)\n }\n const data = simulation.success ? simulation.data : null\n\n return {\n currentBuyingPower,\n simulation,\n isSolvent,\n tokenShortfall,\n amount0Required: data?.amount0Required ?? null,\n amount1Required: data?.amount1Required ?? null,\n postCollateral0: data?.postCollateral0 ?? null,\n postCollateral1: data?.postCollateral1 ?? null,\n postMintCollateralReqToken0: data?.postMintCollateralReqToken0 ?? null,\n postMintCollateralReqToken1: data?.postMintCollateralReqToken1 ?? null,\n newPositionCollateralReqToken0:\n data?.perPositionCollateralReqs && data.perPositionCollateralReqs.length > 0\n ? (data.perPositionCollateralReqs[data.perPositionCollateralReqs.length - 1]?.token0 ??\n null)\n : null,\n newPositionCollateralReqToken1:\n data?.perPositionCollateralReqs && data.perPositionCollateralReqs.length > 0\n ? (data.perPositionCollateralReqs[data.perPositionCollateralReqs.length - 1]?.token1 ??\n null)\n : null,\n }\n}\n","/**\n * Read the native token (e.g. ETH) price in USD from a PanopticPool's on-chain tick.\n *\n * @module v2/reads/nativeTokenPrice\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { tickToPriceDecimalScaled } from '../formatters/tick'\n\nexport interface GetNativeTokenPriceParams {\n client: PublicClient\n /** Address of a PanopticPool deployed on a native/USD stablecoin underlying pool */\n panopticPoolAddress: Address\n /** Decimals of token0 in the underlying pool */\n token0Decimals: bigint\n /** Decimals of token1 in the underlying pool */\n token1Decimals: bigint\n /** Whether the native asset is token0 (true) or token1 (false) */\n nativeIsToken0: boolean\n}\n\n/**\n * Fetch the native token price in USD by reading `getCurrentTick()` from a\n * PanopticPool deployed on a native/stablecoin pair.\n *\n * @returns The price as a decimal string (e.g. \"2000.00\")\n */\nexport async function getNativeTokenPrice(params: GetNativeTokenPriceParams): Promise<string> {\n const { client, panopticPoolAddress, token0Decimals, token1Decimals, nativeIsToken0 } = params\n\n const currentTick = await client.readContract({\n address: panopticPoolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n })\n\n // tickToPriceDecimalScaled returns token0/token1 price (price of token0 denominated in token1).\n // If nativeIsToken0: price = USD per native (what we want)\n // If !nativeIsToken0: price = native per USD → invert by swapping decimals\n if (nativeIsToken0) {\n return tickToPriceDecimalScaled(BigInt(currentTick), token0Decimals, token1Decimals, 2n)\n } else {\n // Swap decimals to get the inverse price\n return tickToPriceDecimalScaled(BigInt(currentTick), token1Decimals, token0Decimals, 2n)\n }\n}\n","/**\n * Account trade history for the Panoptic v2 SDK.\n *\n * Fetches OptionMinted and OptionBurnt events filtered by account address\n * using indexed topic filtering for RPC efficiency (2 calls total).\n *\n * @module v2/reads/history\n */\n\nimport type { Address, Hash, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport type { BlockMeta } from '../types'\nimport { decodePositionBalance } from '../writes/utils'\n\n/**\n * A single trade (mint or burn) in the account's history.\n */\nexport interface AccountTrade {\n /** Whether this was a mint or burn */\n action: 'mint' | 'burn'\n /** TokenId of the position */\n tokenId: bigint\n /** Position size */\n positionSize: bigint\n /** Block number of the trade */\n blockNumber: bigint\n /** Transaction hash */\n transactionHash: Hash\n /** Log index within the block */\n logIndex: bigint\n /** Tick at mint (only for mints) */\n tickAtMint?: bigint\n /** Timestamp at mint in Unix seconds (only for mints) */\n timestampAtMint?: bigint\n /** Whether a swap occurred at mint (only for mints) */\n swapAtMint?: boolean\n /** Pool utilization for token 0 at mint (only for mints) */\n poolUtilization0?: bigint\n /** Pool utilization for token 1 at mint (only for mints) */\n poolUtilization1?: bigint\n /** Premia settled per leg on burn (only for burns) */\n premiaByLeg?: readonly [bigint, bigint, bigint, bigint]\n}\n\n/**\n * Account history result.\n */\nexport interface AccountHistory {\n /** All trades sorted by block number ascending, then log index */\n trades: AccountTrade[]\n /** Block metadata at query time */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getAccountHistory.\n */\nexport interface GetAccountHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address to fetch history for */\n account: Address\n /** Start block (default: 0n) */\n fromBlock?: bigint\n /** End block (default: latest) */\n toBlock?: bigint\n /** Optional block number for _meta (default: toBlock or latest) */\n blockNumber?: bigint\n}\n\n/**\n * Fetch trade history for an account on a specific pool.\n *\n * Uses indexed topic filtering on the `recipient` field of OptionMinted\n * and OptionBurnt events, resulting in exactly 2 RPC calls regardless\n * of the number of trades.\n *\n * @param params - Query parameters\n * @returns Account trade history sorted chronologically\n *\n * @example\n * ```typescript\n * const history = await getAccountHistory({\n * client,\n * poolAddress,\n * account: '0x...',\n * fromBlock: 18_000_000n,\n * })\n *\n * for (const trade of history.trades) {\n * console.log(`${trade.action} tokenId=${trade.tokenId} size=${trade.positionSize}`)\n * }\n * ```\n */\nexport async function getAccountHistory(params: GetAccountHistoryParams): Promise<AccountHistory> {\n const { client, poolAddress, account, fromBlock = 0n, toBlock, blockNumber } = params\n\n const effectiveToBlock = toBlock ?? blockNumber ?? (await client.getBlockNumber())\n const metaBlockNumber = blockNumber ?? effectiveToBlock\n\n // Fetch mints and burns in parallel — 2 RPC calls total.\n // Both events have `recipient` as indexed topic[1], so the RPC node\n // filters server-side via the topic hash.\n const [mintLogs, burnLogs, _meta] = await Promise.all([\n client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: 'OptionMinted',\n args: { recipient: account },\n fromBlock,\n toBlock: effectiveToBlock,\n }),\n client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: 'OptionBurnt',\n args: { recipient: account },\n fromBlock,\n toBlock: effectiveToBlock,\n }),\n getBlockMeta({ client, blockNumber: metaBlockNumber }),\n ])\n\n const trades: AccountTrade[] = []\n\n // Parse mints\n for (const log of mintLogs) {\n const args = log.args as {\n recipient: Address\n tokenId: bigint\n balanceData: bigint\n }\n const balance = decodePositionBalance(args.balanceData)\n trades.push({\n action: 'mint',\n tokenId: args.tokenId,\n positionSize: balance.positionSize,\n blockNumber: log.blockNumber!,\n transactionHash: log.transactionHash!,\n logIndex: BigInt(log.logIndex!),\n tickAtMint: balance.tickAtMint,\n timestampAtMint: balance.timestampAtMint,\n swapAtMint: balance.swapAtMint,\n poolUtilization0: balance.poolUtilization0,\n poolUtilization1: balance.poolUtilization1,\n })\n }\n\n // Parse burns\n for (const log of burnLogs) {\n const args = log.args as {\n recipient: Address\n tokenId: bigint\n positionSize: bigint\n premiaByLeg: readonly [bigint, bigint, bigint, bigint]\n }\n trades.push({\n action: 'burn',\n tokenId: args.tokenId,\n positionSize: args.positionSize,\n blockNumber: log.blockNumber!,\n transactionHash: log.transactionHash!,\n logIndex: BigInt(log.logIndex!),\n premiaByLeg: args.premiaByLeg,\n })\n }\n\n // Sort chronologically: by block number, then log index\n trades.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n return a.logIndex < b.logIndex ? -1 : 1\n })\n\n return { trades, _meta }\n}\n","/**\n * Historical Uniswap fee reads for the Panoptic v2 SDK.\n *\n * Standalone function for fetching Uniswap fee accrual across historical blocks.\n * Works with any Uniswap V3/V4 pool — no Panoptic pool required.\n *\n * Also used internally by getStreamiaHistory for the Uniswap fee component.\n *\n * @module v2/reads/uniswapFeeHistory\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { InvalidHistoryRangeError } from '../errors/sdk'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\nimport type { StreamiaLeg } from '../types/streamia'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A single snapshot of Uniswap fee data at a particular block. */\nexport interface UniswapFeeSnapshot {\n /** Resolved block number for this snapshot. */\n blockNumber: bigint\n /** Timestamp of the resolved block in Unix seconds. */\n blockTimestamp: bigint\n /** Uniswap fee delta from the first block in the series */\n fees: { token0: bigint; token1: bigint }\n}\n\n/** Result from getUniswapFeeHistory. */\nexport interface UniswapFeeHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: UniswapFeeSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n/** Parameters for getUniswapFeeHistory. */\nexport interface GetUniswapFeeHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Decoded legs with pre-computed liquidity */\n legs: StreamiaLeg[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n// ── Public function ────────────────────────────────────────────────────\n\n/**\n * Get historical Uniswap fee accrual for a set of liquidity legs across multiple blocks.\n *\n * Works with any Uniswap V3/V4 pool — no Panoptic pool required.\n * Returns fee deltas relative to the first block in the series.\n *\n * @param params - The parameters\n * @returns Fee snapshots at each block\n */\nexport async function getUniswapFeeHistory(\n params: GetUniswapFeeHistoryParams,\n): Promise<UniswapFeeHistoryResult> {\n const { client, blockNumbers, legs, poolConfig } = params\n\n // Validate legs\n for (const leg of legs) {\n if (leg.lowerTick >= leg.upperTick) {\n throw new InvalidHistoryRangeError(\n `Leg lowerTick (${leg.lowerTick}) must be < upperTick (${leg.upperTick})`,\n )\n }\n if (leg.liquidity <= 0n) {\n throw new InvalidHistoryRangeError(`Leg liquidity must be > 0, got ${leg.liquidity}`)\n }\n }\n\n if (blockNumbers.length === 0 || legs.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n const [blockData, blockMetadata, _meta] = await Promise.all([\n fetchUniswapFeeData(client, blockNumbers, legs, poolConfig),\n Promise.all(blockNumbers.map((blockNumber) => getBlockMeta({ client, blockNumber }))),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n let initialFees0: bigint | null = null\n let initialFees1: bigint | null = null\n\n const snapshots: UniswapFeeSnapshot[] = blockData.map((bd, i) => {\n const { total0, total1 } = computeUniswapFeesForBlock(bd, legs)\n\n if (initialFees0 === null) {\n initialFees0 = total0\n initialFees1 = total1\n }\n\n return {\n blockNumber: blockMetadata[i].blockNumber,\n blockTimestamp: blockMetadata[i].blockTimestamp,\n fees: {\n token0: total0 - initialFees0,\n token1: total1 - (initialFees1 as bigint),\n },\n }\n })\n\n return { snapshots, _meta }\n}\n\n// ── Internals (also used by streamiaHistory) ─────────────────────────\n\n/** Raw Uniswap data fetched for a single block. */\nexport interface UniswapBlockData {\n currentTick: number\n feeGrowthGlobal0: bigint\n feeGrowthGlobal1: bigint\n /** Map from tick number → { feeGrowthOutside0, feeGrowthOutside1 } */\n tickData: Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>\n}\n\n/**\n * Fetch Uniswap pool data for all blocks in parallel.\n * Globals (slot0, feeGrowthGlobal) are fetched ONCE per block, not per-leg.\n * Tick data is fetched for each unique tick across all legs.\n */\nexport async function fetchUniswapFeeData(\n client: PublicClient,\n blockNumbers: (bigint | undefined)[],\n legs: StreamiaLeg[],\n poolConfig: PoolVersionConfig,\n): Promise<UniswapBlockData[]> {\n const uniqueTickSet = new Set<number>()\n for (const leg of legs) {\n uniqueTickSet.add(leg.lowerTick)\n uniqueTickSet.add(leg.upperTick)\n }\n const uniqueTicks = [...uniqueTickSet].sort((a, b) => a - b)\n\n const blockPromises = blockNumbers.map((bn) =>\n fetchUniswapBlockSnapshot(client, bn, uniqueTicks, poolConfig),\n )\n\n return Promise.all(blockPromises)\n}\n\n/**\n * Compute total Uniswap fees for all legs at a single block, using the\n * standard Uniswap V3 fee accumulation formula.\n */\nexport function computeUniswapFeesForBlock(\n blockData: UniswapBlockData,\n legs: StreamiaLeg[],\n): { total0: bigint; total1: bigint } {\n let total0 = 0n\n let total1 = 0n\n\n for (const leg of legs) {\n const lower = blockData.tickData.get(leg.lowerTick)\n const upper = blockData.tickData.get(leg.upperTick)\n if (!lower || !upper) continue\n\n const { feeGrowthGlobal0, feeGrowthGlobal1, currentTick } = blockData\n\n const feesBelow0 =\n currentTick >= leg.lowerTick\n ? lower.feeGrowthOutside0\n : feeGrowthGlobal0 - lower.feeGrowthOutside0\n const feesBelow1 =\n currentTick >= leg.lowerTick\n ? lower.feeGrowthOutside1\n : feeGrowthGlobal1 - lower.feeGrowthOutside1\n\n const feesAbove0 =\n currentTick < leg.upperTick\n ? upper.feeGrowthOutside0\n : feeGrowthGlobal0 - upper.feeGrowthOutside0\n const feesAbove1 =\n currentTick < leg.upperTick\n ? upper.feeGrowthOutside1\n : feeGrowthGlobal1 - upper.feeGrowthOutside1\n\n const fees0 = ((feeGrowthGlobal0 - feesBelow0 - feesAbove0) * leg.liquidity) / (1n << 128n)\n const fees1 = ((feeGrowthGlobal1 - feesBelow1 - feesAbove1) * leg.liquidity) / (1n << 128n)\n\n total0 += fees0\n total1 += fees1\n }\n\n return { total0, total1 }\n}\n\n// ── Block snapshot fetchers ──────────────────────────────────────────\n\nasync function fetchUniswapBlockSnapshot(\n client: PublicClient,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n poolConfig: PoolVersionConfig,\n): Promise<UniswapBlockData> {\n if (poolConfig.version === 'v3') {\n return fetchV3BlockSnapshot(client, poolConfig.poolAddress, blockNumber, uniqueTicks)\n } else {\n return fetchV4BlockSnapshot(\n client,\n poolConfig.stateViewAddress,\n poolConfig.poolId,\n blockNumber,\n uniqueTicks,\n )\n }\n}\n\nasync function fetchV3BlockSnapshot(\n client: PublicClient,\n poolAddress: Address,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n): Promise<UniswapBlockData> {\n const contracts = [\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'slot0' as const },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'feeGrowthGlobal0X128' as const },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'feeGrowthGlobal1X128' as const },\n ...uniqueTicks.map((tick) => ({\n address: poolAddress,\n abi: uniswapV3PoolAbi,\n functionName: 'ticks' as const,\n args: [tick] as const,\n })),\n ]\n\n const results = await client.multicall({ contracts, blockNumber, allowFailure: false })\n\n const slot0Result = results[0] as readonly [\n bigint,\n number,\n number,\n number,\n number,\n number,\n boolean,\n ]\n const feeGrowthGlobal0 = results[1] as bigint\n const feeGrowthGlobal1 = results[2] as bigint\n\n const tickData = new Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>()\n for (let i = 0; i < uniqueTicks.length; i++) {\n const tickResult = results[3 + i] as readonly [\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n number,\n boolean,\n ]\n tickData.set(uniqueTicks[i], {\n feeGrowthOutside0: tickResult[2],\n feeGrowthOutside1: tickResult[3],\n })\n }\n\n return { currentTick: slot0Result[1], feeGrowthGlobal0, feeGrowthGlobal1, tickData }\n}\n\nasync function fetchV4BlockSnapshot(\n client: PublicClient,\n stateViewAddress: Address,\n poolId: `0x${string}`,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n): Promise<UniswapBlockData> {\n const contracts = [\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getSlot0' as const,\n args: [poolId] as const,\n },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getFeeGrowthGlobals' as const,\n args: [poolId] as const,\n },\n ...uniqueTicks.map((tick) => ({\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getTickInfo' as const,\n args: [poolId, tick] as const,\n })),\n ]\n\n const results = await client.multicall({ contracts, blockNumber, allowFailure: false })\n\n const slot0Result = results[0] as readonly [bigint, number, number, number]\n const feeGrowthResult = results[1] as readonly [bigint, bigint]\n\n const tickData = new Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>()\n for (let i = 0; i < uniqueTicks.length; i++) {\n const tickResult = results[2 + i] as readonly [bigint, bigint, bigint, bigint]\n tickData.set(uniqueTicks[i], {\n feeGrowthOutside0: tickResult[2],\n feeGrowthOutside1: tickResult[3],\n })\n }\n\n return {\n currentTick: slot0Result[1],\n feeGrowthGlobal0: feeGrowthResult[0],\n feeGrowthGlobal1: feeGrowthResult[1],\n tickData,\n }\n}\n","/**\n * Historical streamia (streaming premia) reads for the Panoptic v2 SDK.\n *\n * Fetches Panoptic premia and optionally Uniswap fee accrual across a series\n * of historical block numbers for a single position. Composes\n * getUniswapFeeHistory internally for the Uniswap fee component.\n *\n * @module v2/reads/streamiaHistory\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { InvalidHistoryRangeError } from '../errors/sdk'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\nimport type { StreamiaLeg } from '../types/streamia'\nimport { computeUniswapFeesForBlock, fetchUniswapFeeData } from './uniswapFeeHistory'\n\n// Re-export types that were originally defined here for backward compatibility\nexport type { PoolVersionConfig, V3PoolConfig, V4PoolConfig } from '../types/poolConfig'\nexport type { StreamiaLeg } from '../types/streamia'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A settled premia event, used to subtract already-settled amounts. */\nexport interface SettledEvent {\n /** Block at which settlement occurred */\n blockNumber: bigint\n /** Amount settled for token 0 */\n settled0: bigint\n /** Amount settled for token 1 */\n settled1: bigint\n}\n\n/** Parameters for getStreamiaHistory. */\nexport interface GetStreamiaHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool contract address */\n panopticPoolAddress: Address\n /** Account whose position to query */\n account: Address\n /** The encoded tokenId */\n tokenId: bigint\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Decoded legs with pre-computed liquidity */\n legs: StreamiaLeg[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Whether to include Uniswap fee data (default: true) */\n includeUniswapFees?: boolean\n /** Settled premia events to subtract from Panoptic premia (optional) */\n settledEvents?: SettledEvent[]\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n/** A single snapshot of streamia data at a particular block. */\nexport interface StreamiaSnapshot {\n /** Block number (undefined if queried as latest) */\n blockNumber: bigint | undefined\n /** Net Panoptic premia (short - long), after subtracting settled amounts */\n panopticPremia: { token0: bigint; token1: bigint }\n /** Uniswap fee delta from the first block in the series */\n uniswapFees: { token0: bigint; token1: bigint }\n}\n\n/** Result from getStreamiaHistory. */\nexport interface StreamiaHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: StreamiaSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n// 128-bit mask for LeftRight decoding\nconst MASK_128 = (1n << 128n) - 1n\n\n// ── Main function ──────────────────────────────────────────────────────\n\n/**\n * Get historical streamia data for a position across multiple blocks.\n *\n * @param params - The parameters\n * @returns Snapshots of Panoptic premia and Uniswap fee deltas at each block\n */\nexport async function getStreamiaHistory(\n params: GetStreamiaHistoryParams,\n): Promise<StreamiaHistoryResult> {\n const {\n client,\n panopticPoolAddress,\n account,\n tokenId,\n blockNumbers,\n legs,\n poolConfig,\n includeUniswapFees = true,\n settledEvents,\n } = params\n\n // Validate legs\n for (const leg of legs) {\n if (leg.lowerTick >= leg.upperTick) {\n throw new InvalidHistoryRangeError(\n `Leg lowerTick (${leg.lowerTick}) must be < upperTick (${leg.upperTick})`,\n )\n }\n if (leg.liquidity <= 0n) {\n throw new InvalidHistoryRangeError(`Leg liquidity must be > 0, got ${leg.liquidity}`)\n }\n }\n\n if (blockNumbers.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n // ── 1. Panoptic premia: one readContract per block ─────────────────\n const premiaRequests = blockNumbers.map((bn) =>\n client.readContract({\n address: panopticPoolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, [tokenId]],\n blockNumber: bn,\n }),\n )\n\n // ── 2. Uniswap fees (delegated to uniswapFeeHistory internals) ────\n const uniswapDataPromise =\n includeUniswapFees && legs.length > 0\n ? fetchUniswapFeeData(client, blockNumbers, legs, poolConfig)\n : undefined\n\n // ── 3. Fire all in parallel ────────────────────────────────────────\n const [premiaResults, uniswapData, _meta] = await Promise.all([\n Promise.all(premiaRequests),\n uniswapDataPromise ?? Promise.resolve(undefined),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n // ── 4. Pre-sort settled events for O(n+m) accumulation ─────────────\n const sortedSettled = settledEvents\n ? [...settledEvents].sort((a, b) => (a.blockNumber < b.blockNumber ? -1 : 1))\n : []\n\n // ── 5. Build snapshots ─────────────────────────────────────────────\n let settledIdx = 0\n let accSettled0 = 0n\n let accSettled1 = 0n\n\n let initialUniswapFees0: bigint | null = null\n let initialUniswapFees1: bigint | null = null\n\n const snapshots: StreamiaSnapshot[] = premiaResults.map((result, i) => {\n const bn = blockNumbers[i]\n\n const shortPacked = result[0]\n const longPacked = result[1]\n\n const short0 = shortPacked & MASK_128\n const short1 = shortPacked >> 128n\n const long0 = longPacked & MASK_128\n const long1 = longPacked >> 128n\n\n // Advance settled accumulator\n const effectiveBn = bn ?? BigInt(Number.MAX_SAFE_INTEGER)\n while (\n settledIdx < sortedSettled.length &&\n sortedSettled[settledIdx].blockNumber <= effectiveBn\n ) {\n accSettled0 += sortedSettled[settledIdx].settled0\n accSettled1 += sortedSettled[settledIdx].settled1\n settledIdx++\n }\n\n const premia0 = short0 - long0 - accSettled0\n const premia1 = short1 - long1 - accSettled1\n\n let uniswapFees0 = 0n\n let uniswapFees1 = 0n\n\n if (uniswapData) {\n const blockData = uniswapData[i]\n const { total0, total1 } = computeUniswapFeesForBlock(blockData, legs)\n\n if (initialUniswapFees0 === null) {\n initialUniswapFees0 = total0\n initialUniswapFees1 = total1\n }\n uniswapFees0 = total0 - initialUniswapFees0\n uniswapFees1 = total1 - (initialUniswapFees1 as bigint)\n }\n\n return {\n blockNumber: bn,\n panopticPremia: { token0: premia0, token1: premia1 },\n uniswapFees: { token0: uniswapFees0, token1: uniswapFees1 },\n }\n })\n\n return { snapshots, _meta }\n}\n","/**\n * Direct Uniswap V3 pool read — no Panoptic deployment required.\n *\n * @module v2/reads/uniswapPool\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { encodeAbiParameters, keccak256, zeroAddress } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticValidationError } from '../errors'\nimport type { BlockMeta } from '../types'\n\nconst erc20MetaAbi = [\n {\n type: 'function',\n name: 'symbol',\n inputs: [],\n outputs: [{ type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'name',\n inputs: [],\n outputs: [{ type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'decimals',\n inputs: [],\n outputs: [{ type: 'uint8' }],\n stateMutability: 'view',\n },\n] as const\n\nexport interface UniswapV3PoolToken {\n address: Address\n symbol: string\n name: string\n decimals: number\n}\n\nexport interface UniswapV3PoolInfo {\n poolAddress: Address\n token0: UniswapV3PoolToken\n token1: UniswapV3PoolToken\n /** Fee tier in hundredths of a bip (e.g. 500 = 0.05%) */\n fee: number\n tickSpacing: number\n currentTick: number\n sqrtPriceX96: bigint\n liquidity: bigint\n /**\n * Packed protocol fee from slot0: `feeProtocol1 << 4 | feeProtocol0`. Each\n * nibble `n` denotes a protocol fee of `1/n` of the swap fee (`0` = off).\n */\n feeProtocol: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV3PoolInfoParams {\n client: PublicClient\n poolAddress: Address\n}\n\n/**\n * Fetch core data for a Uniswap V3 pool directly from chain.\n *\n * Does NOT require a Panoptic deployment — works for any V3 pool address.\n */\nexport async function getUniswapV3PoolInfo(\n params: GetUniswapV3PoolInfoParams,\n): Promise<UniswapV3PoolInfo> {\n const { client, poolAddress } = params\n\n // Pin every read to the same block so pool state + token metadata are\n // self-consistent. Pool reads run first because token0/token1 are needed to\n // address the ERC20 metadata calls; the second multicall is pinned to the\n // same block as the first.\n const _meta = await getBlockMeta({ client })\n\n const [slot0, fee, tickSpacing, token0Addr, token1Addr, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'slot0' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'fee' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'tickSpacing' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'token0' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'token1' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'liquidity' },\n ],\n })\n\n const [t0Symbol, t0Name, t0Decimals, t1Symbol, t1Name, t1Decimals] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'symbol' },\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'name' },\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'decimals' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'symbol' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'name' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'decimals' },\n ],\n })\n\n return {\n poolAddress,\n token0: {\n address: token0Addr,\n symbol: t0Symbol,\n name: t0Name,\n decimals: Number(t0Decimals),\n },\n token1: {\n address: token1Addr,\n symbol: t1Symbol,\n name: t1Name,\n decimals: Number(t1Decimals),\n },\n fee: Number(fee),\n tickSpacing: Number(tickSpacing),\n currentTick: Number(slot0[1]),\n sqrtPriceX96: slot0[0],\n liquidity,\n feeProtocol: BigInt(slot0[5]),\n _meta,\n }\n}\n\nexport interface UniswapV3Liquidities {\n ticks: bigint[]\n liquidityNets: bigint[]\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV3PoolLiquiditiesParams {\n client: PublicClient\n /** Uniswap V3 pool address */\n poolAddress: Address\n /** PanopticQuery address — must expose the public `getTickNetsV3` overload */\n queryAddress: Address\n /** Center tick of the range to scan */\n startTick: number\n /** Number of ticks on each side of startTick to scan */\n nTicks: bigint\n}\n\n/** Absolute Uniswap V3/V4 tick bounds. */\nconst TICK_MIN = -887272\nconst TICK_MAX = 887272\n\n/**\n * Clamp `nTicks` so the scan range\n * [scaled(startTick) − nTicks·tickSpacing, scaled(startTick) + nTicks·tickSpacing]\n * stays within [TICK_MIN, TICK_MAX]. Required because PanopticQuery's\n * getTickNetsV3/V4 revert with \"Tick out of bounds\" otherwise.\n */\nfunction clampNTicks(startTick: number, tickSpacing: number, nTicks: bigint): bigint {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new PanopticValidationError(\n `clampNTicks: tickSpacing must be a positive integer, got ${tickSpacing}`,\n )\n }\n const scaled = Math.trunc(startTick / tickSpacing) * tickSpacing\n const maxUp = Math.floor((TICK_MAX - scaled) / tickSpacing)\n const maxDown = Math.floor((scaled - TICK_MIN) / tickSpacing)\n const safe = BigInt(Math.max(0, Math.min(maxUp, maxDown)))\n return nTicks < safe ? nTicks : safe\n}\n\n/**\n * Fetch cumulative liquidity distribution for a Uniswap V3 pool via\n * `PanopticQuery.getTickNetsV3`. Does NOT require a Panoptic market to exist\n * for the pool — only a deployed PanopticQuery on the chain.\n */\nexport async function getUniswapV3PoolLiquidities(\n params: GetUniswapV3PoolLiquiditiesParams,\n): Promise<UniswapV3Liquidities> {\n const { client, poolAddress, queryAddress, startTick, nTicks } = params\n\n // We don't know tickSpacing here; PanopticQuery reads it from the pool.\n // For safety, clamp against the worst case (tickSpacing = 1).\n const safeN = clampNTicks(startTick, 1, nTicks)\n\n // Pin the read to a specific block so the returned ticks/liquidityNets\n // are consistent with the _meta we hand back.\n const _meta = await getBlockMeta({ client })\n const [ticks, liquidityNets] = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNetsV3',\n args: [poolAddress, startTick, safeN],\n blockNumber: _meta.blockNumber,\n })\n\n return {\n ticks: [...ticks],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n\n// ============================================================================\n// V4\n// ============================================================================\n\nexport interface UniswapV4PoolKey {\n currency0: Address\n currency1: Address\n /** Fee in hundredths of a bip (e.g. 500 = 0.05%) */\n fee: number\n tickSpacing: number\n hooks: Address\n}\n\nconst POOL_KEY_ABI_PARAMS = [\n {\n type: 'tuple',\n components: [\n { name: 'currency0', type: 'address' },\n { name: 'currency1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickSpacing', type: 'int24' },\n { name: 'hooks', type: 'address' },\n ],\n },\n] as const\n\n/** Compute the v4 poolId from a PoolKey: `keccak256(abi.encode(poolKey))`. */\nexport function computeV4PoolId(poolKey: UniswapV4PoolKey): Hex {\n return keccak256(\n encodeAbiParameters(POOL_KEY_ABI_PARAMS, [\n {\n currency0: poolKey.currency0,\n currency1: poolKey.currency1,\n fee: poolKey.fee,\n tickSpacing: poolKey.tickSpacing,\n hooks: poolKey.hooks,\n },\n ]),\n )\n}\n\nexport interface ResolveUniswapV4PoolKeyParams {\n client: PublicClient\n /** Uniswap V4 PoolManager address */\n poolManager: Address\n /** The bytes32 poolId hash */\n poolId: Hex\n /** Lower bound block for the scan (defaults to 0n) */\n fromBlock?: bigint\n /**\n * Per-request block range. Many RPCs cap getLogs at 10k/50k blocks;\n * defaults to 9_500 to stay under common limits.\n */\n chunkSize?: bigint\n /**\n * Number of chunked getLogs requests fired in parallel per batch.\n * Higher = faster but more likely to trip RPC rate limits. Default 8.\n */\n concurrency?: number\n}\n\n/**\n * Resolve a V4 PoolKey from its poolId by scanning `Initialize` event logs\n * on the PoolManager, filtered on the indexed `id` topic.\n *\n * Walks backwards from the latest block in `chunkSize` increments to\n * accommodate RPCs that cap getLogs ranges. Chunks are fired in parallel\n * batches of `concurrency` to keep wall-clock time low; returns as soon as\n * any batch produces a match. Throws if no event is found or if the\n * recomputed poolId does not match the queried one.\n */\nexport async function resolveUniswapV4PoolKey(\n _params: ResolveUniswapV4PoolKeyParams,\n): Promise<UniswapV4PoolKey> {\n // Disabled to save on RPC costs — the Initialize-event scan over the full\n // PoolManager history can issue dozens of eth_getLogs requests per\n // first-load resolution. Re-enable by uncommenting the body below.\n throw new PanopticValidationError(\n 'resolveUniswapV4PoolKey is disabled. ' +\n 'Resolve the V4 PoolKey via your indexer (e.g. Ponder) and pass it to getUniswapV4PoolInfo directly.',\n )\n\n /*\n const {\n client,\n poolManager,\n poolId,\n fromBlock = 0n,\n chunkSize = 9_500n,\n concurrency = 8,\n } = _params\n\n const latest = await client.getBlockNumber()\n\n // Pre-compute all chunk ranges, walking backwards.\n const ranges: Array<{ from: bigint; to: bigint }> = []\n let to = latest\n while (to >= fromBlock) {\n const from = to - chunkSize + 1n > fromBlock ? to - chunkSize + 1n : fromBlock\n ranges.push({ from, to })\n if (from === fromBlock) break\n to = from - 1n\n }\n\n let foundLogs: Awaited<ReturnType<PublicClient['getLogs']>> = []\n\n for (let i = 0; i < ranges.length; i += concurrency) {\n const batch = ranges.slice(i, i + concurrency)\n const results = await Promise.all(\n batch.map((r) =>\n client.getLogs({\n address: poolManager,\n event: uniswapV4PoolManagerAbi[0],\n args: { id: poolId },\n fromBlock: r.from,\n toBlock: r.to,\n }),\n ),\n )\n const hit = results.find((logs) => logs.length > 0)\n if (hit) {\n foundLogs = hit\n break\n }\n }\n\n if (foundLogs.length === 0) {\n throw new Error(`No Initialize event found for poolId ${poolId} on PoolManager ${poolManager}`)\n }\n\n const args = (foundLogs[0] as { args: Record<string, unknown> }).args as {\n id: Hex\n currency0: Address\n currency1: Address\n fee: number\n tickSpacing: number\n hooks: Address\n }\n\n const key: UniswapV4PoolKey = {\n currency0: args.currency0,\n currency1: args.currency1,\n fee: Number(args.fee),\n tickSpacing: Number(args.tickSpacing),\n hooks: args.hooks,\n }\n\n const recomputed = computeV4PoolId(key)\n if (recomputed.toLowerCase() !== poolId.toLowerCase()) {\n throw new Error(\n `Recomputed poolId ${recomputed} does not match queried ${poolId} — PoolKey encoding mismatch`,\n )\n }\n\n return key\n */\n}\n\n/**\n * Slot0 + liquidity for a V4 pool by poolId — does NOT require the PoolKey.\n * Used to render basic info (currentTick, sqrtPriceX96, liquidity) when the\n * PoolKey is unknown.\n */\nexport interface UniswapV4PoolBasicState {\n poolId: Hex\n sqrtPriceX96: bigint\n currentTick: number\n /** Packed directional protocol fee: `oneForZero << 12 | zeroForOne`, in pips. */\n protocolFee: bigint\n /** Dynamic LP fee from slot0 (NOT necessarily the static PoolKey.fee). */\n lpFee: number\n liquidity: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV4PoolBasicStateParams {\n client: Pick<PublicClient, 'getBlock' | 'multicall'>\n stateViewAddress: Address\n poolId: Hex\n}\n\nexport async function getUniswapV4PoolBasicState(\n params: GetUniswapV4PoolBasicStateParams,\n): Promise<UniswapV4PoolBasicState> {\n const { client, stateViewAddress, poolId } = params\n // Pin slot0 + liquidity to the same block as the returned _meta.\n const _meta = await getBlockMeta({ client })\n const [slot0, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: stateViewAddress, abi: stateViewAbi, functionName: 'getSlot0', args: [poolId] },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getLiquidity',\n args: [poolId],\n },\n ],\n })\n return {\n poolId,\n sqrtPriceX96: slot0[0],\n currentTick: Number(slot0[1]),\n protocolFee: BigInt(slot0[2]),\n lpFee: Number(slot0[3]),\n liquidity,\n _meta,\n }\n}\n\nexport interface UniswapV4PoolInfo {\n poolId: Hex\n poolKey: UniswapV4PoolKey\n token0: UniswapV3PoolToken\n token1: UniswapV3PoolToken\n fee: number\n tickSpacing: number\n hooks: Address\n currentTick: number\n sqrtPriceX96: bigint\n /** Packed directional protocol fee: `oneForZero << 12 | zeroForOne`, in pips. */\n protocolFee: bigint\n liquidity: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV4PoolInfoParams {\n client: Pick<PublicClient, 'getBlock' | 'multicall'>\n stateViewAddress: Address\n poolKey: UniswapV4PoolKey\n}\n\n/** Synthetic token metadata for native ETH (currency address `0x0`). */\nconst NATIVE_ETH_META = { symbol: 'ETH', name: 'Ether', decimals: 18 } as const\n\nasync function readErc20Meta(\n client: Pick<PublicClient, 'multicall'>,\n address: Address,\n blockNumber?: bigint,\n): Promise<{ symbol: string; name: string; decimals: number }> {\n const [symbol, name, decimals] = await client.multicall({\n allowFailure: false,\n blockNumber,\n contracts: [\n { address, abi: erc20MetaAbi, functionName: 'symbol' },\n { address, abi: erc20MetaAbi, functionName: 'name' },\n { address, abi: erc20MetaAbi, functionName: 'decimals' },\n ],\n })\n return { symbol, name, decimals: Number(decimals) }\n}\n\n/**\n * Fetch core data for a Uniswap V4 pool directly from chain.\n *\n * Does NOT require a Panoptic deployment — only StateView + (for non-native\n * currencies) ERC20s. Caller must supply a resolved PoolKey (see\n * `resolveUniswapV4PoolKey`).\n */\nexport async function getUniswapV4PoolInfo(\n params: GetUniswapV4PoolInfoParams,\n): Promise<UniswapV4PoolInfo> {\n const { client, stateViewAddress, poolKey } = params\n const poolId = computeV4PoolId(poolKey)\n\n // Skip ERC20 metadata reads for native ETH (currency `0x0`) so the\n // multicall doesn't revert, and substitute synthetic metadata.\n const c0IsNative = poolKey.currency0 === zeroAddress\n const c1IsNative = poolKey.currency1 === zeroAddress\n\n const _meta = await getBlockMeta({ client })\n\n // State reads (slot0 + liquidity) batched in one multicall.\n const [slot0, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: stateViewAddress, abi: stateViewAbi, functionName: 'getSlot0', args: [poolId] },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getLiquidity',\n args: [poolId],\n },\n ],\n })\n\n // ERC20 metadata (skipped for native ETH) batched in a second multicall,\n // pinned to the same block as the state reads above for consistency.\n const token0Meta = c0IsNative\n ? { ...NATIVE_ETH_META }\n : await readErc20Meta(client, poolKey.currency0, _meta.blockNumber)\n const token1Meta = c1IsNative\n ? { ...NATIVE_ETH_META }\n : await readErc20Meta(client, poolKey.currency1, _meta.blockNumber)\n\n return {\n poolId,\n poolKey,\n token0: { address: poolKey.currency0, ...token0Meta },\n token1: { address: poolKey.currency1, ...token1Meta },\n fee: poolKey.fee,\n tickSpacing: poolKey.tickSpacing,\n hooks: poolKey.hooks,\n currentTick: Number(slot0[1]),\n sqrtPriceX96: slot0[0],\n protocolFee: BigInt(slot0[2]),\n liquidity,\n _meta,\n }\n}\n\nexport interface GetUniswapV4PoolLiquiditiesParams {\n client: PublicClient\n queryAddress: Address\n poolManager: Address\n poolId: Hex\n tickSpacing: number\n startTick: number\n nTicks: bigint\n}\n\n/**\n * Fetch cumulative liquidity distribution for a Uniswap V4 pool via\n * `PanopticQuery.getTickNetsV4`. Does NOT require a Panoptic market for the pool.\n */\nexport async function getUniswapV4PoolLiquidities(\n params: GetUniswapV4PoolLiquiditiesParams,\n): Promise<UniswapV3Liquidities> {\n const { client, queryAddress, poolManager, poolId, tickSpacing, startTick, nTicks } = params\n\n const safeN = clampNTicks(startTick, tickSpacing, nTicks)\n\n // Pin to a specific block so the returned ticks/liquidityNets match _meta.\n const _meta = await getBlockMeta({ client })\n const [ticks, liquidityNets] = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNetsV4',\n args: [poolManager, poolId, tickSpacing, startTick, safeN],\n blockNumber: _meta.blockNumber,\n })\n\n return {\n ticks: [...ticks],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n","/**\n * Direct Uniswap V3/V4 LP position reads — no Panoptic deployment required.\n *\n * Fetches a position's liquidity, tick range and uncollected fees:\n * - V3: `NonfungiblePositionManager.positions` + a `collect` simulation\n * (exact fees, including tokensOwed and unaccrued feeGrowth).\n * - V4: `StateView.getPositionInfo` + `getFeeGrowthInside` and the\n * feeGrowthInside delta math from v4-core's `Position.calculatePositionFeesAccrued`.\n *\n * @module v2/reads/uniswapLpPosition\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { BaseError, ContractFunctionRevertedError, ExecutionRevertedError, toHex } from 'viem'\n\nimport { StateViewAbi } from '../../../abis/StateView'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n// The root NonFungiblePositionManagerAbi flattens collect's CollectParams\n// struct into scalar inputs, which yields a different function selector than\n// the deployed contract's `collect((uint256,address,uint128,uint128))` — so a\n// correct minimal ABI is defined here.\nconst nfpmAbi = [\n {\n type: 'function',\n name: 'positions',\n inputs: [{ name: 'tokenId', type: 'uint256' }],\n outputs: [\n { name: 'nonce', type: 'uint96' },\n { name: 'operator', type: 'address' },\n { name: 'token0', type: 'address' },\n { name: 'token1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickLower', type: 'int24' },\n { name: 'tickUpper', type: 'int24' },\n { name: 'liquidity', type: 'uint128' },\n { name: 'feeGrowthInside0LastX128', type: 'uint256' },\n { name: 'feeGrowthInside1LastX128', type: 'uint256' },\n { name: 'tokensOwed0', type: 'uint128' },\n { name: 'tokensOwed1', type: 'uint128' },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'collect',\n inputs: [\n {\n name: 'params',\n type: 'tuple',\n components: [\n { name: 'tokenId', type: 'uint256' },\n { name: 'recipient', type: 'address' },\n { name: 'amount0Max', type: 'uint128' },\n { name: 'amount1Max', type: 'uint128' },\n ],\n },\n ],\n outputs: [\n { name: 'amount0', type: 'uint256' },\n { name: 'amount1', type: 'uint256' },\n ],\n stateMutability: 'payable',\n },\n] as const\n\nconst MAX_UINT128 = 2n ** 128n - 1n\nconst MAX_UINT256 = 2n ** 256n - 1n\nconst Q128 = 2n ** 128n\n\n/** Liquidity, range and uncollected fees for a single LP position. */\nexport interface UniswapLpPositionState {\n liquidity: bigint\n tickLower: number\n tickUpper: number\n /** Uncollected fees in token0, inclusive of tokensOwed (V3). */\n fees0: bigint\n /** Uncollected fees in token1, inclusive of tokensOwed (V3). */\n fees1: bigint\n /** Block metadata the reads were pinned to. */\n _meta: BlockMeta\n}\n\n/**\n * Whether an error thrown by a viem contract call is an on-chain revert (as\n * opposed to a transport/RPC failure such as a timeout or rate limit).\n */\nfunction isContractRevert(error: unknown): boolean {\n return (\n error instanceof BaseError &&\n error.walk(\n (err) =>\n err instanceof ContractFunctionRevertedError || err instanceof ExecutionRevertedError,\n ) != null\n )\n}\n\nexport interface UniswapV3LpPositionState extends UniswapLpPositionState {\n token0: Address\n token1: Address\n /** Fee tier in hundredths of a bip (e.g. 500 = 0.05%). */\n fee: number\n}\n\nexport interface GetUniswapV3LpPositionStateParams {\n client: PublicClient\n /** NonfungiblePositionManager address. */\n nfpmAddress: Address\n /** ERC721 tokenId of the position. */\n tokenId: bigint\n /** Current owner of the position NFT (used as `account` for the collect simulation). */\n owner: Address\n /** Optional historical block to pin the position read to. */\n blockNumber?: bigint\n}\n\n/**\n * Fetch a Uniswap V3 LP position's state and uncollected fees.\n *\n * Fees come from simulating `collect` with max amounts as the owner — one\n * eth_call returning the exact claimable amounts (tokensOwed + fee growth\n * since the last poke). The simulation is best-effort: if it reverts (e.g.\n * an empty position), fees fall back to 0.\n */\nexport async function getUniswapV3LpPositionState(\n params: GetUniswapV3LpPositionStateParams,\n): Promise<UniswapV3LpPositionState> {\n const { client, nfpmAddress, tokenId, owner, blockNumber } = params\n\n // Pin both reads to the same block so position state and fees are\n // self-consistent with the returned _meta. The collect simulation cannot be\n // folded into a Multicall3 batch: it must run with msg.sender = owner.\n const _meta = await getBlockMeta({ client, blockNumber })\n\n const position = await client.readContract({\n address: nfpmAddress,\n abi: nfpmAbi,\n functionName: 'positions',\n args: [tokenId],\n blockNumber: _meta.blockNumber,\n })\n const [, , token0, token1, fee, tickLower, tickUpper, liquidity] = position\n\n let fees0 = 0n\n let fees1 = 0n\n try {\n const { result } = await client.simulateContract({\n address: nfpmAddress,\n abi: nfpmAbi,\n functionName: 'collect',\n args: [{ tokenId, recipient: owner, amount0Max: MAX_UINT128, amount1Max: MAX_UINT128 }],\n account: owner,\n blockNumber: _meta.blockNumber,\n })\n ;[fees0, fees1] = result\n } catch (error) {\n // collect reverts for some empty positions — report zero fees. Transport\n // and RPC failures propagate so callers don't mistake them for no fees.\n if (!isContractRevert(error)) throw error\n }\n\n return {\n token0,\n token1,\n fee: Number(fee),\n tickLower: Number(tickLower),\n tickUpper: Number(tickUpper),\n liquidity,\n fees0,\n fees1,\n _meta,\n }\n}\n\n/**\n * Uncollected fees from a feeGrowthInside delta, mirroring v4-core's\n * `Position.calculatePositionFeesAccrued`: the subtraction wraps around\n * uint256 (feeGrowthInside can legitimately underflow in-protocol).\n */\nexport function feesFromFeeGrowthDelta(\n feeGrowthInsideCurrentX128: bigint,\n feeGrowthInsideLastX128: bigint,\n liquidity: bigint,\n): bigint {\n const delta = (feeGrowthInsideCurrentX128 - feeGrowthInsideLastX128) & MAX_UINT256\n return (delta * liquidity) / Q128\n}\n\nexport interface GetUniswapV4LpPositionStateParams {\n client: PublicClient\n /** StateView address. */\n stateViewAddress: Address\n /** Uniswap v4 PositionManager (posm) address — the position owner inside PoolManager. */\n positionManagerAddress: Address\n /** The bytes32 poolId hash. */\n poolId: Hex\n /** ERC721 tokenId of the position (posm salt = bytes32(tokenId)). */\n tokenId: bigint\n tickLower: number\n tickUpper: number\n /** Optional historical block to pin the position read to. */\n blockNumber?: bigint\n}\n\n/**\n * Fetch a Uniswap V4 LP position's state and uncollected fees via StateView.\n *\n * The position inside PoolManager is keyed by (positionManager, tickLower,\n * tickUpper, salt) where posm uses `bytes32(tokenId)` as the salt. Fees on\n * pools with fee-taking hooks may be approximate.\n */\nexport async function getUniswapV4LpPositionState(\n params: GetUniswapV4LpPositionStateParams,\n): Promise<UniswapLpPositionState> {\n const {\n client,\n stateViewAddress,\n positionManagerAddress,\n poolId,\n tokenId,\n tickLower,\n tickUpper,\n blockNumber,\n } = params\n\n const salt = toHex(tokenId, { size: 32 })\n\n // Pin both StateView reads to the same block as the returned _meta.\n const _meta = await getBlockMeta({ client, blockNumber })\n\n const [positionInfo, feeGrowthInside] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n {\n address: stateViewAddress,\n abi: StateViewAbi,\n functionName: 'getPositionInfo',\n args: [poolId, positionManagerAddress, tickLower, tickUpper, salt],\n },\n {\n address: stateViewAddress,\n abi: StateViewAbi,\n functionName: 'getFeeGrowthInside',\n args: [poolId, tickLower, tickUpper],\n },\n ],\n })\n\n const [liquidity, feeGrowthInside0LastX128, feeGrowthInside1LastX128] = positionInfo\n const [feeGrowthInside0X128, feeGrowthInside1X128] = feeGrowthInside\n\n return {\n liquidity,\n tickLower,\n tickUpper,\n fees0: feesFromFeeGrowthDelta(feeGrowthInside0X128, feeGrowthInside0LastX128, liquidity),\n fees1: feesFromFeeGrowthDelta(feeGrowthInside1X128, feeGrowthInside1LastX128, liquidity),\n _meta,\n }\n}\n","/**\n * Historical price reads for the Panoptic v2 SDK.\n *\n * Fetches slot0 (tick + sqrtPriceX96) across a series of historical blocks\n * for price-over-time charting. All block reads are parallelized via\n * Promise.all (viem auto-batches into multicall).\n *\n * @module v2/reads/priceHistory\n */\n\nimport type { PublicClient } from 'viem'\n\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A single price snapshot at a particular block. */\nexport interface PriceSnapshot {\n /** Block number (undefined if queried as latest) */\n blockNumber: bigint | undefined\n /** Current tick of the pool at this block */\n tick: number\n /** sqrtPriceX96 at this block */\n sqrtPriceX96: bigint\n}\n\n/** Result from getPriceHistory. */\nexport interface PriceHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: PriceSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n/** Parameters for getPriceHistory. */\nexport interface GetPriceHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n// ── Main function ──────────────────────────────────────────────────────\n\n/**\n * Get historical price data (tick + sqrtPriceX96) for a pool across multiple blocks.\n *\n * @param params - The parameters\n * @returns Price snapshots at each block\n *\n * @example\n * ```typescript\n * const { snapshots } = await getPriceHistory({\n * client,\n * blockNumbers: [18000000n, 18000100n, 18000200n],\n * poolConfig: { version: 'v3', poolAddress: '0x...' },\n * })\n *\n * for (const snap of snapshots) {\n * console.log(`Block ${snap.blockNumber}: tick=${snap.tick}`)\n * }\n * ```\n */\nexport async function getPriceHistory(params: GetPriceHistoryParams): Promise<PriceHistoryResult> {\n const { client, blockNumbers, poolConfig } = params\n\n if (blockNumbers.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n // Fire one slot0 read per block. Calls at different historical blocks cannot\n // be coalesced into one multicall, so callers should not poll this path.\n const slot0Requests = blockNumbers.map((bn) => fetchSlot0(client, bn, poolConfig))\n\n const [slot0Results, _meta] = await Promise.all([\n Promise.all(slot0Requests),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n const snapshots: PriceSnapshot[] = slot0Results.map((result, i) => ({\n blockNumber: blockNumbers[i],\n tick: result.tick,\n sqrtPriceX96: result.sqrtPriceX96,\n }))\n\n return { snapshots, _meta }\n}\n\n// ── Internals ──────────────────────────────────────────────────────────\n\ninterface Slot0Data {\n tick: number\n sqrtPriceX96: bigint\n}\n\nasync function fetchSlot0(\n client: PublicClient,\n blockNumber: bigint | undefined,\n poolConfig: PoolVersionConfig,\n): Promise<Slot0Data> {\n if (poolConfig.version === 'v3') {\n const result = await client.readContract({\n address: poolConfig.poolAddress,\n abi: uniswapV3PoolAbi,\n functionName: 'slot0',\n blockNumber,\n })\n return {\n sqrtPriceX96: result[0],\n tick: result[1],\n }\n } else {\n const result = await client.readContract({\n address: poolConfig.stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getSlot0',\n args: [poolConfig.poolId],\n blockNumber,\n })\n return {\n sqrtPriceX96: result[0],\n tick: result[1],\n }\n }\n}\n","/**\n * Position enrichment data for UI display.\n *\n * Batches all contract reads needed to enrich subgraph position data with\n * on-chain premia, portfolio values, and collateral requirements.\n *\n * @module v2/reads/enrichment\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi, panopticQueryAbi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError } from '../errors'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\n\n/**\n * Error thrown when an enrichment contract call fails for a specific position.\n */\nexport class EnrichmentCallError extends PanopticError {\n /** The tokenId of the position that failed */\n readonly tokenId: bigint\n /** The name of the failing call */\n readonly callName: string\n\n constructor(tokenId: bigint, callName: string, cause?: unknown) {\n super(\n `Enrichment call \"${callName}\" failed for tokenId ${tokenId}`,\n cause instanceof Error ? cause : undefined,\n )\n this.tokenId = tokenId\n this.callName = callName\n }\n}\n\n/**\n * Input describing a position for enrichment.\n */\nexport interface PositionInput {\n /** The tokenId (256-bit identifier) */\n tokenId: bigint\n /** Whether the position is currently open */\n isOpen: boolean\n /** Tick at time of mint */\n tickAtMint: number\n /** Account address that owns the position */\n account: Address\n /** Pool address the position belongs to */\n poolAddress: Address\n /** Tick at burn (closed positions only) */\n tickAtBurn?: number\n /** Block number of the burn tx (closed positions only) */\n burnBlockNumber?: bigint\n /** Premium in token0 from subgraph (closed positions only) */\n burnPremium0?: bigint\n /** Premium in token1 from subgraph (closed positions only) */\n burnPremium1?: bigint\n}\n\n/**\n * Enrichment result for a single position.\n *\n * Values are in raw token units (token0 and token1), not asset/quote.\n * The UI maps these to asset/quote based on isAssetToken0.\n */\nexport interface PositionEnrichmentResult {\n /** Net premia owed: shortPremium - longPremium for token0 (open); burnPremium0 for closed */\n premiaOwed0: bigint\n /** Net premia owed: shortPremium - longPremium for token1 (open); burnPremium1 for closed */\n premiaOwed1: bigint\n /** Portfolio value in token0 at current tick (open) or burn tick (closed) */\n portfolioValue0: bigint\n /** Portfolio value in token1 at current tick (open) or burn tick (closed) */\n portfolioValue1: bigint\n /** Portfolio value in token0 at mint tick */\n portfolioValueAtMint0: bigint\n /** Portfolio value in token1 at mint tick */\n portfolioValueAtMint1: bigint\n /**\n * Per-token collateral requirement from `getFullPositionsData.collateralRequirements[]`.\n * These are NOT cross-margined — each is in its own token denomination.\n * For closed positions these are 0n (collateral is moot).\n */\n collateralReqToken0: bigint\n collateralReqToken1: bigint\n}\n\n/**\n * Parameters for getPositionEnrichmentData.\n */\nexport interface GetPositionEnrichmentDataParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticQuery helper contract address */\n queryAddress: Address\n /** Positions to enrich */\n positions: PositionInput[]\n /** Current pool tick (used for open position portfolio values) */\n currentTick: number\n /** Optional block number for open position reads */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * Result from getPositionEnrichmentData.\n */\nexport interface GetPositionEnrichmentDataResult {\n /** Enrichment data keyed by tokenId string */\n byTokenId: Map<string, PositionEnrichmentResult>\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Fetch enrichment data (premia, portfolio values, collateral requirements) for a set of positions.\n *\n * Batches all needed contract reads into efficient multicalls:\n * - **Open positions**: 3 calls per position in a single multicall at current block:\n * 1. `getFullPositionsData` → premia + collateral requirements\n * 2. `getPortfolioValue` at currentTick → current portfolio value\n * 3. `getPortfolioValue` at mintTick → portfolio value at mint\n * - **Closed positions**: 2 calls per position at `burnBlockNumber - 1`:\n * 1. `getPortfolioValue` at burnTick → portfolio value at close\n * 2. `getPortfolioValue` at mintTick → portfolio value at mint\n * (premia come from subgraph `burnPremium0/1`)\n *\n * ## Same-Block Guarantee\n * Open position data is fetched at a single block number.\n * Closed position data is fetched at `burnBlockNumber - 1` (per position).\n *\n * @param params - The parameters\n * @returns Map of tokenId → enrichment data, with block metadata\n */\nexport async function getPositionEnrichmentData(\n params: GetPositionEnrichmentDataParams,\n): Promise<GetPositionEnrichmentDataResult> {\n const { client, queryAddress, positions, currentTick, blockNumber } = params\n\n // Fetch a single block metadata for the entire enrichment result\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber }))\n\n if (positions.length === 0) {\n return { byTokenId: new Map(), _meta }\n }\n\n const openPositions = positions.filter((p) => p.isOpen)\n const closedPositions = positions.filter((p) => !p.isOpen)\n\n const byTokenId = new Map<string, PositionEnrichmentResult>()\n\n // Process open and closed positions in parallel\n await Promise.all([\n processOpenPositions(client, queryAddress, openPositions, currentTick, blockNumber, _meta),\n processClosedPositions(client, queryAddress, closedPositions),\n ]).then(([openResults, closedResults]) => {\n // Merge results into byTokenId map\n for (const [key, value] of openResults.entries) {\n byTokenId.set(key, value)\n }\n for (const [key, value] of closedResults) {\n byTokenId.set(key, value)\n }\n })\n\n return { byTokenId, _meta }\n}\n\n/** Number of multicall contracts per open position */\nconst OPEN_CALLS_PER_POSITION = 3\n/** Number of multicall contracts per closed position */\nconst CLOSED_CALLS_PER_POSITION = 2\n\n/**\n * Process open positions: single multicall with 5 calls per position.\n */\nasync function processOpenPositions(\n client: PublicClient,\n queryAddress: Address,\n positions: PositionInput[],\n currentTick: number,\n blockNumber: bigint | undefined,\n _meta: BlockMeta,\n): Promise<{ entries: [string, PositionEnrichmentResult][] }> {\n if (positions.length === 0) {\n return { entries: [] }\n }\n\n const targetBlockNumber = blockNumber ?? _meta.blockNumber\n\n // Build multicall contracts: 3 calls per position\n const contracts = positions.flatMap((p) => [\n // 1. getFullPositionsData → premia + collateral requirements\n {\n address: p.poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData' as const,\n args: [p.account, true, [p.tokenId]] as const,\n },\n // 2. getPortfolioValue at currentTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, currentTick, [p.tokenId]] as const,\n },\n // 3. getPortfolioValue at mintTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtMint, [p.tokenId]] as const,\n },\n ])\n\n const multicallResults = await client.multicall({\n contracts,\n blockNumber: targetBlockNumber,\n allowFailure: true,\n })\n\n const entries: [string, PositionEnrichmentResult][] = []\n\n for (let i = 0; i < positions.length; i++) {\n const position = positions[i]\n const baseIdx = i * OPEN_CALLS_PER_POSITION\n\n const premiaResult = multicallResults[baseIdx]\n const portfolioResult = multicallResults[baseIdx + 1]\n const portfolioAtMintResult = multicallResults[baseIdx + 2]\n\n if (premiaResult.status !== 'success') {\n throw new EnrichmentCallError(position.tokenId, 'getFullPositionsData', premiaResult.error)\n }\n if (portfolioResult.status !== 'success') {\n throw new EnrichmentCallError(\n position.tokenId,\n 'getPortfolioValue (currentTick)',\n portfolioResult.error,\n )\n }\n if (portfolioAtMintResult.status !== 'success') {\n throw new EnrichmentCallError(\n position.tokenId,\n 'getPortfolioValue (mintTick)',\n portfolioAtMintResult.error,\n )\n }\n\n // Decode getFullPositionsData: [shortPremium, longPremium, balances[], collateralReqs[], netPremia[]]\n const [shortPremiumPacked, longPremiumPacked, , collateralReqsPacked] = premiaResult.result as [\n bigint,\n bigint,\n bigint[],\n bigint[],\n bigint[],\n ]\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n const premiaOwed0 = shortPremium.right - longPremium.right // token0\n const premiaOwed1 = shortPremium.left - longPremium.left // token1\n\n // Decode per-token collateral requirements from collateralReqs[0] (LeftRightUnsigned)\n const collateralReq = decodeLeftRightUnsigned(collateralReqsPacked[0] ?? 0n)\n\n // Decode portfolio values\n const [portfolioValue0, portfolioValue1] = portfolioResult.result as [bigint, bigint]\n const [portfolioValueAtMint0, portfolioValueAtMint1] = portfolioAtMintResult.result as [\n bigint,\n bigint,\n ]\n\n entries.push([\n position.tokenId.toString(),\n {\n premiaOwed0,\n premiaOwed1,\n portfolioValue0,\n portfolioValue1,\n portfolioValueAtMint0,\n portfolioValueAtMint1,\n collateralReqToken0: collateralReq.right,\n collateralReqToken1: collateralReq.left,\n },\n ])\n }\n\n return { entries }\n}\n\n/**\n * Process closed positions: per-position calls at burnBlockNumber - 1.\n *\n * Returns entries array (not a map) to merge into the final result.\n */\nasync function processClosedPositions(\n client: PublicClient,\n queryAddress: Address,\n positions: PositionInput[],\n): Promise<[string, PositionEnrichmentResult][]> {\n if (positions.length === 0) return []\n\n // Group positions by burnBlockNumber for batch efficiency\n const byBlock = new Map<bigint, PositionInput[]>()\n for (const p of positions) {\n if (p.burnBlockNumber == null) continue\n const readBlock = p.burnBlockNumber - 1n\n const group = byBlock.get(readBlock) ?? []\n group.push(p)\n byBlock.set(readBlock, group)\n }\n\n const entries: [string, PositionEnrichmentResult][] = []\n\n // Process each block group\n await Promise.all(\n Array.from(byBlock.entries()).map(async ([readBlock, blockPositions]) => {\n // Build multicall contracts: 2 calls per position\n const contracts = blockPositions.flatMap((p) => [\n // 1. getPortfolioValue at burnTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtBurn ?? 0, [p.tokenId]] as const,\n },\n // 2. getPortfolioValue at mintTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtMint, [p.tokenId]] as const,\n },\n ])\n\n const multicallResults = await client.multicall({\n contracts,\n blockNumber: readBlock,\n allowFailure: true,\n })\n\n for (let i = 0; i < blockPositions.length; i++) {\n const position = blockPositions[i]\n const baseIdx = i * CLOSED_CALLS_PER_POSITION\n\n const portfolioAtBurnResult = multicallResults[baseIdx]\n const portfolioAtMintResult = multicallResults[baseIdx + 1]\n\n // Closed position reads can fail legitimately (e.g. position minted and burned\n // in the same block — at burnBlock-1 it doesn't exist yet). Fall back to zeros.\n const [portfolioValue0, portfolioValue1] =\n portfolioAtBurnResult.status === 'success'\n ? (portfolioAtBurnResult.result as [bigint, bigint])\n : [0n, 0n]\n const [portfolioValueAtMint0, portfolioValueAtMint1] =\n portfolioAtMintResult.status === 'success'\n ? (portfolioAtMintResult.result as [bigint, bigint])\n : [0n, 0n]\n\n entries.push([\n position.tokenId.toString(),\n {\n premiaOwed0: position.burnPremium0 ?? 0n,\n premiaOwed1: position.burnPremium1 ?? 0n,\n portfolioValue0,\n portfolioValue1,\n portfolioValueAtMint0,\n portfolioValueAtMint1,\n collateralReqToken0: 0n,\n collateralReqToken1: 0n,\n },\n ])\n }\n }),\n )\n\n return entries\n}\n","/**\n * Get synchronization status for an account.\n * @module v2/sync/getSyncStatus\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { loadCheckpoint } from './reorgHandling'\n\n/**\n * Parameters for getSyncStatus.\n */\nexport interface GetSyncStatusParams {\n /** viem public client */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to check */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Sync status result.\n */\nexport interface SyncStatusResult {\n /** Last synced block number (0n if never synced) */\n lastSyncedBlock: bigint\n /** Whether the account is fully synced to current block */\n isSynced: boolean\n /** Number of blocks behind (0n if synced) */\n blocksBehind: bigint\n /** Number of positions tracked */\n positionCount: bigint\n /** Whether a checkpoint exists */\n hasCheckpoint: boolean\n}\n\n/**\n * Get the synchronization status for an account.\n *\n * This function checks the stored checkpoint and compares against\n * the current chain head to determine sync status.\n *\n * @param params - Status parameters\n * @returns Sync status information\n */\nexport async function getSyncStatus(params: GetSyncStatusParams): Promise<SyncStatusResult> {\n const { client, chainId, poolAddress, account, storage } = params\n\n // Get current block\n const currentBlock = await client.getBlockNumber()\n\n // Load checkpoint\n const checkpoint = await loadCheckpoint(storage, chainId, poolAddress, account)\n\n if (!checkpoint) {\n return {\n lastSyncedBlock: 0n,\n isSynced: false,\n blocksBehind: currentBlock,\n positionCount: 0n,\n hasCheckpoint: false,\n }\n }\n\n const blocksBehind = currentBlock - checkpoint.lastBlock\n const isSynced = blocksBehind <= 0n\n\n return {\n lastSyncedBlock: checkpoint.lastBlock,\n isSynced,\n blocksBehind: blocksBehind > 0n ? blocksBehind : 0n,\n positionCount: BigInt(checkpoint.positionIds.length),\n hasCheckpoint: true,\n }\n}\n","/**\n * Trade history tracking for closed positions.\n * @module v2/sync/tradeHistory\n */\n\nimport type { Address } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { getClosedPositionsKey, jsonSerializer } from '../storage'\nimport type { ClosedPosition, RealizedPnL } from '../types'\n\n/**\n * Parameters for saving a closed position.\n */\nexport interface SaveClosedPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account that owned the position */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** The closed position data */\n closedPosition: ClosedPosition\n}\n\n/**\n * Save a closed position to trade history.\n *\n * @param params - Save parameters\n */\nexport async function saveClosedPosition(params: SaveClosedPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, closedPosition } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n let history: ClosedPosition[]\n if (existingData) {\n try {\n history = jsonSerializer.parse(existingData) as ClosedPosition[]\n } catch {\n history = []\n }\n } else {\n history = []\n }\n\n // Add new closed position\n history.push(closedPosition)\n\n // Sort by close block (most recent first)\n history.sort((a, b) => Number(b.closeBlock - a.closeBlock))\n\n await storage.set(key, jsonSerializer.stringify(history))\n}\n\n/**\n * Parameters for getting trade history.\n */\nexport interface GetTradeHistoryParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to get history for */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Maximum number of positions to return (default: 100) */\n limit?: bigint\n /** Offset for pagination */\n offset?: bigint\n /** Filter by closure reason */\n closureReason?: 'closed' | 'liquidated' | 'force_exercised'\n /** Filter by block range (from) */\n fromBlock?: bigint\n /** Filter by block range (to) */\n toBlock?: bigint\n}\n\n/**\n * Get trade history (closed positions) for an account.\n *\n * This function reads from local storage, no RPC calls.\n * Positions are returned in reverse chronological order (most recent first).\n *\n * @param params - Query parameters\n * @returns Array of closed positions\n */\nexport async function getTradeHistory(params: GetTradeHistoryParams): Promise<ClosedPosition[]> {\n const {\n chainId,\n poolAddress,\n account,\n storage,\n limit = 100n,\n offset = 0n,\n closureReason,\n fromBlock,\n toBlock,\n } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n let history: ClosedPosition[]\n try {\n history = jsonSerializer.parse(data) as ClosedPosition[]\n } catch {\n return []\n }\n\n // Apply filters\n if (closureReason) {\n history = history.filter((p) => p.closureReason === closureReason)\n }\n\n if (fromBlock !== undefined) {\n history = history.filter((p) => p.closeBlock >= fromBlock)\n }\n\n if (toBlock !== undefined) {\n history = history.filter((p) => p.closeBlock <= toBlock)\n }\n\n // Apply pagination\n const start = Number(offset)\n const end = start + Number(limit)\n return history.slice(start, end)\n}\n\n/**\n * Get closed positions (alias for getTradeHistory with specific closure reason).\n *\n * @param params - Query parameters\n * @returns Array of closed positions\n */\nexport async function getClosedPositions(params: GetTradeHistoryParams): Promise<ClosedPosition[]> {\n return getTradeHistory(params)\n}\n\n/**\n * Parameters for getting realized PnL.\n */\nexport interface GetRealizedPnLParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to get PnL for */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Filter by block range (from) */\n fromBlock?: bigint\n /** Filter by block range (to) */\n toBlock?: bigint\n}\n\n/**\n * Get realized PnL summary for an account.\n *\n * Calculates totals from all closed positions in storage.\n *\n * @param params - Query parameters\n * @returns Realized PnL summary\n */\nexport async function getRealizedPnL(params: GetRealizedPnLParams): Promise<RealizedPnL> {\n const { chainId, poolAddress, account, storage, fromBlock, toBlock } = params\n\n const history = await getTradeHistory({\n chainId,\n poolAddress,\n account,\n storage,\n limit: BigInt(Number.MAX_SAFE_INTEGER), // Get all\n fromBlock,\n toBlock,\n })\n\n let total0 = 0n\n let total1 = 0n\n let winCount = 0n\n let lossCount = 0n\n\n for (const position of history) {\n total0 += position.realizedPnL0\n total1 += position.realizedPnL1\n\n // Consider it a win if either token had positive PnL\n // (in practice, one will usually dominate)\n const isWin = position.realizedPnL0 > 0n || position.realizedPnL1 > 0n\n const isLoss = position.realizedPnL0 < 0n || position.realizedPnL1 < 0n\n\n if (isWin && !isLoss) {\n winCount++\n } else if (isLoss && !isWin) {\n lossCount++\n }\n // Mixed results (win on one, loss on other) don't count as either\n }\n\n return {\n total0,\n total1,\n positionCount: BigInt(history.length),\n winCount,\n lossCount,\n }\n}\n\n/**\n * Clear all trade history for an account.\n *\n * @param params - Query parameters\n */\nexport async function clearTradeHistory(\n params: Omit<\n GetTradeHistoryParams,\n 'limit' | 'offset' | 'closureReason' | 'fromBlock' | 'toBlock'\n >,\n): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n await storage.delete(key)\n}\n","/**\n * Chunk spread tracking for volatility surface data.\n * @module v2/sync/chunkTracking\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { ChunkLimitError } from '../errors'\nimport type { StorageAdapter } from '../storage'\nimport { getTrackedChunksKey, jsonSerializer } from '../storage'\nimport { DEFAULT_VEGOID } from '../tokenId/constants'\nimport type { BlockMeta } from '../types'\nimport { MAX_TRACKED_CHUNKS, WAD } from '../utils/constants'\n\n/**\n * Key for identifying a liquidity chunk.\n * A chunk is a unique combination of (tokenType, tickLower, tickUpper).\n */\nexport interface LiquidityChunkKey {\n /** Token type: 0n = token0 (put), 1n = token1 (call) */\n tokenType: 0n | 1n\n /** Lower tick bound */\n tickLower: bigint\n /** Upper tick bound */\n tickUpper: bigint\n}\n\n/**\n * Full chunk data with spread calculation.\n */\nexport interface LiquidityChunkSpread extends LiquidityChunkKey {\n /** Liquidity currently deployed in Uniswap */\n netLiquidity: bigint\n /** Liquidity borrowed by option buyers */\n removedLiquidity: bigint\n /** Computed spread: (1 + (1/VEGOID) * removed/net) * 1e18 */\n spreadWad: bigint\n}\n\n/**\n * Parameters for adding tracked chunks.\n */\nexport interface AddTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Chunks to add */\n chunks: LiquidityChunkKey[]\n}\n\n/**\n * Serialize a chunk key to a string for storage/comparison.\n */\nfunction serializeChunkKey(chunk: LiquidityChunkKey): string {\n return `${chunk.tokenType}:${chunk.tickLower}:${chunk.tickUpper}`\n}\n\n/**\n * Deserialize a chunk key from a string.\n */\nfunction deserializeChunkKey(key: string): LiquidityChunkKey {\n const [tokenType, tickLower, tickUpper] = key.split(':')\n return {\n tokenType: BigInt(tokenType) as 0n | 1n,\n tickLower: BigInt(tickLower),\n tickUpper: BigInt(tickUpper),\n }\n}\n\n/**\n * Add chunks to tracking.\n *\n * @param params - Parameters\n * @throws ChunkLimitError if adding would exceed 1000 chunks\n */\nexport async function addTrackedChunks(params: AddTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage, chunks } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const existingData = await storage.get(key)\n\n let trackedKeys: Set<string>\n if (existingData) {\n try {\n const keys = jsonSerializer.parse(existingData) as string[]\n trackedKeys = new Set(keys)\n } catch {\n trackedKeys = new Set()\n }\n } else {\n trackedKeys = new Set()\n }\n\n // Add new chunks\n for (const chunk of chunks) {\n const serialized = serializeChunkKey(chunk)\n trackedKeys.add(serialized)\n }\n\n // Check limit\n if (trackedKeys.size > MAX_TRACKED_CHUNKS) {\n const attemptedAdd = BigInt(chunks.length)\n throw new ChunkLimitError(BigInt(trackedKeys.size - chunks.length), attemptedAdd)\n }\n\n await storage.set(key, jsonSerializer.stringify([...trackedKeys]))\n}\n\n/**\n * Parameters for removing tracked chunks.\n */\nexport interface RemoveTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Chunks to remove */\n chunks: LiquidityChunkKey[]\n}\n\n/**\n * Remove chunks from tracking.\n *\n * @param params - Parameters\n */\nexport async function removeTrackedChunks(params: RemoveTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage, chunks } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let trackedKeys: Set<string>\n try {\n const keys = jsonSerializer.parse(existingData) as string[]\n trackedKeys = new Set(keys)\n } catch {\n return\n }\n\n // Remove chunks\n for (const chunk of chunks) {\n const serialized = serializeChunkKey(chunk)\n trackedKeys.delete(serialized)\n }\n\n if (trackedKeys.size === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify([...trackedKeys]))\n }\n}\n\n/**\n * Parameters for getting tracked chunks.\n */\nexport interface GetTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Get all tracked chunk keys.\n *\n * @param params - Parameters\n * @returns Array of tracked chunk keys\n */\nexport async function getTrackedChunks(\n params: GetTrackedChunksParams,\n): Promise<LiquidityChunkKey[]> {\n const { chainId, poolAddress, storage } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n try {\n const keys = jsonSerializer.parse(data) as string[]\n return keys.map(deserializeChunkKey)\n } catch {\n return []\n }\n}\n\n/**\n * Parameters for getting chunk spreads (legacy manual tracking).\n * @deprecated Use scanChunks() for automatic chunk discovery\n */\nexport interface GetChunkSpreadsParams {\n /** viem public client */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address (PanopticPool) */\n poolAddress: Address\n /** SFPM address */\n sfpmAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Optional filter by token type */\n tokenType?: 0n | 1n\n /** VEGOID constant (default: 4n) */\n vegoid?: bigint\n}\n\n/**\n * Get spread data for all tracked chunks (legacy).\n *\n * @deprecated Use scanChunks() for automatic chunk discovery with on-chain data.\n * This function only returns manually tracked chunks.\n *\n * @param params - Parameters\n * @returns Array of chunk spreads with liquidity data\n */\nexport async function getChunkSpreads(\n params: GetChunkSpreadsParams,\n): Promise<LiquidityChunkSpread[]> {\n const { chainId, poolAddress, storage, tokenType } = params\n\n // Get tracked chunks\n let chunks = await getTrackedChunks({ chainId, poolAddress, storage })\n\n // Apply filter\n if (tokenType !== undefined) {\n chunks = chunks.filter((c) => c.tokenType === tokenType)\n }\n\n if (chunks.length === 0) {\n return []\n }\n\n // Return tracked chunks without liquidity data\n // Use scanChunks() for on-chain liquidity data\n return chunks.map((chunk) => ({\n ...chunk,\n netLiquidity: 0n,\n removedLiquidity: 0n,\n spreadWad: WAD,\n }))\n}\n\n/**\n * Calculate spread from liquidity values.\n *\n * spread = 1 + (1/VEGOID) * removedLiquidity / netLiquidity\n *\n * @param netLiquidity - Liquidity in Uniswap\n * @param removedLiquidity - Liquidity borrowed by buyers\n * @param vegoid - VEGOID constant (default: 4n)\n * @returns Spread in WAD (1e18 = 1.0x)\n */\nexport function calculateSpreadWad(\n netLiquidity: bigint,\n removedLiquidity: bigint,\n vegoid: bigint = DEFAULT_VEGOID,\n): bigint {\n if (netLiquidity === 0n) {\n return WAD // 1.0x spread if no liquidity\n }\n\n // spread = WAD + (WAD / vegoid) * removedLiquidity / netLiquidity\n // = WAD + (WAD * removedLiquidity) / (vegoid * netLiquidity)\n const bonus = (WAD * removedLiquidity) / (vegoid * netLiquidity)\n return WAD + bonus\n}\n\n/**\n * Clear all tracked chunks for a pool.\n *\n * @param params - Parameters\n */\nexport async function clearTrackedChunks(params: GetTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n await storage.delete(key)\n}\n\n// ============================================================================\n// PanopticQuery-based chunk functions (recommended)\n// ============================================================================\n\n/**\n * Scanned chunk with liquidity data from PanopticQuery.scanChunks().\n */\nexport interface ScannedChunk {\n /** Strike tick (center of the chunk) */\n strike: bigint\n /** Token type 0 net liquidity */\n netLiquidity0: bigint\n /** Token type 1 net liquidity */\n netLiquidity1: bigint\n /** Token type 0 removed liquidity */\n removedLiquidity0: bigint\n /** Token type 1 removed liquidity */\n removedLiquidity1: bigint\n /** Computed spread for token type 0 */\n spreadWad0: bigint\n /** Computed spread for token type 1 */\n spreadWad1: bigint\n /** Token type 0 settled tokens (LeftRightUnsigned: left=token1, right=token0) */\n settledTokens0: bigint\n /** Token type 1 settled tokens (LeftRightUnsigned: left=token1, right=token0) */\n settledTokens1: bigint\n}\n\n/**\n * Result of scanning chunks in a tick range.\n */\nexport interface ScanChunksResult {\n /** Array of scanned chunks with liquidity data */\n chunks: ScannedChunk[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for scanChunks().\n */\nexport interface ScanChunksParams {\n /** viem public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery contract address */\n queryAddress: Address\n /** Lower tick bound of range to scan */\n tickLower: bigint\n /** Upper tick bound of range to scan */\n tickUpper: bigint\n /** Width of chunks to scan (tickUpper - tickLower for each chunk) */\n width: bigint\n /** VEGOID constant for spread calculation (default: 4n) */\n vegoid?: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Scan for non-empty liquidity chunks in a tick range.\n *\n * Uses PanopticQuery.scanChunks() to discover chunks with liquidity.\n * Returns only non-empty chunks, making it efficient for large ranges.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - Parameters\n * @returns Scanned chunks with liquidity data and block metadata\n *\n * @example\n * ```typescript\n * const result = await scanChunks({\n * client,\n * poolAddress: '0x...',\n * queryAddress: '0x...',\n * tickLower: -1000n,\n * tickUpper: 1000n,\n * width: 100n, // 100 tick wide chunks\n * })\n *\n * for (const chunk of result.chunks) {\n * console.log(`Strike ${chunk.strike}: spread0=${chunk.spreadWad0}, spread1=${chunk.spreadWad1}`)\n * }\n * ```\n */\nexport async function scanChunks(params: ScanChunksParams): Promise<ScanChunksResult> {\n const {\n client,\n poolAddress,\n queryAddress,\n tickLower,\n tickUpper,\n width,\n vegoid = 4n,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'scanChunks',\n args: [poolAddress, Number(tickLower), Number(tickUpper), Number(width)],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [strikes, netLiquidities, removedLiquidities, settledTokens] = result\n\n const chunks: ScannedChunk[] = strikes.map((strike, i) => {\n const net0 = netLiquidities[i][0]\n const net1 = netLiquidities[i][1]\n const removed0 = removedLiquidities[i][0]\n const removed1 = removedLiquidities[i][1]\n\n return {\n strike: BigInt(strike),\n netLiquidity0: net0,\n netLiquidity1: net1,\n removedLiquidity0: removed0,\n removedLiquidity1: removed1,\n spreadWad0: calculateSpreadWad(net0, removed0, vegoid),\n spreadWad1: calculateSpreadWad(net1, removed1, vegoid),\n settledTokens0: settledTokens[i][0],\n settledTokens1: settledTokens[i][1],\n }\n })\n\n return { chunks, _meta }\n}\n\n/**\n * Chunk data for a single leg of a position.\n */\nexport interface LegChunkData {\n /** Leg index (0-3) */\n legIndex: number\n /** Net liquidity (liquidity in Uniswap) */\n netLiquidity: bigint\n /** Removed liquidity (borrowed by option buyers) */\n removedLiquidity: bigint\n /** Computed spread */\n spreadWad: bigint\n}\n\n/**\n * Chunk data for a position (all legs).\n */\nexport interface PositionChunkData {\n /** TokenId of the position */\n tokenId: bigint\n /** Chunk data for each leg */\n legs: LegChunkData[]\n}\n\n/**\n * Result of getting position chunk data.\n */\nexport interface GetPositionChunkDataResult {\n /** Array of position chunk data */\n positions: PositionChunkData[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPositionChunkData().\n */\nexport interface GetPositionChunkDataParams {\n /** viem public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery contract address */\n queryAddress: Address\n /** Array of tokenIds to query */\n tokenIds: bigint[]\n /** VEGOID constant for spread calculation (default: 4n) */\n vegoid?: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Get chunk data (liquidity) for specific positions.\n *\n * Uses PanopticQuery.getChunkData() to fetch net and removed liquidity\n * for each leg of the given positions.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - Parameters\n * @returns Position chunk data with liquidity for each leg\n *\n * @example\n * ```typescript\n * const result = await getPositionChunkData({\n * client,\n * poolAddress: '0x...',\n * queryAddress: '0x...',\n * tokenIds: [tokenId1, tokenId2],\n * })\n *\n * for (const pos of result.positions) {\n * console.log(`Position ${pos.tokenId}:`)\n * for (const leg of pos.legs) {\n * console.log(` Leg ${leg.legIndex}: net=${leg.netLiquidity}, removed=${leg.removedLiquidity}`)\n * }\n * }\n * ```\n */\nexport async function getPositionChunkData(\n params: GetPositionChunkDataParams,\n): Promise<GetPositionChunkDataResult> {\n const {\n client,\n poolAddress,\n queryAddress,\n tokenIds,\n vegoid = DEFAULT_VEGOID,\n blockNumber,\n } = params\n\n if (tokenIds.length === 0) {\n const _meta = await getBlockMeta({ client, blockNumber })\n return { positions: [], _meta }\n }\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [chunkData, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getChunkData',\n args: [poolAddress, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // chunkData is uint256[2][4][] - [positionIndex][legIndex][0=net, 1=removed]\n const positions: PositionChunkData[] = tokenIds.map((tokenId, posIndex) => {\n const positionData = chunkData[posIndex]\n const legs: LegChunkData[] = []\n\n // Each position has up to 4 legs\n for (let legIndex = 0; legIndex < 4; legIndex++) {\n const legData = positionData[legIndex]\n const netLiquidity = legData[0]\n const removedLiquidity = legData[1]\n\n // Only include legs with data (non-zero liquidity indicates active leg)\n if (netLiquidity > 0n || removedLiquidity > 0n) {\n legs.push({\n legIndex,\n netLiquidity,\n removedLiquidity,\n spreadWad: calculateSpreadWad(netLiquidity, removedLiquidity, vegoid),\n })\n }\n }\n\n return { tokenId, legs }\n })\n\n return { positions, _meta }\n}\n","/**\n * Pending position tracking for optimistic updates.\n * @module v2/sync/pendingPositions\n */\n\nimport type { Address, Hash } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { getPendingPositionsKey, jsonSerializer } from '../storage'\nimport type { TokenIdLeg } from '../types'\n\n/**\n * A pending position that has been submitted but not yet confirmed.\n */\nexport interface PendingPosition {\n /** The TokenId */\n tokenId: bigint\n /** Owner address */\n owner: Address\n /** Pool address */\n poolAddress: Address\n /** Position size (from simulation) */\n positionSize: bigint\n /** Decoded legs */\n legs: TokenIdLeg[]\n /** Transaction hash */\n txHash: Hash\n /** Block number when submitted */\n submittedAtBlock: bigint\n /** Timestamp when submitted */\n submittedAt: bigint\n /** Status */\n status: 'pending' | 'confirmed' | 'failed'\n}\n\n/**\n * Parameters for adding a pending position.\n */\nexport interface AddPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Pending position data */\n position: PendingPosition\n}\n\n/**\n * Add a pending position for optimistic updates.\n *\n * Called when openPosition() submits a transaction.\n *\n * @param params - Parameters\n */\nexport async function addPendingPosition(params: AddPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, position } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n let pending: PendingPosition[]\n if (existingData) {\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n pending = []\n }\n } else {\n pending = []\n }\n\n // Add new pending position\n pending.push(position)\n\n await storage.set(key, jsonSerializer.stringify(pending))\n}\n\n/**\n * Parameters for getting pending positions.\n */\nexport interface GetPendingPositionsParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Get all pending positions for an account.\n *\n * @param params - Parameters\n * @returns Array of pending positions\n */\nexport async function getPendingPositions(\n params: GetPendingPositionsParams,\n): Promise<PendingPosition[]> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n try {\n const pending = jsonSerializer.parse(data) as PendingPosition[]\n // Only return pending status\n return pending.filter((p) => p.status === 'pending')\n } catch {\n return []\n }\n}\n\n/**\n * Parameters for confirming a pending position.\n */\nexport interface ConfirmPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Token ID to confirm */\n tokenId: bigint\n}\n\n/**\n * Mark a pending position as confirmed.\n *\n * Called when syncPositions() finds the OptionMinted event.\n *\n * @param params - Parameters\n */\nexport async function confirmPendingPosition(params: ConfirmPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, tokenId } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Find and update the position\n const updated = pending.map((p) =>\n p.tokenId === tokenId ? { ...p, status: 'confirmed' as const } : p,\n )\n\n // Remove confirmed positions (they're now in the main position list)\n const remaining = updated.filter((p) => p.status === 'pending')\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n\n/**\n * Parameters for failing a pending position.\n */\nexport interface FailPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Transaction hash that failed */\n txHash: Hash\n}\n\n/**\n * Mark a pending position as failed (transaction reverted).\n *\n * @param params - Parameters\n */\nexport async function failPendingPosition(params: FailPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, txHash } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Remove the failed position\n const remaining = pending.filter((p) => p.txHash !== txHash)\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n\n/**\n * Clear all pending positions for an account.\n *\n * @param params - Parameters\n */\nexport async function clearPendingPositions(params: GetPendingPositionsParams): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n await storage.delete(key)\n}\n\n/**\n * Clean up stale pending positions.\n *\n * Removes pending positions older than the specified block threshold.\n * This handles cases where transactions were dropped from the mempool.\n *\n * @param params - Parameters\n * @param maxAgeBlocks - Maximum age in blocks (default: 100)\n * @param currentBlock - Current block number\n */\nexport async function cleanupStalePendingPositions(\n params: GetPendingPositionsParams,\n currentBlock: bigint,\n maxAgeBlocks: bigint = 100n,\n): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Filter out stale positions\n const threshold = currentBlock - maxAgeBlocks\n const remaining = pending.filter((p) => p.status === 'pending' && p.submittedAtBlock > threshold)\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else if (remaining.length !== pending.length) {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n","/**\n * Event reconstruction for full position history scan.\n * @module v2/sync/eventReconstruction\n */\n\nimport type { Address, Hash, PublicClient } from 'viem'\n\nimport type { SyncEvent } from '../types'\n\n/**\n * Parameters for event reconstruction.\n */\nexport interface EventReconstructionParams {\n /** viem public client */\n client: PublicClient\n /** Pool address */\n poolAddress: Address\n /** Account to reconstruct positions for */\n account: Address\n /** Starting block for event scan */\n fromBlock: bigint\n /** Ending block for event scan */\n toBlock: bigint\n /** Batch size for log queries (default: 10000) */\n batchSize?: bigint\n /** Progress callback */\n onProgress?: (event: SyncEvent) => void\n}\n\n/**\n * Event reconstruction result.\n */\nexport interface EventReconstructionResult {\n /** Position IDs that are currently open */\n openPositions: bigint[]\n /** Position IDs that have been closed */\n closedPositions: bigint[]\n /** Number of blocks scanned */\n blocksScanned: bigint\n /** Last scanned block number */\n lastBlock: bigint\n /** Last scanned block hash */\n lastBlockHash: Hash\n}\n\n/**\n * Mint event from reconstruction.\n */\ninterface MintEvent {\n tokenId: bigint\n positionSize: bigint\n blockNumber: bigint\n blockHash: Hash\n transactionHash: Hash\n logIndex: number\n}\n\n/**\n * Burn event from reconstruction.\n */\ninterface BurnEvent {\n tokenId: bigint\n positionSize: bigint\n blockNumber: bigint\n blockHash: Hash\n transactionHash: Hash\n logIndex: number\n}\n\n/**\n * Reconstruct position history from events.\n * This is the fallback method when snapshot recovery fails.\n * It scans all OptionMinted and OptionBurnt events to build the position set.\n *\n * @param params - Reconstruction parameters\n * @returns Reconstruction result with open and closed positions\n */\nexport async function reconstructFromEvents(\n params: EventReconstructionParams,\n): Promise<EventReconstructionResult> {\n const {\n client,\n poolAddress,\n account,\n fromBlock,\n toBlock,\n batchSize = 10000n,\n onProgress,\n } = params\n\n const mintEvents: MintEvent[] = []\n const burnEvents: BurnEvent[] = []\n\n let currentBlock = fromBlock\n const totalBlocks = toBlock - fromBlock\n\n // Scan in batches\n while (currentBlock <= toBlock) {\n const endBlock =\n currentBlock + batchSize - 1n > toBlock ? toBlock : currentBlock + batchSize - 1n\n\n // Fetch mint events for this batch\n const [mints, burns] = await Promise.all([\n client.getLogs({\n address: poolAddress,\n event: {\n type: 'event',\n name: 'OptionMinted',\n inputs: [\n { type: 'address', name: 'recipient', indexed: true },\n { type: 'uint256', name: 'tokenId', indexed: true },\n { type: 'uint256', name: 'balanceData', indexed: false },\n ],\n },\n args: {\n recipient: account,\n },\n fromBlock: currentBlock,\n toBlock: endBlock,\n }),\n client.getLogs({\n address: poolAddress,\n event: {\n type: 'event',\n name: 'OptionBurnt',\n inputs: [\n { type: 'address', name: 'recipient', indexed: true },\n { type: 'uint256', name: 'tokenId', indexed: true },\n { type: 'uint256', name: 'positionSize', indexed: false },\n { type: 'int256[4]', name: 'premiaByLeg', indexed: false },\n ],\n },\n args: {\n recipient: account,\n },\n fromBlock: currentBlock,\n toBlock: endBlock,\n }),\n ])\n\n // Process mint events\n for (const mint of mints) {\n // Decode position size from balanceData (first 128 bits)\n const balanceData = mint.args.balanceData as bigint\n const positionSize = balanceData & ((1n << 128n) - 1n)\n\n mintEvents.push({\n tokenId: mint.args.tokenId as bigint,\n positionSize,\n blockNumber: mint.blockNumber,\n blockHash: mint.blockHash,\n transactionHash: mint.transactionHash,\n logIndex: mint.logIndex,\n })\n }\n\n // Process burn events\n for (const burn of burns) {\n burnEvents.push({\n tokenId: burn.args.tokenId as bigint,\n positionSize: burn.args.positionSize as bigint,\n blockNumber: burn.blockNumber,\n blockHash: burn.blockHash,\n transactionHash: burn.transactionHash,\n logIndex: burn.logIndex,\n })\n }\n\n // Report progress\n if (onProgress) {\n const blocksProcessed = endBlock - fromBlock + 1n\n const progress = totalBlocks > 0n ? (blocksProcessed * 100n) / totalBlocks : 100n\n\n onProgress({\n currentBlock: endBlock,\n targetBlock: toBlock,\n positionsFound: BigInt(mintEvents.length),\n progress,\n })\n }\n\n currentBlock = endBlock + 1n\n }\n\n // Build position map: tokenId -> net position size\n const positionMap = new Map<bigint, bigint>()\n\n // Sort all events by block and log index\n const allEvents = [\n ...mintEvents.map((e) => ({ ...e, type: 'mint' as const })),\n ...burnEvents.map((e) => ({ ...e, type: 'burn' as const })),\n ].sort((a, b) => {\n const blockDiff = Number(a.blockNumber - b.blockNumber)\n if (blockDiff !== 0) return blockDiff\n return a.logIndex - b.logIndex\n })\n\n // Process events in order\n for (const event of allEvents) {\n const current = positionMap.get(event.tokenId) ?? 0n\n\n if (event.type === 'mint') {\n positionMap.set(event.tokenId, current + event.positionSize)\n } else {\n positionMap.set(event.tokenId, current - event.positionSize)\n }\n }\n\n // Separate open and closed positions\n const openPositions: bigint[] = []\n const closedPositions: bigint[] = []\n\n for (const [tokenId, size] of positionMap) {\n if (size > 0n) {\n openPositions.push(tokenId)\n } else {\n closedPositions.push(tokenId)\n }\n }\n\n // Get the last block hash\n const lastBlock = await client.getBlock({ blockNumber: toBlock })\n\n return {\n openPositions,\n closedPositions,\n blocksScanned: toBlock - fromBlock + 1n,\n lastBlock: toBlock,\n lastBlockHash: lastBlock.hash,\n }\n}\n\n/**\n * Get the deployment block for a pool.\n * This searches for the first PoolInitialized event.\n *\n * @param client - viem public client\n * @param poolAddress - Pool address\n * @returns Deployment block number or null if not found\n */\nexport async function getPoolDeploymentBlock(\n client: PublicClient,\n poolAddress: Address,\n): Promise<bigint | null> {\n // Search for the first event from this pool\n // We use a binary search approach to find the deployment block\n\n const currentBlock = await client.getBlockNumber()\n let low = 0n\n let high = currentBlock\n let foundBlock: bigint | null = null\n\n // Binary search with scan windows to find the deployment block.\n // Each iteration checks [mid, mid + scanRange] for logs.\n const scanRange = 10000n\n\n while (low <= high) {\n const mid = (low + high) / 2n\n const rangeEnd = mid + scanRange > high ? high : mid + scanRange\n\n try {\n const logs = await client.getLogs({\n address: poolAddress,\n fromBlock: mid,\n toBlock: rangeEnd,\n })\n\n if (logs.length > 0) {\n // Found logs — record earliest and search before it\n const earliest = logs[0].blockNumber\n if (foundBlock === null || earliest < foundBlock) {\n foundBlock = earliest\n }\n high = earliest - 1n\n } else {\n // No logs in [mid, rangeEnd] — skip the entire checked range\n low = rangeEnd + 1n\n }\n } catch {\n // Range too large for RPC — halve the search space\n high = mid + (rangeEnd - mid) / 2n\n }\n }\n\n return foundBlock\n}\n","/**\n * Item-based wrapper around simulateDispatch for batched mint/burn ops.\n * @module v2/simulations/simulateBatchDispatch\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { buildBatchDispatchArgs } from '../batch/build'\nimport type { BatchDiagnostic, BatchOp } from '../batch/types'\nimport { getBlockMeta } from '../clients'\nimport type { BlockMeta, DispatchSimulation, SimulationResult } from '../types'\nimport { simulateDispatch } from './simulateDispatch'\n\n/**\n * Parameters for `simulateBatchDispatch`.\n *\n * - `client`: viem PublicClient used for read calls.\n * - `poolAddress`: PanopticPool address the batch targets.\n * - `account`: account whose collateral and positions are simulated against.\n * - `items`: ordered batch ops (mints + burns) — order matters because dispatch\n * applies them sequentially.\n * - `existingPositionIds`: account's current on-chain `positionIdList`. Must\n * reflect FRESH on-chain state (not a cached/optimistic snapshot) — stale\n * data here yields incorrect pre-dispatch margin excess and false\n * burn-not-found diagnostics.\n * - `usePremiaAsCollateral`: applied across the whole dispatch. Defaults to\n * `false`.\n * - `builderCode`: applied across the whole dispatch. Defaults to `0n`.\n * - `blockNumber`: optional pinned block; defaults to the client's latest.\n */\nexport interface SimulateBatchDispatchParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n /** Batch ops in operation order. */\n items: BatchOp[]\n /** Current on-chain positionIdList for the account (fresh). */\n existingPositionIds: bigint[]\n /** Apply across the whole dispatch. Defaults to false. */\n usePremiaAsCollateral?: boolean\n /** Apply across the whole dispatch. Defaults to 0n. */\n builderCode?: bigint\n /** Optional pinned block. */\n blockNumber?: bigint\n}\n\n/**\n * Result returned by `simulateBatchDispatch`.\n *\n * Either delegates to `simulateDispatch` (and therefore matches its\n * `SimulationResult<DispatchSimulation>` shape), or short-circuits with\n * batch-level diagnostics when the items fail validation. In either case the\n * shape includes a `diagnostics` field so callers can render conflicts before\n * deciding what to do — UIs typically gray out the Execute button when\n * `diagnostics.length > 0`.\n */\nexport type SimulateBatchDispatchResult =\n | (SimulationResult<DispatchSimulation> & { diagnostics: BatchDiagnostic[] })\n | { success: false; diagnostics: BatchDiagnostic[]; _meta: BlockMeta }\n\n/**\n * Simulate a batch dispatch built from `items` + the current on-chain\n * positionIdList. Returns batch diagnostics OR a real simulation result.\n */\nexport async function simulateBatchDispatch(\n params: SimulateBatchDispatchParams,\n): Promise<SimulateBatchDispatchResult> {\n const {\n client,\n poolAddress,\n account,\n items,\n existingPositionIds,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n } = params\n\n const { args, diagnostics } = buildBatchDispatchArgs({\n items,\n existingPositionIds,\n usePremiaAsCollateral,\n builderCode,\n })\n\n if (args === null) {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const meta = await getBlockMeta({ client, blockNumber: targetBlockNumber })\n return { success: false, diagnostics, _meta: meta }\n }\n\n const sim = await simulateDispatch({\n client,\n poolAddress,\n account,\n positionIdList: args.positionIdList,\n finalPositionIdList: args.finalPositionIdList,\n existingPositionIdList: existingPositionIds,\n positionSizes: args.positionSizes,\n tickAndSpreadLimits: args.tickAndSpreadLimits,\n usePremiaAsCollateral: args.usePremiaAsCollateral,\n builderCode: args.builderCode,\n blockNumber,\n })\n\n return { ...sim, diagnostics: [] }\n}\n","/**\n * Close position simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateClosePosition\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { ClosePositionSimulation, SimulationResult } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating position closing.\n */\nexport interface SimulateClosePositionParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Current position ID list */\n positionIdList: bigint[]\n /** TokenId of position to close */\n tokenId: bigint\n /** Position size to close */\n positionSize: bigint\n /**\n * Lower tick limit (always <= tickLimitHigh).\n * Use MIN_TICK (-887272n) to allow any downward price movement.\n */\n tickLimitLow: bigint\n /**\n * Upper tick limit (always >= tickLimitLow).\n * Use MAX_TICK (887272n) to allow any upward price movement.\n */\n tickLimitHigh: bigint\n /** Spread limit tick (use 0n for no spread limit) */\n spreadLimit?: bigint\n /**\n * Whether to swap tokens at burn to achieve single-sided exposure.\n * When true, tickLimits are passed to dispatch in descending order (high, low).\n * When false (default), tickLimits are passed in ascending order (low, high).\n */\n swapAtMint?: boolean\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Builder code */\n builderCode?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate closing a position.\n *\n * Uses PanopticPool.multicall with getAssetsOf-dispatch-getAssetsOf pattern\n * to measure exact collateral asset movements from the burn.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with close data or error\n */\nexport async function simulateClosePosition(\n params: SimulateClosePositionParams,\n): Promise<SimulationResult<ClosePositionSimulation>> {\n const {\n client,\n poolAddress,\n account,\n positionIdList,\n tokenId,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit = 0n,\n swapAtMint = false,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Build tick limits based on swapAtMint flag:\n // - swapAtMint=true: descending order (high, low) triggers SFPM swap\n // - swapAtMint=false: ascending order (low, high) no swap\n const tickLimits: readonly [number, number, number] = swapAtMint\n ? [Number(tickLimitHigh), Number(tickLimitLow), Number(spreadLimit)]\n : [Number(tickLimitLow), Number(tickLimitHigh), Number(spreadLimit)]\n\n try {\n // Prepare final position list (without the closed position)\n const finalPositionIdList = positionIdList.filter((id) => id !== tokenId)\n\n // Encode dispatch call data for burn (positionSize = 0 signals close)\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId],\n finalPositionIdList,\n [0n],\n [tickLimits],\n usePremiaAsCollateral,\n builderCode,\n ],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow = flowResult.tokenFlow\n const _meta = await metaPromise\n\n // Map token flow to simulation fields:\n // Positive delta = user receives collateral back\n const data: ClosePositionSimulation = {\n amount0Received: tokenFlow.delta0,\n amount1Received: tokenFlow.delta1,\n premiaCollected0: null, // Requires pre-close premia snapshot\n premiaCollected1: null,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n realizedPnL0: null, // Requires open position cost basis\n realizedPnL1: null,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","/**\n * Force exercise simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateForceExercise\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { ForceExerciseSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating force exercise.\n */\nexport interface SimulateForceExerciseParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Exercisor account address */\n account: Address\n /** Account whose position is being exercised */\n user: Address\n /** Position IDs from the exercisor's account */\n positionIdListFrom: bigint[]\n /** Position IDs of the target user */\n positionIdListTo: bigint[]\n /** Final position ID list for the user after exercise */\n positionIdListToFinal: bigint[]\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a force exercise operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with exercise data or error\n */\nexport async function simulateForceExercise(\n params: SimulateForceExerciseParams,\n): Promise<SimulationResult<ForceExerciseSimulation>> {\n const {\n client,\n poolAddress,\n account,\n user,\n positionIdListFrom,\n positionIdListTo,\n positionIdListToFinal,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Default token flow for failure cases\n const emptyTokenFlow: TokenFlow = {\n delta0: 0n,\n delta1: 0n,\n balanceBefore0: 0n,\n balanceBefore1: 0n,\n balanceAfter0: 0n,\n balanceAfter1: 0n,\n tickBefore: null,\n tickAfter: null,\n }\n\n try {\n // Encode dispatchFrom call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatchFrom',\n args: [positionIdListFrom, user, positionIdListTo, positionIdListToFinal, 0n],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account, // Measure exercisor's collateral change\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n // Check for specific exercise-related errors\n const errorMessage = flowResult.error || 'Simulation failed'\n const isNotExercisable =\n errorMessage.includes('NoLegsExercisable') || errorMessage.includes('NotALongLeg')\n\n if (isNotExercisable) {\n const _meta = await metaPromise\n const data: ForceExerciseSimulation = {\n exerciseFee0: 0n,\n exerciseFee1: 0n,\n canExercise: false,\n reason: errorMessage.includes('NoLegsExercisable')\n ? 'No legs are exercisable (not ITM)'\n : 'Position does not have a long leg',\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n throw new PanopticError(errorMessage)\n }\n\n const _meta = await metaPromise\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Build simulation result with actual token flow data\n // Exercise fee is what the exercisor receives (positive delta)\n const data: ForceExerciseSimulation = {\n exerciseFee0: tokenFlow.delta0,\n exerciseFee1: tokenFlow.delta1,\n canExercise: true,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n // If simulation fails, check the reason\n const errorMessage = error instanceof Error ? error.message : 'Simulation failed'\n\n // Check for specific exercise-related errors\n const isNotExercisable =\n errorMessage.includes('NoLegsExercisable') || errorMessage.includes('NotALongLeg')\n\n if (isNotExercisable) {\n const data: ForceExerciseSimulation = {\n exerciseFee0: 0n,\n exerciseFee1: 0n,\n canExercise: false,\n reason: errorMessage.includes('NoLegsExercisable')\n ? 'No legs are exercisable (not ITM)'\n : 'Position does not have a long leg',\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(errorMessage, error instanceof Error ? error : undefined),\n _meta,\n }\n }\n}\n","/**\n * Liquidation simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateLiquidate\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { LiquidateSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating liquidation.\n */\nexport interface SimulateLiquidateParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Liquidator account address */\n account: Address\n /** Account being liquidated */\n liquidatee: Address\n /** Position IDs from the liquidator's account */\n positionIdListFrom: bigint[]\n /** Position IDs of the liquidatee */\n positionIdListTo: bigint[]\n /** Final position ID list for the liquidatee after liquidation */\n positionIdListToFinal: bigint[]\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a liquidation operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with liquidation data or error\n */\nexport async function simulateLiquidate(\n params: SimulateLiquidateParams,\n): Promise<SimulationResult<LiquidateSimulation>> {\n const {\n client,\n poolAddress,\n account,\n liquidatee,\n positionIdListFrom,\n positionIdListTo,\n positionIdListToFinal,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Default token flow for failure cases\n const emptyTokenFlow: TokenFlow = {\n delta0: 0n,\n delta1: 0n,\n balanceBefore0: 0n,\n balanceBefore1: 0n,\n balanceAfter0: 0n,\n balanceAfter1: 0n,\n tickBefore: null,\n tickAfter: null,\n }\n\n try {\n // Encode dispatchFrom call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatchFrom',\n args: [positionIdListFrom, liquidatee, positionIdListTo, positionIdListToFinal, 0n],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account, // Measure liquidator's collateral change\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n // Check if it's a specific error indicating not liquidatable\n const errorMessage = flowResult.error || 'Simulation failed'\n const isNotLiquidatable =\n errorMessage.includes('NotMarginCalled') || errorMessage.includes('AccountInsolvent')\n\n if (isNotLiquidatable) {\n const _meta = await metaPromise\n const data: LiquidateSimulation = {\n bonus0: 0n,\n bonus1: 0n,\n positionsClosed: [],\n isLiquidatable: false,\n shortfall0: 0n,\n shortfall1: 0n,\n }\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n throw new PanopticError(errorMessage)\n }\n\n const _meta = await metaPromise\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Positions that would be closed\n const positionsClosed = positionIdListTo.filter((id) => !positionIdListToFinal.includes(id))\n\n // Build simulation result with actual token flow data\n // Positive delta = liquidator receives bonus\n const data: LiquidateSimulation = {\n bonus0: tokenFlow.delta0 > 0n ? tokenFlow.delta0 : 0n,\n bonus1: tokenFlow.delta1 > 0n ? tokenFlow.delta1 : 0n,\n positionsClosed,\n isLiquidatable: true,\n shortfall0: 0n, // Would need additional calculation\n shortfall1: 0n,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n // If simulation fails, the account might not be liquidatable\n const errorMessage = error instanceof Error ? error.message : 'Simulation failed'\n const isNotLiquidatable =\n errorMessage.includes('NotMarginCalled') || errorMessage.includes('AccountInsolvent')\n\n if (isNotLiquidatable) {\n const data: LiquidateSimulation = {\n bonus0: 0n,\n bonus1: 0n,\n positionsClosed: [],\n isLiquidatable: false,\n shortfall0: 0n,\n shortfall1: 0n,\n }\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(errorMessage, error instanceof Error ? error : undefined),\n _meta,\n }\n }\n}\n","/**\n * Settle simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateSettle\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { SettleSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/** BIT_MASK_128 = (1n << 128n) - 1n */\nconst BIT_MASK_128 = (1n << 128n) - 1n\n\n/**\n * PanopticPool multicall ABI (inherited from Uniswap).\n */\nconst multicallAbi = [\n {\n type: 'function',\n name: 'multicall',\n inputs: [{ name: 'data', type: 'bytes[]' }],\n outputs: [{ name: 'results', type: 'bytes[]' }],\n stateMutability: 'nonpayable',\n },\n] as const\n\n/**\n * Parameters for simulating premium settlement.\n */\nexport interface SimulateSettleParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Current position ID list */\n positionIdList: bigint[]\n /** Optional tokenId to compute forfeit amounts for */\n tokenId?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate premium settlement.\n *\n * When `tokenId` is provided, the simulation also computes forfeit amounts\n * by chaining the dispatch with `getFullPositionsData` reads\n * in a single multicall.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with settlement data or error\n */\nexport async function simulateSettle(\n params: SimulateSettleParams,\n): Promise<SimulationResult<SettleSimulation>> {\n const { client, poolAddress, account, positionIdList, tokenId, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // For settlement, we call dispatch with unchanged position lists\n const positionSizes = positionIdList.map(() => 0n)\n const tickAndSpreadLimits = positionIdList.map(() => [-887272n, 887272n, 0n] as const)\n\n // Encode dispatch call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n positionIdList,\n positionIdList,\n positionSizes.map((s) => BigInt(s) as unknown as bigint & { readonly __uint128: true }),\n tickAndSpreadLimits.map(\n (t) => [Number(t[0]), Number(t[1]), Number(t[2])] as readonly [number, number, number],\n ),\n false,\n 0n,\n ],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Compute forfeit amounts if tokenId is provided\n let forfeitAmounts: [bigint, bigint] | undefined\n if (tokenId !== undefined) {\n forfeitAmounts = await computeForfeitAmounts({\n client,\n poolAddress,\n account,\n positionIdList,\n tokenId,\n dispatchCallData: callData,\n blockNumber: targetBlockNumber,\n })\n }\n\n const _meta = await metaPromise\n\n // Build simulation result with actual token flow data\n // Positive delta = premia received\n const data: SettleSimulation = {\n premiaReceived0: tokenFlow.delta0 > 0n ? tokenFlow.delta0 : 0n,\n premiaReceived1: tokenFlow.delta1 > 0n ? tokenFlow.delta1 : 0n,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n forfeitAmounts,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n\n/**\n * Compute forfeit amounts by chaining dispatch + getFullPositionsData\n * in a single PanopticPool.multicall.\n */\nasync function computeForfeitAmounts(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n positionIdList: bigint[]\n tokenId: bigint\n dispatchCallData: Hex\n blockNumber: bigint\n}): Promise<[bigint, bigint]> {\n const { client, poolAddress, account, tokenId, dispatchCallData, blockNumber } = params\n\n // Encode getFullPositionsData calls (available = false, total = true)\n const feesCallAvailable = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, [tokenId]],\n })\n const feesCallTotal = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, [tokenId]],\n })\n\n try {\n // Chain: dispatch (settle) + fees(available) + fees(total) in one multicall\n const { result } = await client.simulateContract({\n address: poolAddress,\n abi: multicallAbi,\n functionName: 'multicall',\n args: [[dispatchCallData, feesCallAvailable, feesCallTotal]],\n account,\n blockNumber,\n })\n\n // Decode the two fee reads (result[0] is dispatch, result[1] and result[2] are fees)\n const decodeFeesResult = (data: Hex): bigint => {\n return decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data,\n })[0]\n }\n\n const availablePremium = decodeFeesResult(result[1])\n const totalPremium = decodeFeesResult(result[2])\n\n const available0 = availablePremium & BIT_MASK_128\n const available1 = availablePremium >> 128n\n const total0 = totalPremium & BIT_MASK_128\n const total1 = totalPremium >> 128n\n\n return [total0 - available0, total1 - available1]\n } catch (error) {\n throw new PanopticError(\n 'Forfeit amount computation failed',\n error instanceof Error ? error : undefined,\n )\n }\n}\n","/**\n * Vault simulation functions for the Panoptic v2 SDK.\n * @module v2/simulations/simulateVault\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { DepositSimulation, SimulationResult, WithdrawSimulation } from '../types'\n\n/**\n * Parameters for simulating deposit.\n */\nexport interface SimulateDepositParams {\n /** Public client */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Assets to deposit */\n assets: bigint\n /** Whether the collateral tracker wraps native ETH (requires sending msg.value) */\n isNativeETH?: boolean\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a deposit operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with deposit data or error\n */\nexport async function simulateDeposit(\n params: SimulateDepositParams,\n): Promise<SimulationResult<DepositSimulation>> {\n const { client, collateralTrackerAddress, account, assets, isNativeETH, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Run multicall (historical block), gas estimate (latest), and block meta in parallel\n const [[currentShares, currentAssets, previewedShares], gasEstimate, _meta] = await Promise.all(\n [\n client.multicall({\n contracts: [\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'balanceOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewDeposit',\n args: [assets],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n }),\n client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'deposit',\n args: [assets, account],\n account,\n ...(isNativeETH && { value: assets }),\n blockNumber: targetBlockNumber,\n }),\n metaPromise,\n ],\n )\n\n const data: DepositSimulation = {\n sharesMinted: previewedShares,\n postAssets: currentAssets + assets,\n postShares: currentShares + previewedShares,\n }\n\n return {\n success: true,\n data,\n gasEstimate,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n\n/**\n * Parameters for simulating withdrawal.\n */\nexport interface SimulateWithdrawParams {\n /** Public client */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Assets to withdraw */\n assets: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a withdrawal operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with withdrawal data or error\n */\nexport async function simulateWithdraw(\n params: SimulateWithdrawParams,\n): Promise<SimulationResult<WithdrawSimulation>> {\n const { client, collateralTrackerAddress, account, assets, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Get current state\n const [currentShares, currentAssets, maxWithdrawable, previewedShares] = await client.multicall(\n {\n contracts: [\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'balanceOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxWithdraw',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewWithdraw',\n args: [assets],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n },\n )\n\n // Check if withdrawal is possible\n const canWithdraw = assets <= maxWithdrawable\n\n const _meta = await metaPromise\n\n if (!canWithdraw) {\n const data: WithdrawSimulation = {\n sharesBurned: 0n,\n assetsReceived: 0n,\n postAssets: currentAssets,\n postShares: currentShares,\n canWithdraw: false,\n reason: `Requested ${assets}, but max withdrawable is ${maxWithdrawable}`,\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n _meta,\n }\n }\n\n const gasEstimate = await client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'withdraw',\n args: [assets, account, account],\n account,\n blockNumber: targetBlockNumber,\n })\n\n const data: WithdrawSimulation = {\n sharesBurned: previewedShares,\n assetsReceived: assets,\n postAssets: currentAssets - assets,\n postShares: currentShares - previewedShares,\n canWithdraw: true,\n }\n\n return {\n success: true,\n data,\n gasEstimate,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","/**\n * SFPM simulation functions for the Panoptic v2 SDK.\n *\n * These simulate `mintTokenizedPosition` and `burnTokenizedPosition` on the\n * SemiFungiblePositionManager, called with `account: poolAddress` (the pool\n * is the caller in the actual protocol flow).\n *\n * @module v2/simulations/sfpm\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { encodeAbiParameters } from 'viem'\n\nimport { semiFungiblePositionManagerV4Abi } from '../../../generated'\nimport type { PoolKey } from '../types'\n\n/**\n * Encode a V4 PoolKey struct as bytes for the SFPM.\n */\nexport function encodePoolKeyBytes(poolKey: PoolKey): Hex {\n return encodeAbiParameters(\n [\n {\n type: 'tuple',\n components: [\n { name: 'currency0', type: 'address' },\n { name: 'currency1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickSpacing', type: 'int24' },\n { name: 'hooks', type: 'address' },\n ],\n },\n ],\n [\n {\n currency0: poolKey.currency0,\n currency1: poolKey.currency1,\n fee: Number(poolKey.fee),\n tickSpacing: Number(poolKey.tickSpacing),\n hooks: poolKey.hooks,\n },\n ],\n )\n}\n\n/**\n * Encode a V3 pool address as poolKey bytes for the V3 SFPM.\n * V3 SFPM expects `abi.encode(uniswapV3PoolAddress)`.\n */\nexport function encodeV3PoolKeyBytes(v3PoolAddress: Address): Hex {\n return encodeAbiParameters([{ type: 'address' }], [v3PoolAddress])\n}\n\n/**\n * Parameters for simulating an SFPM mint or burn.\n */\nexport interface SimulateSFPMParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManager address */\n sfpmAddress: Address\n /** PanopticPool address (used as `account` — the pool is the caller) */\n poolAddress: Address\n /** Encoded pool key (bytes) */\n poolKey: Hex\n /** TokenId to mint/burn */\n tokenId: bigint\n /** Position size (uint128) */\n positionSize: bigint\n /** Lower tick limit */\n tickLimitLow: number\n /** Upper tick limit */\n tickLimitHigh: number\n}\n\n/** Return type from SFPM mintTokenizedPosition / burnTokenizedPosition */\nexport type SFPMSimulationResult = readonly [\n readonly [bigint, bigint, bigint, bigint],\n bigint,\n number,\n]\n\n/**\n * Simulate an SFPM mintTokenizedPosition call.\n *\n * @param params - Simulation parameters\n * @returns The result tuple: [collectedAmounts[4], totalSwapped, newTick]\n */\nexport async function simulateSFPMMint(params: SimulateSFPMParams): Promise<SFPMSimulationResult> {\n const {\n client,\n sfpmAddress,\n poolAddress,\n poolKey,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n } = params\n\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'mintTokenizedPosition',\n args: [\n poolKey,\n tokenId,\n BigInt(positionSize) as bigint & { readonly __uint128: true },\n tickLimitLow,\n tickLimitHigh,\n ],\n account: poolAddress,\n })\n\n return result\n}\n\n/**\n * Simulate an SFPM burnTokenizedPosition call.\n *\n * @param params - Simulation parameters\n * @returns The result tuple: [collectedAmounts[4], totalSwapped, newTick]\n */\nexport async function simulateSFPMBurn(params: SimulateSFPMParams): Promise<SFPMSimulationResult> {\n const {\n client,\n sfpmAddress,\n poolAddress,\n poolKey,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n } = params\n\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'burnTokenizedPosition',\n args: [\n poolKey,\n tokenId,\n BigInt(positionSize) as bigint & { readonly __uint128: true },\n tickLimitLow,\n tickLimitHigh,\n ],\n account: poolAddress,\n })\n\n return result\n}\n","/**\n * Swap simulation for the Panoptic v2 SDK.\n *\n * Mirrors `writes/swap.ts`, which swaps via width=0 **credit** legs rather than\n * loans so the swap can never be capped by a collateral tracker's utilization.\n *\n * @module v2/simulations/simulateSwap\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport { tickLimits } from '../formatters/tick'\nimport { getPool } from '../reads/pool'\nimport type { SimulationResult, TokenFlow } from '../types'\nimport { buildUniqueCredit, resolveTokenIndex } from '../writes/loanUtils'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Swap simulation data.\n */\nexport interface SwapSimulation {\n /** Amount of tokenIn spent (positive) */\n amountIn: bigint\n /** Amount of tokenOut received (positive) */\n amountOut: bigint\n /** Raw token flow from the simulation */\n tokenFlow: TokenFlow\n}\n\n/**\n * Parameters for simulateSwapExactOut.\n */\nexport interface SimulateSwapExactOutParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Chain ID */\n chainId: bigint\n /** Token address to receive */\n tokenOut: Address\n /** Exact amount of tokenOut */\n amountOut: bigint\n /** Slippage tolerance in bps */\n slippageBps: bigint\n /** Existing position IDs */\n existingPositionIds: bigint[]\n /** Builder code for referral fee attribution. Defaults to `0n`. */\n builderCode?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Parameters for simulateSwapExactIn.\n */\nexport interface SimulateSwapExactInParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Chain ID */\n chainId: bigint\n /** Token address to sell */\n tokenIn: Address\n /** Exact amount of tokenIn */\n amountIn: bigint\n /** Slippage tolerance in bps */\n slippageBps: bigint\n /** Existing position IDs */\n existingPositionIds: bigint[]\n /** Builder code for referral fee attribution. Defaults to `0n`. */\n builderCode?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Build dispatch calldata for swap simulation.\n */\nfunction buildSwapCallData(\n creditTokenId: bigint,\n existingPositionIds: bigint[],\n amount: bigint,\n mintTickLimits: readonly [number, number, number],\n burnTickLimits: readonly [number, number, number],\n builderCode: bigint,\n): `0x${string}` {\n return encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [creditTokenId, creditTokenId],\n [...existingPositionIds],\n [amount, 0n],\n [mintTickLimits, burnTickLimits],\n false,\n builderCode,\n ],\n })\n}\n\n/**\n * Build SwapSimulation from token flow, given which token index is \"out\".\n */\nfunction buildSwapResult(tokenFlow: TokenFlow, tokenOutIndex: bigint): SwapSimulation {\n // delta is negative when user deposits, positive when user receives\n // For a swap: one delta should be negative (spent) and one positive (received)\n const delta0 = tokenFlow.delta0\n const delta1 = tokenFlow.delta1\n\n if (tokenOutIndex === 0n) {\n return {\n amountOut: delta0 > 0n ? delta0 : -delta0,\n amountIn: delta1 < 0n ? -delta1 : delta1,\n tokenFlow,\n }\n } else {\n return {\n amountOut: delta1 > 0n ? delta1 : -delta1,\n amountIn: delta0 < 0n ? -delta0 : delta0,\n tokenFlow,\n }\n }\n}\n\n/**\n * Simulate an exact-output swap.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with swap data or error\n */\nexport async function simulateSwapExactOut(\n params: SimulateSwapExactOutParams,\n): Promise<SimulationResult<SwapSimulation>> {\n const {\n client,\n poolAddress,\n account,\n chainId,\n tokenOut,\n amountOut,\n slippageBps,\n existingPositionIds,\n builderCode = 0n,\n blockNumber,\n } = params\n\n try {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n const pool = await getPool({ client, poolAddress, chainId, blockNumber: targetBlockNumber })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const tokenOutIndex = resolveTokenIndex(tokenOut, token0, token1)\n // Credit is denominated in the exact token (tokenOut); asset === tokenType.\n // Using the counter-token here is the loan convention and inverts the swap.\n const tokenType = tokenOutIndex\n\n const { low: tickLimitLow, high: tickLimitHigh } = tickLimits(pool.currentTick, slippageBps)\n\n const { tokenId: creditTokenId, adjustedSize } = buildUniqueCredit(\n pool.poolId,\n tokenOutIndex,\n tokenType,\n pool.currentTick,\n pool.tickSpacing,\n existingPositionIds,\n amountOut,\n )\n\n // Mint: swapAtMint=true (descending), Burn: swapAtMint=false (ascending)\n const mintTickLimits: readonly [number, number, number] = [\n Number(tickLimitHigh),\n Number(tickLimitLow),\n 0,\n ]\n const burnTickLimits: readonly [number, number, number] = [\n Number(tickLimitLow),\n Number(tickLimitHigh),\n 0,\n ]\n\n const callData = buildSwapCallData(\n creditTokenId,\n existingPositionIds,\n adjustedSize,\n mintTickLimits,\n burnTickLimits,\n builderCode,\n )\n\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw flowResult.rawError ?? new PanopticError(flowResult.error || 'Swap simulation failed')\n }\n\n const _meta = await metaPromise\n const data = buildSwapResult(flowResult.tokenFlow, tokenOutIndex)\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow: flowResult.tokenFlow,\n _meta,\n }\n } catch (error) {\n // Build a fallback _meta if getBlockMeta also failed\n const fallbackMeta = { blockNumber: 0n, blockTimestamp: 0n, blockHash: '0x0' as `0x${string}` }\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta: fallbackMeta,\n }\n }\n}\n\n/**\n * Simulate an exact-input swap.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with swap data or error\n */\nexport async function simulateSwapExactIn(\n params: SimulateSwapExactInParams,\n): Promise<SimulationResult<SwapSimulation>> {\n const {\n client,\n poolAddress,\n account,\n chainId,\n tokenIn,\n amountIn,\n slippageBps,\n existingPositionIds,\n builderCode = 0n,\n blockNumber,\n } = params\n\n try {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n const pool = await getPool({ client, poolAddress, chainId, blockNumber: targetBlockNumber })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const tokenInIndex = resolveTokenIndex(tokenIn, token0, token1)\n const tokenType = tokenInIndex\n\n const { low: tickLimitLow, high: tickLimitHigh } = tickLimits(pool.currentTick, slippageBps)\n\n const { tokenId: creditTokenId, adjustedSize } = buildUniqueCredit(\n pool.poolId,\n tokenInIndex,\n tokenType,\n pool.currentTick,\n pool.tickSpacing,\n existingPositionIds,\n amountIn,\n )\n\n // Mint: swapAtMint=false (ascending), Burn: swapAtMint=true (descending)\n const mintTickLimits: readonly [number, number, number] = [\n Number(tickLimitLow),\n Number(tickLimitHigh),\n 0,\n ]\n const burnTickLimits: readonly [number, number, number] = [\n Number(tickLimitHigh),\n Number(tickLimitLow),\n 0,\n ]\n\n // tokenOut is the OTHER token\n const tokenOutIndex = tokenInIndex === 0n ? 1n : 0n\n\n const callData = buildSwapCallData(\n creditTokenId,\n existingPositionIds,\n adjustedSize,\n mintTickLimits,\n burnTickLimits,\n builderCode,\n )\n\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw flowResult.rawError ?? new PanopticError(flowResult.error || 'Swap simulation failed')\n }\n\n const _meta = await metaPromise\n const data = buildSwapResult(flowResult.tokenFlow, tokenOutIndex)\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow: flowResult.tokenFlow,\n _meta,\n }\n } catch (error) {\n const fallbackMeta = { blockNumber: 0n, blockTimestamp: 0n, blockHash: '0x0' as `0x${string}` }\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta: fallbackMeta,\n }\n }\n}\n","/**\n * Price conversion between the two pool tokens at a given sqrtPriceX96.\n *\n * Mirrors the on-chain `PanopticMath.convert0to1` / `convert1to0` truncation,\n * with an overflow-safe branch for when `sqrtPriceX96^2` would not fit in a\n * uint256.\n *\n * @module v2/utils/priceConvert\n */\n\nimport { PanopticError } from '../errors'\n\nconst Q128 = 1n << 128n\n\n/**\n * A non-positive price has no meaningful conversion, and `convert1to0` would\n * divide by zero — surface that as a typed SDK error rather than a RangeError\n * thrown from inside the arithmetic.\n */\nfunction assertPositivePrice(sqrtPriceX96: bigint): void {\n if (sqrtPriceX96 <= 0n) {\n throw new PanopticError(`sqrtPriceX96 must be positive, got ${sqrtPriceX96}`)\n }\n}\n\n/** Convert a token0 amount to its token1-equivalent at the given sqrtPriceX96. */\nexport function convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n assertPositivePrice(sqrtPriceX96)\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\n/** Convert a token1 amount to its token0-equivalent at the given sqrtPriceX96. */\nexport function convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n assertPositivePrice(sqrtPriceX96)\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Convert an amount denominated in `fromTokenIndex` into the other token's\n * terms, so the two sides of a pool flow can be compared on one scale.\n */\nexport function convertToTokenIndex(\n amount: bigint,\n fromTokenIndex: bigint,\n toTokenIndex: bigint,\n sqrtPriceX96: bigint,\n): bigint {\n if (fromTokenIndex === toTokenIndex) return amount\n return fromTokenIndex === 0n\n ? convert0to1(amount, sqrtPriceX96)\n : convert1to0(amount, sqrtPriceX96)\n}\n","/**\n * \"One token out\": force the net token flow of an arbitrary dispatch into a\n * single collateral token.\n *\n * Closing a multi-leg position normally settles in BOTH collateral tokens — a\n * straddle with one ITM leg pays out in one and charges in the other. This\n * module wraps the user's dispatch with a temporary width=0 credit leg that\n * cancels the non-target side, so the account's net change is (up to dust) in\n * one token only.\n *\n * Generalises {@link quoteTokenShortfallRecovery}, which handles the same\n * mechanism but only in the \"user is short a token\" direction and only when the\n * pool has already reverted with `NotEnoughTokens`.\n *\n * @module v2/simulations/oneTokenFlow\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { PanopticError } from '../errors'\nimport { getPool } from '../reads/pool'\nimport type { BlockMeta, TokenFlow } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport { convertToTokenIndex } from '../utils/priceConvert'\nimport { buildUniqueCredit } from '../writes/loanUtils'\nimport {\n type CreditWrapDirection,\n type DispatchIntent,\n buildCreditWrappedDispatch,\n} from './creditWrap'\nimport { simulateDispatch } from './simulateDispatch'\nimport { getNotEnoughTokensError } from './tokenShortfallRecovery'\n\nconst BPS_DENOMINATOR = 10_000n\n\n/**\n * Default {@link OneTokenFlowQuoteParams.minSwapRatioBps}: 0.5%.\n *\n * A swap pays a pool fee of roughly 5-30 bps plus slippage, so a non-target\n * flow below this fraction of the target flow cannot pay for itself — while\n * still leaving any residual small enough not to surprise someone who asked to\n * settle in one token.\n */\nexport const DEFAULT_MIN_SWAP_RATIO_BPS = 50n\n\nexport interface OneTokenFlowQuoteParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n chainId: bigint\n /** The user's actual on-chain position list BEFORE the dispatch. */\n existingPositionIds: bigint[]\n /** The dispatch the user is about to send, unwrapped. */\n dispatch: DispatchIntent\n /** Index of the token the whole net flow should land in: `0n` or `1n`. */\n targetTokenIndex: bigint\n /**\n * Slippage tolerance for the credit swap, in **basis points** (1% = 100).\n * Applied to the estimated target-token cost of an exact-out swap to produce\n * `maximumAmountIn`. Values above `10_000` (100%) are rejected.\n */\n slippageBps: bigint\n /**\n * Minimum size of the non-target flow, in **basis points** of the target\n * token's own flow, for the swap to be worth doing. Below this the residual\n * is dust and the swap would cost more in pool fee and slippage than it\n * settles, so the quote reports `below-threshold` and the caller falls back\n * to the native two-token flow. Defaults to\n * {@link DEFAULT_MIN_SWAP_RATIO_BPS}. Pass `0n` to always swap.\n *\n * Only applied when the unwrapped dispatch simulates successfully. When it\n * reverts on a shortfall, the swap is what makes the transaction possible at\n * all, so no threshold is applied.\n */\n minSwapRatioBps?: bigint\n /**\n * Price bound for the temporary credit legs. Defaults to the full tick range —\n * the swap is protected economically by the balance check, not by a price\n * band, and the user's own operations keep their own limits.\n */\n tickLimitLow?: bigint\n /** See {@link OneTokenFlowQuoteParams.tickLimitLow}. */\n tickLimitHigh?: bigint\n blockNumber?: bigint\n}\n\nexport interface OneTokenFlowQuote {\n targetToken: Address\n otherToken: Address\n targetTokenIndex: bigint\n otherTokenIndex: bigint\n direction: CreditWrapDirection\n /**\n * Amount of `otherToken` the credit sources (`exact-out`) or sells\n * (`exact-in`) — i.e. the non-target flow being cancelled.\n */\n swapAmount: bigint\n /**\n * Target-token side of the swap leg alone, priced by a swap-only simulation:\n * spent for `exact-out`, received for `exact-in`. NOT the same as\n * `netTargetChange`, which also includes the user's own operations.\n */\n estimatedCounterAmount: bigint\n /** `estimatedCounterAmount` padded by `slippageBps`. `exact-out` only. */\n maximumAmountIn: bigint\n slippageBps: bigint\n /** Signed net change of the target token across the ENTIRE wrapped tx. */\n netTargetChange: bigint\n /**\n * Signed net change of the other token across the entire wrapped tx — the\n * residual dust left by sizing the credit from a single simulation. Disclose\n * this to the user rather than claiming an exact zero.\n */\n residualOtherChange: bigint\n /** The temporary width=0 credit leg used to move the flow. */\n creditTokenId: bigint\n dispatch: DispatchIntent\n tokenFlow: TokenFlow\n _meta: BlockMeta\n}\n\nexport type OneTokenFlowUnavailableReason =\n | 'already-single-token'\n | 'below-threshold'\n | 'base-simulation-failed'\n | 'invalid-slippage'\n | 'invalid-target-token'\n | 'invalid-tick-limits'\n | 'swap-unavailable'\n | 'wrap-unavailable'\n\nexport type OneTokenFlowResult =\n | { available: true; quote: OneTokenFlowQuote }\n | {\n available: false\n reason: OneTokenFlowUnavailableReason\n /** Human-readable description of the sub-step that failed, for diagnostics. */\n detail?: string\n error?: PanopticError\n }\n\nfunction deltaAt(tokenFlow: TokenFlow, index: bigint): bigint {\n return index === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n}\n\nfunction balanceBeforeAt(tokenFlow: TokenFlow, index: bigint): bigint {\n return index === 0n ? tokenFlow.balanceBefore0 : tokenFlow.balanceBefore1\n}\n\nfunction abs(value: bigint): bigint {\n return value < 0n ? -value : value\n}\n\nfunction padForSlippage(amount: bigint, slippageBps: bigint): bigint {\n return (amount * (BPS_DENOMINATOR + slippageBps) + BPS_DENOMINATOR - 1n) / BPS_DENOMINATOR\n}\n\n/**\n * Quote a dispatch wrapped so its net flow lands in `targetTokenIndex` only.\n *\n * Three simulations, all pinned to one block and with no convergence loop:\n *\n * 1. the user's dispatch as-is, to measure the non-target flow to cancel;\n * 2. the credit legs alone, to price the swap and check the source balance;\n * 3. the wrapped dispatch, whose token flow is what the user is shown and what\n * the residual dust is read from.\n */\nexport async function quoteOneTokenFlow(\n params: OneTokenFlowQuoteParams,\n): Promise<OneTokenFlowResult> {\n const { targetTokenIndex } = params\n const minSwapRatioBps = params.minSwapRatioBps ?? DEFAULT_MIN_SWAP_RATIO_BPS\n if (targetTokenIndex !== 0n && targetTokenIndex !== 1n) {\n return {\n available: false,\n reason: 'invalid-target-token',\n detail: `targetTokenIndex=${targetTokenIndex} is neither 0 nor 1`,\n }\n }\n if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR) {\n return {\n available: false,\n reason: 'invalid-slippage',\n detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR}]`,\n }\n }\n const tickLimitLow = params.tickLimitLow ?? MIN_TICK\n const tickLimitHigh = params.tickLimitHigh ?? MAX_TICK\n if (tickLimitLow >= tickLimitHigh) {\n return {\n available: false,\n reason: 'invalid-tick-limits',\n detail: `tickLimitLow=${tickLimitLow} >= tickLimitHigh=${tickLimitHigh}`,\n }\n }\n\n const otherTokenIndex = targetTokenIndex === 0n ? 1n : 0n\n const targetBlockNumber = params.blockNumber ?? (await params.client.getBlockNumber())\n const simulateArgs = {\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n blockNumber: targetBlockNumber,\n }\n\n // Read ahead of the simulation: the shortfall branch below has to know which\n // collateral a NotEnoughTokens revert refers to before it can size a credit.\n const pool = await getPool({\n client: params.client,\n poolAddress: params.poolAddress,\n chainId: params.chainId,\n blockNumber: targetBlockNumber,\n })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const targetToken = targetTokenIndex === 0n ? token0 : token1\n const otherToken = otherTokenIndex === 0n ? token0 : token1\n // NotEnoughTokens is raised by the CollateralTracker and carries ITS address,\n // not the underlying token's.\n const otherTracker =\n otherTokenIndex === 0n ? pool.collateralTracker0.address : pool.collateralTracker1.address\n\n // 1. The user's dispatch as-is. When it reverts because the account is short\n // the non-target token, the revert itself quantifies the flow to cancel —\n // so one-token-out subsumes the plain shortfall-recovery case.\n const baseSimulation = await simulateDispatch({ ...simulateArgs, ...params.dispatch })\n let swapAmount: bigint\n let direction: CreditWrapDirection\n // The target-token flow of the user's ops alone. Null when the base dispatch\n // reverted, which only happens on the exact-out path.\n let baseTargetDelta: bigint | null = null\n if (baseSimulation.success && baseSimulation.tokenFlow !== undefined) {\n baseTargetDelta = deltaAt(baseSimulation.tokenFlow, targetTokenIndex)\n const otherDelta = deltaAt(baseSimulation.tokenFlow, otherTokenIndex)\n if (otherDelta === 0n) {\n return {\n available: false,\n reason: 'already-single-token',\n detail: 'the dispatch does not move the non-target token',\n }\n }\n // delta < 0: the account PAYS the other token — source it (exact-out).\n // delta > 0: the account RECEIVES it — sell it into the target (exact-in).\n direction = otherDelta < 0n ? 'exact-out' : 'exact-in'\n swapAmount = abs(otherDelta)\n } else {\n const shortfall = baseSimulation.success ? null : getNotEnoughTokensError(baseSimulation.error)\n if (shortfall === null) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: baseSimulation.success\n ? 'base simulation returned no token flow'\n : `base simulation reverted: ${baseSimulation.error.message}`,\n error: baseSimulation.success ? undefined : baseSimulation.error,\n }\n }\n // Only a shortfall in the NON-target collateral can be sized as a credit in\n // otherTokenIndex. A shortfall in the target token (or in neither) means the\n // account cannot fund the position at all, and sourcing the other token\n // would quote a swap that does not address it.\n if (shortfall.tokenAddress.toLowerCase() !== otherTracker.toLowerCase()) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: `shortfall is in ${shortfall.tokenAddress}, not the non-target collateral ${otherTracker}`,\n error: baseSimulation.success ? undefined : baseSimulation.error,\n }\n }\n const pending = shortfall.assetsRequested - shortfall.assetBalance\n if (pending <= 0n) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: `requested=${shortfall.assetsRequested} <= balance=${shortfall.assetBalance}`,\n }\n }\n direction = 'exact-out'\n swapAmount = pending\n }\n\n // Dust gate. The non-target flow is only worth swapping if it is material\n // next to the flow being settled; below that the swap burns a pool fee and\n // slippage to move an amount the user cannot see. Skipped when the base\n // dispatch reverted (baseTargetDelta === null), because there the swap is\n // what makes the transaction possible rather than a convenience.\n //\n // Compared in the target token's terms so the two sides share a scale. Note\n // this is deliberately NOT a fraction of notional: Neutralize ITM drives the\n // net flow toward zero while notional stays large, which would suppress the\n // swap on nearly every neutralized position.\n if (baseTargetDelta !== null && minSwapRatioBps > 0n) {\n const swapInTargetTerms = convertToTokenIndex(\n swapAmount,\n otherTokenIndex,\n targetTokenIndex,\n pool.sqrtPriceX96,\n )\n if (swapInTargetTerms * BPS_DENOMINATOR < minSwapRatioBps * abs(baseTargetDelta)) {\n return {\n available: false,\n reason: 'below-threshold',\n detail:\n `non-target flow ${swapInTargetTerms} (in target token terms) is below ` +\n `${minSwapRatioBps}bps of the target flow ${abs(baseTargetDelta)}`,\n }\n }\n }\n\n // asset === tokenType === otherTokenIndex: the credit is denominated in the\n // token whose flow is being cancelled. Passing the counter-token as tokenType\n // is the LOAN convention and silently inverts the swap.\n const collisionIds = Array.from(\n new Set([\n ...params.existingPositionIds,\n ...params.dispatch.positionIdList,\n ...params.dispatch.finalPositionIdList,\n ]),\n )\n const credit = buildUniqueCredit(\n pool.poolId,\n otherTokenIndex,\n otherTokenIndex,\n pool.currentTick,\n pool.tickSpacing,\n collisionIds,\n swapAmount,\n )\n\n // exact-out must straddle the user's ops so the sourced token is available\n // while they run; exact-in can only follow them, since the token being sold\n // does not exist until they have run.\n const placement = direction === 'exact-out' ? 'straddle' : 'append'\n const creditWrapArgs = {\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n direction,\n placement,\n } as const\n\n // 2. For exact-out ONLY, the credit legs alone: prices the swap and proves the\n // account can cover it out of the target token before it is committed to.\n //\n // Deliberately skipped for exact-in. There, the token being sold does not\n // exist until the user's ops have run, so a swap-only simulation reverts\n // for an account holding none of it — refusing a wrap that would in fact\n // have worked. Its price is recovered from the wrapped run instead, and no\n // balance guard is needed since the ops themselves fund the sale.\n let estimatedCounterAmount = 0n\n let maximumAmountIn = 0n\n if (direction === 'exact-out') {\n const swapOnlyDispatch = buildCreditWrappedDispatch({\n ...creditWrapArgs,\n dispatch: {\n positionIdList: [],\n finalPositionIdList: [...params.existingPositionIds],\n positionSizes: [],\n tickAndSpreadLimits: [],\n usePremiaAsCollateral: false,\n builderCode: 0n,\n },\n })\n const swapSimulation = await simulateDispatch({ ...simulateArgs, ...swapOnlyDispatch })\n if (!swapSimulation.success || swapSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: swapSimulation.success\n ? 'swap-only simulation returned no token flow'\n : `swap-only simulation reverted: ${swapSimulation.error.message}`,\n error: swapSimulation.success ? undefined : swapSimulation.error,\n }\n }\n estimatedCounterAmount = abs(deltaAt(swapSimulation.tokenFlow, targetTokenIndex))\n maximumAmountIn = padForSlippage(estimatedCounterAmount, params.slippageBps)\n const sourceBalance = balanceBeforeAt(swapSimulation.tokenFlow, targetTokenIndex)\n if (sourceBalance < maximumAmountIn) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: `source balance ${sourceBalance} < maximumAmountIn ${maximumAmountIn} (estimated ${estimatedCounterAmount}, slippageBps ${params.slippageBps})`,\n error: new PanopticError('Insufficient collateral to fund the one-token-out swap'),\n }\n }\n }\n\n // 3. The wrapped dispatch. Single pass — the swap itself shifts fees and\n // commission slightly, so the non-target side lands near, not exactly at,\n // zero. That remainder is surfaced as `residualOtherChange`.\n const wrappedDispatch = buildCreditWrappedDispatch({\n ...creditWrapArgs,\n dispatch: params.dispatch,\n })\n const wrappedSimulation = await simulateDispatch({ ...simulateArgs, ...wrappedDispatch })\n if (!wrappedSimulation.success || wrappedSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'wrap-unavailable',\n detail: wrappedSimulation.success\n ? 'wrapped dispatch simulation returned no token flow'\n : `wrapped dispatch reverted: ${wrappedSimulation.error.message}`,\n error: wrappedSimulation.success ? undefined : wrappedSimulation.error,\n }\n }\n\n // exact-in never priced the swap on its own (see above): recover it as the\n // extra target-token the wrap produced over the plain dispatch.\n if (direction === 'exact-in' && baseTargetDelta !== null) {\n estimatedCounterAmount = abs(\n deltaAt(wrappedSimulation.tokenFlow, targetTokenIndex) - baseTargetDelta,\n )\n }\n\n return {\n available: true,\n quote: {\n targetToken,\n otherToken,\n targetTokenIndex,\n otherTokenIndex,\n direction,\n swapAmount,\n estimatedCounterAmount,\n maximumAmountIn,\n slippageBps: params.slippageBps,\n netTargetChange: deltaAt(wrappedSimulation.tokenFlow, targetTokenIndex),\n residualOtherChange: deltaAt(wrappedSimulation.tokenFlow, otherTokenIndex),\n creditTokenId: credit.tokenId,\n dispatch: wrappedDispatch,\n tokenFlow: wrappedSimulation.tokenFlow,\n _meta: wrappedSimulation._meta,\n },\n }\n}\n","/**\n * Uniswap v4 PoolManager event ABI (subset for event watching).\n * @module abis/poolManager\n */\n\nexport const poolManagerAbi = [\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'tickLower', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'tickUpper', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'liquidityDelta', internalType: 'int256', type: 'int256', indexed: false },\n { name: 'salt', internalType: 'bytes32', type: 'bytes32', indexed: false },\n ],\n name: 'ModifyLiquidity',\n },\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'amount0', internalType: 'int128', type: 'int128', indexed: false },\n { name: 'amount1', internalType: 'int128', type: 'int128', indexed: false },\n { name: 'sqrtPriceX96', internalType: 'uint160', type: 'uint160', indexed: false },\n { name: 'liquidity', internalType: 'uint128', type: 'uint128', indexed: false },\n { name: 'tick', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'fee', internalType: 'uint24', type: 'uint24', indexed: false },\n ],\n name: 'Swap',\n },\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'amount0', internalType: 'uint256', type: 'uint256', indexed: false },\n { name: 'amount1', internalType: 'uint256', type: 'uint256', indexed: false },\n ],\n name: 'Donate',\n },\n] as const\n","/**\n * Simple WebSocket event watching for the Panoptic v2 SDK.\n * @module v2/events/watchEvents\n */\n\nimport type { Address, Hash, Log, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { PanopticEvent, PanopticEventType } from '../types'\nimport { decodeLeftRightSigned, decodePositionBalance } from '../writes/utils'\n\n/**\n * A decoded contract event log that includes both base Log fields and typed args.\n * viem's getContractEvents/watchContractEvent return logs with `.args`,\n * but the generic `Log` type doesn't include it. We use `unknown` for args\n * and narrow to specific types in each parse function's switch cases.\n */\ntype DecodedLog = Log & { args: unknown }\n\n/**\n * Parameters for watching events.\n */\nexport interface WatchEventsParams {\n /** Public client (must have WebSocket transport for real-time watching) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors */\n onError?: (error: Error) => void\n}\n\n/**\n * Event name to ABI event mapping for PanopticPool.\n */\nconst POOL_EVENT_NAMES: Record<string, PanopticEventType> = {\n OptionMinted: 'OptionMinted',\n OptionBurnt: 'OptionBurnt',\n AccountLiquidated: 'AccountLiquidated',\n ForcedExercised: 'ForcedExercised',\n PremiumSettled: 'PremiumSettled',\n}\n\n/**\n * Event name to ABI event mapping for CollateralTracker.\n */\nconst COLLATERAL_EVENT_NAMES: Record<string, PanopticEventType> = {\n Deposit: 'Deposit',\n Withdraw: 'Withdraw',\n ProtocolLossRealized: 'ProtocolLossRealized',\n}\n\n/**\n * Event name to ABI event mapping for RiskEngine.\n */\nconst RISK_ENGINE_EVENT_NAMES: Record<string, PanopticEventType> = {\n BorrowRateUpdated: 'BorrowRateUpdated',\n}\n\n/**\n * Event name to ABI event mapping for SFPM.\n */\nconst SFPM_EVENT_NAMES: Record<string, PanopticEventType> = {\n LiquidityChunkUpdated: 'LiquidityChunkUpdated',\n}\n\n/**\n * Event name to ABI event mapping for v4 PoolManager.\n */\nconst POOL_MANAGER_EVENT_NAMES: Record<string, PanopticEventType> = {\n ModifyLiquidity: 'ModifyLiquidity',\n Swap: 'Swap',\n Donate: 'Donate',\n}\n\n/**\n * Parse a decoded log into a typed PanopticEvent.\n */\nfunction parsePoolLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n // Type narrowing based on event name\n switch (eventName) {\n case 'OptionMinted': {\n const args = log.args as { recipient: Address; tokenId: bigint; balanceData: bigint }\n const balanceData = decodePositionBalance(args.balanceData)\n return {\n type: 'OptionMinted',\n ...baseEvent,\n recipient: args.recipient,\n tokenId: args.tokenId,\n positionSize: balanceData.positionSize,\n poolUtilization0: balanceData.poolUtilization0,\n poolUtilization1: balanceData.poolUtilization1,\n tickAtMint: balanceData.tickAtMint,\n timestampAtMint: balanceData.timestampAtMint,\n blockAtMint: balanceData.blockAtMint,\n swapAtMint: balanceData.swapAtMint,\n }\n }\n\n case 'OptionBurnt': {\n const args = log.args as {\n recipient: Address\n positionSize: bigint\n tokenId: bigint\n premiaByLeg: readonly [bigint, bigint, bigint, bigint]\n }\n return {\n type: 'OptionBurnt',\n ...baseEvent,\n recipient: args.recipient,\n tokenId: args.tokenId,\n positionSize: args.positionSize,\n premiaByLeg: args.premiaByLeg,\n }\n }\n\n case 'AccountLiquidated': {\n const args = log.args as { liquidator: Address; liquidatee: Address; bonusAmounts: bigint }\n const bonus = decodeLeftRightSigned(args.bonusAmounts)\n return {\n type: 'AccountLiquidated',\n ...baseEvent,\n liquidator: args.liquidator,\n liquidatee: args.liquidatee,\n bonusAmount0: bonus.right,\n bonusAmount1: bonus.left,\n }\n }\n\n case 'ForcedExercised': {\n const args = log.args as {\n exercisor: Address\n user: Address\n tokenId: bigint\n exerciseFee: bigint\n }\n const fee = decodeLeftRightSigned(args.exerciseFee)\n return {\n type: 'ForcedExercised',\n ...baseEvent,\n exercisor: args.exercisor,\n user: args.user,\n tokenId: args.tokenId,\n exerciseFee0: fee.right,\n exerciseFee1: fee.left,\n }\n }\n\n case 'PremiumSettled': {\n const args = log.args as {\n user: Address\n tokenId: bigint\n legIndex: bigint\n settledAmounts: bigint\n }\n const settled = decodeLeftRightSigned(args.settledAmounts)\n return {\n type: 'PremiumSettled',\n ...baseEvent,\n user: args.user,\n tokenId: args.tokenId,\n legIndex: args.legIndex,\n settledAmount0: settled.right,\n settledAmount1: settled.left,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a CollateralTracker log into a typed PanopticEvent.\n */\nfunction parseCollateralLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'Deposit': {\n const args = log.args as { sender: Address; owner: Address; assets: bigint; shares: bigint }\n return {\n type: 'Deposit',\n ...baseEvent,\n sender: args.sender,\n owner: args.owner,\n assets: args.assets,\n shares: args.shares,\n }\n }\n\n case 'Withdraw': {\n const args = log.args as {\n sender: Address\n receiver: Address\n owner: Address\n assets: bigint\n shares: bigint\n }\n return {\n type: 'Withdraw',\n ...baseEvent,\n sender: args.sender,\n receiver: args.receiver,\n owner: args.owner,\n assets: args.assets,\n shares: args.shares,\n }\n }\n\n case 'ProtocolLossRealized': {\n const args = log.args as {\n liquidatee: Address\n liquidator: Address\n protocolLossAssets: bigint\n protocolLossShares: bigint\n }\n return {\n type: 'ProtocolLossRealized',\n ...baseEvent,\n liquidatee: args.liquidatee,\n liquidator: args.liquidator,\n protocolLossAssets: args.protocolLossAssets,\n protocolLossShares: args.protocolLossShares,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a RiskEngine log into a typed PanopticEvent.\n */\nfunction parseRiskEngineLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'BorrowRateUpdated': {\n const args = log.args as {\n collateralToken: Address\n avgBorrowRate: bigint\n rateAtTarget: bigint\n }\n return {\n type: 'BorrowRateUpdated',\n ...baseEvent,\n collateralToken: args.collateralToken,\n avgBorrowRate: args.avgBorrowRate,\n rateAtTarget: args.rateAtTarget,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse an SFPM log into a typed PanopticEvent.\n */\nfunction parseSfpmLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'LiquidityChunkUpdated': {\n const args = log.args as {\n poolId: Hash\n owner: Address\n tokenType: bigint\n tickLower: number\n tickUpper: number\n liquidityDelta: bigint\n }\n return {\n type: 'LiquidityChunkUpdated',\n ...baseEvent,\n poolId: args.poolId,\n owner: args.owner,\n tokenType: args.tokenType,\n tickLower: args.tickLower,\n tickUpper: args.tickUpper,\n liquidityDelta: args.liquidityDelta,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a v4 PoolManager log into a typed PanopticEvent.\n */\nfunction parsePoolManagerLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'ModifyLiquidity': {\n const args = log.args as {\n id: Hash\n sender: Address\n tickLower: number\n tickUpper: number\n liquidityDelta: bigint\n salt: Hash\n }\n return {\n type: 'ModifyLiquidity',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n tickLower: args.tickLower,\n tickUpper: args.tickUpper,\n liquidityDelta: args.liquidityDelta,\n salt: args.salt,\n }\n }\n\n case 'Swap': {\n const args = log.args as {\n id: Hash\n sender: Address\n amount0: bigint\n amount1: bigint\n sqrtPriceX96: bigint\n liquidity: bigint\n tick: number\n fee: number\n }\n return {\n type: 'Swap',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n amount0: args.amount0,\n amount1: args.amount1,\n sqrtPriceX96: args.sqrtPriceX96,\n liquidity: args.liquidity,\n tick: args.tick,\n fee: args.fee,\n }\n }\n\n case 'Donate': {\n const args = log.args as { id: Hash; sender: Address; amount0: bigint; amount1: bigint }\n return {\n type: 'Donate',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n amount0: args.amount0,\n amount1: args.amount1,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Watch for Panoptic events in real-time using WebSocket.\n *\n * This is a one-shot watcher - if the WebSocket disconnects, it stops.\n * For production bots that need automatic reconnection, use `createEventSubscription()`.\n *\n * @param params - Watch parameters\n * @returns Unwatch function to stop watching\n *\n * @example\n * ```typescript\n * const unwatch = watchEvents({\n * client,\n * poolAddress,\n * eventTypes: ['OptionMinted', 'OptionBurnt'],\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error(error),\n * })\n *\n * // Later: stop watching\n * unwatch()\n * ```\n */\nexport function watchEvents(params: WatchEventsParams): () => void {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n } = params\n\n const unwatchFns: (() => void)[] = []\n\n // Determine which pool events to watch\n const poolEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in POOL_EVENT_NAMES)\n : (Object.keys(POOL_EVENT_NAMES) as PanopticEventType[])\n\n // Watch PanopticPool events\n for (const eventType of poolEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n // Determine which collateral events to watch\n const collateralEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in COLLATERAL_EVENT_NAMES)\n : (Object.keys(COLLATERAL_EVENT_NAMES) as PanopticEventType[])\n\n // Watch CollateralTracker events (if addresses provided)\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch RiskEngine events (if address provided)\n if (riskEngineAddress) {\n const riskEngineEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in RISK_ENGINE_EVENT_NAMES)\n : (Object.keys(RISK_ENGINE_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of riskEngineEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch SFPM events (if address provided)\n if (sfpmAddress) {\n const sfpmEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in SFPM_EVENT_NAMES)\n : (Object.keys(SFPM_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of sfpmEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch PoolManager events (if address provided)\n if (poolManagerAddress) {\n const poolManagerEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in POOL_MANAGER_EVENT_NAMES)\n : (Object.keys(POOL_MANAGER_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of poolManagerEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Return combined unwatch function\n return () => {\n for (const unwatch of unwatchFns) {\n unwatch()\n }\n }\n}\n\nexport type { DecodedLog }\nexport { parseCollateralLog, parsePoolLog, parsePoolManagerLog, parseRiskEngineLog, parseSfpmLog }\n","/**\n * Resilient event subscription with auto-reconnect for the Panoptic v2 SDK.\n * @module v2/events/subscription\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { EventSubscription, PanopticEvent, PanopticEventType } from '../types'\nimport type { DecodedLog } from './watchEvents'\nimport {\n parseCollateralLog,\n parsePoolLog,\n parsePoolManagerLog,\n parseRiskEngineLog,\n parseSfpmLog,\n} from './watchEvents'\n\n/**\n * Reconnection strategy configuration.\n */\nexport interface ReconnectConfig {\n /** Maximum reconnection attempts (0n = infinite) */\n maxAttempts: bigint\n /** Initial delay before first retry (ms) */\n initialDelayMs: bigint\n /** Maximum delay between retries (ms) */\n maxDelayMs: bigint\n /** Backoff multiplier */\n backoffMultiplier: bigint\n}\n\n/**\n * Default reconnection configuration.\n */\nexport const DEFAULT_RECONNECT_CONFIG: ReconnectConfig = {\n maxAttempts: 10n,\n initialDelayMs: 1000n,\n maxDelayMs: 30000n,\n backoffMultiplier: 2n,\n}\n\n/**\n * Parameters for creating an event subscription.\n */\nexport interface CreateEventSubscriptionParams {\n /** Public client (must have WebSocket transport) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors (subscription will auto-reconnect) */\n onError?: (error: Error) => void\n /** Callback for reconnection attempts */\n onReconnect?: (attempt: bigint, nextDelayMs: bigint) => void\n /** Callback when connected */\n onConnected?: () => void\n /** Reconnection strategy configuration */\n reconnect?: Partial<ReconnectConfig>\n}\n\n/**\n * Event subscription handle with additional state.\n */\nexport interface EventSubscriptionHandle extends EventSubscription {\n /** Start watching */\n start: () => void\n /** Stop watching (cleans up, no more reconnects) */\n stop: () => void\n /** Number of reconnection attempts */\n reconnectAttempts: bigint\n /** Last processed block number */\n lastProcessedBlock: bigint\n}\n\n/**\n * Create a resilient event subscription with auto-reconnect and gap filling.\n *\n * Unlike `watchEvents()`, this subscription automatically reconnects on\n * disconnection and fills gaps by fetching missed events.\n *\n * @param params - Subscription parameters\n * @returns Event subscription handle\n *\n * @example\n * ```typescript\n * const subscription = createEventSubscription({\n * client,\n * poolAddress,\n * eventTypes: ['OptionMinted', 'OptionBurnt', 'AccountLiquidated'],\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error('Subscription error:', error),\n * onReconnect: (attempt, nextDelay) => {\n * console.log(`Reconnecting (attempt ${attempt}, next in ${nextDelay}ms)`)\n * },\n * onConnected: () => console.log('Subscription connected'),\n * })\n *\n * // Start watching\n * subscription.start()\n *\n * // Check state\n * console.log('Connected:', subscription.isConnected())\n * console.log('Reconnect attempts:', subscription.reconnectAttempts)\n * console.log('Last processed block:', subscription.lastProcessedBlock)\n *\n * // Stop (cleans up, no more reconnects)\n * subscription.stop()\n * ```\n */\nexport function createEventSubscription(\n params: CreateEventSubscriptionParams,\n): EventSubscriptionHandle {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n onReconnect,\n onConnected,\n reconnect: reconnectConfig,\n } = params\n\n const config: ReconnectConfig = {\n ...DEFAULT_RECONNECT_CONFIG,\n ...reconnectConfig,\n }\n\n // State\n let isRunning = false\n let connected = false\n let reconnectAttempts = 0n\n let lastProcessedBlock = 0n\n let lastProcessedLogIndex = -1n\n let currentDelay = config.initialDelayMs\n let unwatchFns: (() => void)[] = []\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null\n\n const compareEvents = (a: PanopticEvent, b: PanopticEvent): number => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n if (a.logIndex !== b.logIndex) {\n return a.logIndex < b.logIndex ? -1 : 1\n }\n return 0\n }\n\n const isAfterCursor = (event: PanopticEvent): boolean => {\n if (event.blockNumber > lastProcessedBlock) {\n return true\n }\n if (event.blockNumber < lastProcessedBlock) {\n return false\n }\n return event.logIndex > lastProcessedLogIndex\n }\n\n const advanceCursor = (event: PanopticEvent): void => {\n lastProcessedBlock = event.blockNumber\n lastProcessedLogIndex = event.logIndex\n }\n\n // Pool event types\n const poolEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) =>\n [\n 'OptionMinted',\n 'OptionBurnt',\n 'AccountLiquidated',\n 'ForcedExercised',\n 'PremiumSettled',\n ].includes(t),\n )\n : ['OptionMinted', 'OptionBurnt', 'AccountLiquidated', 'ForcedExercised', 'PremiumSettled']\n\n // Collateral event types\n const collateralEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['Deposit', 'Withdraw', 'ProtocolLossRealized'].includes(t))\n : ['Deposit', 'Withdraw', 'ProtocolLossRealized']\n\n // RiskEngine event types\n const riskEngineEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['BorrowRateUpdated'].includes(t))\n : ['BorrowRateUpdated']\n\n // SFPM event types\n const sfpmEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['LiquidityChunkUpdated'].includes(t))\n : ['LiquidityChunkUpdated']\n\n // PoolManager event types\n const poolManagerEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['ModifyLiquidity', 'Swap', 'Donate'].includes(t))\n : ['ModifyLiquidity', 'Swap', 'Donate']\n\n /**\n * Fetch missed events between lastProcessedBlock and currentBlock.\n */\n async function fillGap(fromBlock: bigint, toBlock: bigint): Promise<void> {\n if (fromBlock >= toBlock) return\n\n const allEvents: PanopticEvent[] = []\n\n // Fetch pool events\n for (const eventType of poolEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`))\n }\n }\n\n // Fetch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Sort by block number and log index, then drop anything at/before cursor.\n const newEvents = allEvents.sort(compareEvents).filter(isAfterCursor)\n\n if (newEvents.length > 0) {\n onLogs(newEvents)\n advanceCursor(newEvents[newEvents.length - 1])\n }\n }\n\n /**\n * Start watching events.\n */\n async function setupWatchers(): Promise<void> {\n // Clean up any existing watchers\n cleanup()\n\n try {\n // Get current block for gap detection\n const currentBlock = await client.getBlockNumber()\n\n // Fill gap if we have a previous position\n if (lastProcessedBlock > 0n && lastProcessedBlock < currentBlock) {\n await fillGap(lastProcessedBlock, currentBlock)\n }\n\n // Set baseline for this subscription start (from \"head\"), unless fillGap\n // already advanced us into this block with a concrete log index.\n if (currentBlock > lastProcessedBlock) {\n lastProcessedBlock = currentBlock\n lastProcessedLogIndex = -1n\n }\n\n const createOnLogsHandler = (\n parseLog: (log: DecodedLog) => PanopticEvent | null,\n ): ((logs: readonly unknown[]) => void) => {\n return (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseLog(log as DecodedLog)\n if (parsed && isAfterCursor(parsed)) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n events.sort(compareEvents)\n onLogs(events)\n advanceCursor(events[events.length - 1])\n }\n }\n }\n\n const createPoolOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parsePoolLog(log, eventType))\n const createCollateralOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseCollateralLog(log, eventType))\n const createRiskEngineOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseRiskEngineLog(log, eventType))\n const createSfpmOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseSfpmLog(log, eventType))\n const createPoolManagerOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parsePoolManagerLog(log, eventType))\n\n // Watch pool events\n for (const eventType of poolEventTypes) {\n const unwatch = client.watchContractEvent({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n onLogs: createPoolOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n\n // Watch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(\n Boolean,\n ) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n const unwatch = client.watchContractEvent({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n onLogs: createCollateralOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n const unwatch = client.watchContractEvent({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n onLogs: createRiskEngineOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n const unwatch = client.watchContractEvent({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n onLogs: createSfpmOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n const unwatch = client.watchContractEvent({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n onLogs: createPoolManagerOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Mark as connected\n connected = true\n reconnectAttempts = 0n\n currentDelay = config.initialDelayMs\n onConnected?.()\n } catch (error) {\n handleError(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n /**\n * Clean up watchers.\n */\n function cleanup(): void {\n for (const unwatch of unwatchFns) {\n try {\n unwatch()\n } catch {\n // Ignore cleanup errors\n }\n }\n unwatchFns = []\n connected = false\n }\n\n /**\n * Handle errors and schedule reconnection.\n */\n function handleError(error: Error): void {\n connected = false\n onError?.(error)\n\n if (!isRunning) return\n\n // Reconnect already scheduled; avoid duplicate timers.\n if (reconnectTimeout) return\n\n // Check if we've exceeded max attempts\n if (config.maxAttempts > 0n && reconnectAttempts >= config.maxAttempts) {\n onError?.(new Error(`Max reconnection attempts (${config.maxAttempts}) exceeded`))\n return\n }\n\n // Schedule reconnection\n reconnectAttempts++\n onReconnect?.(reconnectAttempts, currentDelay)\n\n reconnectTimeout = setTimeout(() => {\n reconnectTimeout = null\n if (isRunning) {\n setupWatchers()\n }\n }, Number(currentDelay))\n\n // Increase delay for next attempt (exponential backoff)\n currentDelay = currentDelay * config.backoffMultiplier\n if (currentDelay > config.maxDelayMs) {\n currentDelay = config.maxDelayMs\n }\n }\n\n /**\n * Start the subscription.\n */\n function start(): void {\n if (isRunning) return\n isRunning = true\n setupWatchers()\n }\n\n /**\n * Stop the subscription.\n */\n function stop(): void {\n isRunning = false\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout)\n }\n reconnectTimeout = null\n cleanup()\n }\n\n return {\n start,\n stop,\n unsubscribe: stop,\n isConnected: () => connected,\n get reconnectAttempts() {\n return reconnectAttempts\n },\n get lastProcessedBlock() {\n return lastProcessedBlock\n },\n }\n}\n","/**\n * HTTP polling-based event fetching for the Panoptic v2 SDK.\n * @module v2/events/poller\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { PanopticEvent, PanopticEventType } from '../types'\nimport type { DecodedLog } from './watchEvents'\nimport {\n parseCollateralLog,\n parsePoolLog,\n parsePoolManagerLog,\n parseRiskEngineLog,\n parseSfpmLog,\n} from './watchEvents'\n\n/**\n * Event poller handle.\n */\nexport interface EventPoller {\n /** Start polling */\n start: () => void\n /** Stop polling */\n stop: () => void\n /** Check if polling is active */\n isPolling: () => boolean\n /** Get last polled block */\n lastPolledBlock: bigint\n}\n\n/**\n * Parameters for creating an event poller.\n */\nexport interface CreateEventPollerParams {\n /** Public client (works with HTTP transport) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors */\n onError?: (error: Error) => void\n /** Polling interval in milliseconds (default: 12000 = 1 block on mainnet) */\n intervalMs?: bigint\n /** Maximum blocks to query per poll (default: 1000) */\n maxBlockRange?: bigint\n /** Starting block number (default: current block) */\n fromBlock?: bigint\n}\n\n/**\n * Default polling interval (12 seconds = ~1 mainnet block).\n */\nconst DEFAULT_INTERVAL_MS = 12000n\n\n/**\n * Default maximum block range per poll.\n */\nconst DEFAULT_MAX_BLOCK_RANGE = 1000n\n\n/**\n * Create an HTTP polling-based event fetcher.\n *\n * Use this for environments where WebSocket connections are unreliable or unavailable.\n * It polls `eth_getLogs` at regular intervals to fetch new events.\n *\n * @param params - Poller parameters\n * @returns Event poller handle\n *\n * @example\n * ```typescript\n * const poller = createEventPoller({\n * client,\n * poolAddress,\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error('Polling error:', error),\n * intervalMs: 12000n, // 12 seconds\n * maxBlockRange: 1000n,\n * })\n *\n * // Start polling\n * poller.start()\n *\n * // Check state\n * console.log('Polling:', poller.isPolling())\n * console.log('Last polled block:', poller.lastPolledBlock)\n *\n * // Stop polling\n * poller.stop()\n * ```\n */\nexport function createEventPoller(params: CreateEventPollerParams): EventPoller {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n intervalMs = DEFAULT_INTERVAL_MS,\n maxBlockRange = DEFAULT_MAX_BLOCK_RANGE,\n fromBlock,\n } = params\n\n // State\n let isRunning = false\n let lastPolledBlock = fromBlock ?? 0n\n let pollTimeout: ReturnType<typeof setTimeout> | null = null\n\n // Pool event types\n const poolEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) =>\n [\n 'OptionMinted',\n 'OptionBurnt',\n 'AccountLiquidated',\n 'ForcedExercised',\n 'PremiumSettled',\n ].includes(t),\n )\n : ['OptionMinted', 'OptionBurnt', 'AccountLiquidated', 'ForcedExercised', 'PremiumSettled']\n\n // Collateral event types\n const collateralEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['Deposit', 'Withdraw', 'ProtocolLossRealized'].includes(t))\n : ['Deposit', 'Withdraw', 'ProtocolLossRealized']\n\n // RiskEngine event types\n const riskEngineEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['BorrowRateUpdated'].includes(t))\n : ['BorrowRateUpdated']\n\n // SFPM event types\n const sfpmEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['LiquidityChunkUpdated'].includes(t))\n : ['LiquidityChunkUpdated']\n\n // PoolManager event types\n const poolManagerEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['ModifyLiquidity', 'Swap', 'Donate'].includes(t))\n : ['ModifyLiquidity', 'Swap', 'Donate']\n\n /**\n * Fetch events for a block range.\n */\n async function fetchEvents(from: bigint, to: bigint): Promise<PanopticEvent[]> {\n const allEvents: PanopticEvent[] = []\n\n // Fetch pool events\n for (const eventType of poolEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`))\n }\n }\n\n // Fetch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Sort by block number and log index\n allEvents.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n return a.logIndex < b.logIndex ? -1 : 1\n })\n\n return allEvents\n }\n\n /**\n * Perform a single poll iteration.\n */\n async function poll(): Promise<void> {\n if (!isRunning) return\n\n try {\n // Get current block\n const currentBlock = await client.getBlockNumber()\n\n // Initialize lastPolledBlock if not set\n if (lastPolledBlock === 0n) {\n lastPolledBlock = currentBlock\n schedulePoll()\n return\n }\n\n // Check if there are new blocks\n if (currentBlock <= lastPolledBlock) {\n schedulePoll()\n return\n }\n\n // Calculate range to query (respect maxBlockRange)\n let toBlock = currentBlock\n const range = toBlock - lastPolledBlock\n if (range > maxBlockRange) {\n toBlock = lastPolledBlock + maxBlockRange\n }\n\n // Fetch events\n const events = await fetchEvents(lastPolledBlock + 1n, toBlock)\n\n // Update last polled block\n lastPolledBlock = toBlock\n\n // Deliver events\n if (events.length > 0) {\n onLogs(events)\n }\n\n // If we didn't catch up to current block, poll again immediately\n if (toBlock < currentBlock && isRunning) {\n // Use setImmediate-like behavior with 0ms timeout\n pollTimeout = setTimeout(poll, 0)\n } else {\n schedulePoll()\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n schedulePoll()\n }\n }\n\n /**\n * Schedule next poll.\n */\n function schedulePoll(): void {\n if (!isRunning) return\n pollTimeout = setTimeout(poll, Number(intervalMs))\n }\n\n /**\n * Start polling.\n */\n function start(): void {\n if (isRunning) return\n isRunning = true\n poll()\n }\n\n /**\n * Stop polling.\n */\n function stop(): void {\n isRunning = false\n if (pollTimeout) {\n clearTimeout(pollTimeout)\n pollTimeout = null\n }\n }\n\n return {\n start,\n stop,\n isPolling: () => isRunning,\n get lastPolledBlock() {\n return lastPolledBlock\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"v2-CC5WDfS9.js","names":["params: ResolveBlockNumbersParams","blockNumber: bigint","targetTimestamp: number","low: bigint","high: bigint","params: EstimateBlockNumbersParams","params: MulticallReadParams<TContracts>","results: MulticallResult<unknown>[]","tokenURI: string","startBlock: bigint","endBlock: bigint","points: number","plan: SfpmSwapPlan","sfpmV3Abi","params: FetchSfpmV3PoolIdParams","sfpmV3Abi","params: EnsureSfpmV3PoolInitializedParams","WIDE_LIMITS: [number, number]","slippageBps: bigint","params: SfpmSwapPlanParams","invertedLimits: [number, number]","swapOn: 'mint' | 'burn'","packed: bigint","half: bigint","err: unknown","params: QuoteSfpmSwapParams","sfpmV3Abi","params: GetUniswapV3PoolFromIdParams","params: GetUniswapV4PoolKeyFromIdParams","params: GetEnforcedTickLimitsParams","params: GetChunkLiquiditiesParams","params: GetFactoryTokenURIParams","params: GetFactoryOwnerOfParams","params: GetFactoryConstructMetadataParams","params: GetPanopticPoolAddressParams","params: MinePoolAddressParams","result: readonly [bigint, bigint]","params: SimulateDeployNewPoolParams","result","params: GetPanopticPoolFromPoolIdParams","params: ResolvePanopticPoolFromPoolIdParams","err: unknown","value: bigint","byteLength: number","addr: Address","hex: Hex","factory: Address","salt: bigint","addrInt: bigint","deployerAddress: Address","v3Pool: Address","riskEngine: Address","poolKey: PoolKey","params: MinePoolAddressLocalParams","params: GetAccountPremiaParams","_meta","params: GetPositionsWithPremiaParams","positions: PositionWithPremia[]","legs: TokenIdLeg[]","params: EstimateCollateralRequiredParams","effectiveTick: bigint","params: GetMaxPositionSizeParams","positionIds: bigint[]","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n low: bigint\n high: bigint\n precisionDivisor: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}","positionSize: bigint","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n positionSize: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}","tickLimits: readonly [number, number, number]","tickLimits","params: GetRequiredCreditForITMParams","tickTriplet: readonly [number, number, number]","params: GetItmAmountsParams","Q192","value: bigint","tokenIndex: 0n | 1n","signedAmount: bigint","signedTick: bigint","poolId: bigint","baseTokenId: bigint","neutralLegs: NeutralLeg[]","prepend: boolean","params: CreateFlowNeutralTokenIdParams","index: 0n | 1n","amount: bigint","abs","indices: (0n | 1n)[]","residual: RequiredCreditForITM","params: GetMaxWithdrawableParams","params: GetMaxRedeemParams","params: {\n client: PublicClient\n collateralTrackerAddress: Address\n account: Address\n assets: bigint\n positionIdList: bigint[]\n usePremiaAsCollateral: boolean\n}","client: PublicClient","poolAddress: Address","tokenIndex: 0 | 1","providedAddress?: Address","params: ERC4626PreviewParams","params: GetGuardianUnlockStateParams","params: GetSafeModeParams","params: GetPortfolioValueParams","params: CheckCollateralAcrossTicksParams","MIN_TICK","MAX_TICK","dataPoints: CollateralDataPoint[]","params: OptimizeTokenIdRiskPartnersParams","effectiveTick: bigint","params: GetPoolLiquiditiesParams","TEN","formatRatio","numerator: bigint","denominator: bigint","precision: bigint","bps: bigint","util: bigint","percent: string","config: PoolFormatterConfig","tick: bigint","precision: bigint","price: string","amount: bigint","amount: string","TEN","formatRatio","numerator: bigint","denominator: bigint","precision: bigint","chainId: bigint","address: Address","tokenListId: string","token0Symbol: string","token1Symbol: string","feeBps: bigint","numerator: bigint","denominator: bigint","precision: bigint","address: string","timestamp: bigint","locale?: string","options?: Intl.DateTimeFormatOptions","ms: bigint","minutes","seconds: bigint","blockNumber: bigint","gas: bigint","hash: string","value: bigint","tokenId: bigint","poolId: bigint","formatted: string","wei: bigint","params: GetAccountGreeksParams","targetBlock","_meta","positions: AccountGreeksResult['positions']","params: CalculateAccountGreeksPureParams","totalValue: bigint[]","totalDelta: bigint[]","positionResults: AccountGreeksCurveResult['positions']","posValues: bigint[]","posDeltas: bigint[]","posGammas: bigint[]","MIN_TICK","MAX_TICK","Q128","a: bigint","b: bigint","convert0to1","amount: bigint","sqrtPriceX96: bigint","convert1to0","params: GetMarginBufferParams","collateralToken0: Address","collateralToken1: Address","calls: MulticallBlockCall[]","usageBps0: bigint | null","usageBps1: bigint | null","crossMarginUsageBps: bigint | null","mintableMarginBinding: bigint | null","required: bigint | undefined","balance: bigint | undefined","denominatedInToken: 0 | 1","lowerLiquidationTick: bigint | null","upperLiquidationTick: bigint | null","liquidationDistance: bigint | null","params: GetDeltaHedgeParamsInput","currentTick: bigint","tickSpacing: bigint","poolMeta: BlockMeta","primaryAsset: bigint","currentDelta: bigint","hedgeLeg: LegConfig","simulatedTickAfter: bigint | undefined","collateralAddresses: [Address, Address]","blockNumber: bigint","client: Client","e: unknown","client: Client","collateralTrackerAddresses: Address[]","chainId: number","blockNumber?: bigint","Q128","convert0to1","amount: bigint","sqrtPriceX96: bigint","convert1to0","params: GetAccountBuyingPowerParams","collateralToken0: Address","collateralToken1: Address","calls: MulticallBlockCall[]","params: BuildCreditWrappedDispatchParams","swapping: TickAndSpreadLimits","notSwapping: TickAndSpreadLimits","wrapped: DispatchIntent","params: SimulateDispatchParams","tokenFlow: TokenFlow","data: Hex | undefined","data","data: DispatchSimulation","BPS_DENOMINATOR","params: BuildTokenShortfallRecoveryDispatchParams","error: unknown","candidate: NotEnoughTokensError | null","args: Partial<\n Pick<NotEnoughTokensError, 'tokenAddress' | 'assetsRequested' | 'assetBalance'>\n >","estimatedAmountIn: bigint","slippageBps: bigint","tokenFlow: TokenFlow","tokenInIndex: 0n | 1n","tokenIndex: 0n | 1n","tokenOutIndex: 0n | 1n","params: TokenShortfallRecoveryQuoteParams","params: GetOpenPositionPreviewParams","tokenShortfall: NotEnoughTokensError | null","params: GetNativeTokenPriceParams","params: GetAccountHistoryParams","trades: AccountTrade[]","params: GetUniswapFeeHistoryParams","_meta","initialFees0: bigint | null","initialFees1: bigint | null","snapshots: UniswapFeeSnapshot[]","client: PublicClient","blockNumbers: (bigint | undefined)[]","legs: StreamiaLeg[]","poolConfig: PoolVersionConfig","blockData: UniswapBlockData","blockNumber: bigint | undefined","uniqueTicks: number[]","poolAddress: Address","stateViewAddress: Address","poolId: `0x${string}`","params: GetStreamiaHistoryParams","_meta","initialUniswapFees0: bigint | null","initialUniswapFees1: bigint | null","snapshots: StreamiaSnapshot[]","params: GetUniswapV3PoolInfoParams","startTick: number","tickSpacing: number","nTicks: bigint","params: GetUniswapV3PoolLiquiditiesParams","poolKey: UniswapV4PoolKey","_params: ResolveUniswapV4PoolKeyParams","params: GetUniswapV4PoolBasicStateParams","client: Pick<PublicClient, 'multicall'>","address: Address","blockNumber?: bigint","params: GetUniswapV4PoolInfoParams","params: GetUniswapV4PoolLiquiditiesParams","Q128","error: unknown","params: GetUniswapV3LpPositionStateParams","feeGrowthInsideCurrentX128: bigint","feeGrowthInsideLastX128: bigint","liquidity: bigint","params: GetUniswapV4LpPositionStateParams","params: GetPriceHistoryParams","_meta","snapshots: PriceSnapshot[]","client: PublicClient","blockNumber: bigint | undefined","poolConfig: PoolVersionConfig","tokenId: bigint","callName: string","cause?: unknown","params: GetPositionEnrichmentDataParams","client: PublicClient","queryAddress: Address","positions: PositionInput[]","currentTick: number","blockNumber: bigint | undefined","_meta: BlockMeta","panopticQueryAbi","entries: [string, PositionEnrichmentResult][]","params: GetSyncStatusParams","params: SaveClosedPositionParams","history: ClosedPosition[]","params: GetTradeHistoryParams","params: GetRealizedPnLParams","params: Omit<\n GetTradeHistoryParams,\n 'limit' | 'offset' | 'closureReason' | 'fromBlock' | 'toBlock'\n >","chunk: LiquidityChunkKey","key: string","params: AddTrackedChunksParams","trackedKeys: Set<string>","params: RemoveTrackedChunksParams","params: GetTrackedChunksParams","params: GetChunkSpreadsParams","netLiquidity: bigint","removedLiquidity: bigint","vegoid: bigint","params: ScanChunksParams","chunks: ScannedChunk[]","params: GetPositionChunkDataParams","_meta","positions: PositionChunkData[]","legs: LegChunkData[]","params: AddPendingPositionParams","pending: PendingPosition[]","params: GetPendingPositionsParams","params: ConfirmPendingPositionParams","params: FailPendingPositionParams","currentBlock: bigint","maxAgeBlocks: bigint","params: EventReconstructionParams","mintEvents: MintEvent[]","burnEvents: BurnEvent[]","openPositions: bigint[]","closedPositions: bigint[]","client: PublicClient","poolAddress: Address","foundBlock: bigint | null","params: SimulateBatchDispatchParams","params: SimulateClosePositionParams","tickLimits: readonly [number, number, number]","tickLimits","data: ClosePositionSimulation","params: SimulateForceExerciseParams","emptyTokenFlow: TokenFlow","_meta","data: ForceExerciseSimulation","tokenFlow: TokenFlow","params: SimulateLiquidateParams","emptyTokenFlow: TokenFlow","_meta","data: LiquidateSimulation","tokenFlow: TokenFlow","params: SimulateSettleParams","tokenFlow: TokenFlow","forfeitAmounts: [bigint, bigint] | undefined","data: SettleSimulation","params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n positionIdList: bigint[]\n tokenId: bigint\n dispatchCallData: Hex\n blockNumber: bigint\n}","data: Hex","params: SimulateDepositParams","data: DepositSimulation","params: SimulateWithdrawParams","data: WithdrawSimulation","poolKey: PoolKey","v3PoolAddress: Address","params: SimulateSFPMParams","creditTokenId: bigint","existingPositionIds: bigint[]","amount: bigint","mintTickLimits: readonly [number, number, number]","burnTickLimits: readonly [number, number, number]","builderCode: bigint","tokenFlow: TokenFlow","tokenOutIndex: bigint","params: SimulateSwapExactOutParams","params: SimulateSwapExactInParams","sqrtPriceX96: bigint","amount: bigint","fromTokenIndex: bigint","toTokenIndex: bigint","tokenFlow: TokenFlow","index: bigint","value: bigint","amount: bigint","slippageBps: bigint","params: OneTokenFlowQuoteParams","swapAmount: bigint","direction: CreditWrapDirection","baseTargetDelta: bigint | null","maximumAmountIn","POOL_EVENT_NAMES: Record<string, PanopticEventType>","COLLATERAL_EVENT_NAMES: Record<string, PanopticEventType>","RISK_ENGINE_EVENT_NAMES: Record<string, PanopticEventType>","SFPM_EVENT_NAMES: Record<string, PanopticEventType>","POOL_MANAGER_EVENT_NAMES: Record<string, PanopticEventType>","log: DecodedLog","eventName: string","params: WatchEventsParams","unwatchFns: (() => void)[]","events: PanopticEvent[]","DEFAULT_RECONNECT_CONFIG: ReconnectConfig","params: CreateEventSubscriptionParams","config: ReconnectConfig","unwatchFns: (() => void)[]","reconnectTimeout: ReturnType<typeof setTimeout> | null","a: PanopticEvent","b: PanopticEvent","event: PanopticEvent","poolEventTypes: PanopticEventType[]","collateralEventTypes: PanopticEventType[]","riskEngineEventTypes: PanopticEventType[]","sfpmEventTypes: PanopticEventType[]","poolManagerEventTypes: PanopticEventType[]","fromBlock: bigint","toBlock: bigint","allEvents: PanopticEvent[]","parseLog: (log: DecodedLog) => PanopticEvent | null","events: PanopticEvent[]","eventType: PanopticEventType","error: Error","params: CreateEventPollerParams","pollTimeout: ReturnType<typeof setTimeout> | null","poolEventTypes: PanopticEventType[]","collateralEventTypes: PanopticEventType[]","riskEngineEventTypes: PanopticEventType[]","sfpmEventTypes: PanopticEventType[]","poolManagerEventTypes: PanopticEventType[]","from: bigint","to: bigint","allEvents: PanopticEvent[]"],"sources":["../src/panoptic/v2/clients/blocksByTimestamp.ts","../src/panoptic/v2/clients/multicall.ts","../src/panoptic/v2/utils/factory.ts","../src/panoptic/v2/utils/interpolateBlocks.ts","../src/panoptic/v2/sfpmSwap/calldata.ts","../src/panoptic/v2/sfpmSwap/init.ts","../src/panoptic/v2/sfpmSwap/plan.ts","../src/panoptic/v2/sfpmSwap/quote.ts","../src/panoptic/v2/reads/sfpm.ts","../src/panoptic/v2/reads/factory.ts","../src/panoptic/v2/reads/minePoolAddressLocal.ts","../src/panoptic/v2/reads/premia.ts","../src/panoptic/v2/reads/collateralEstimate.ts","../src/panoptic/v2/reads/erc4626.ts","../src/panoptic/v2/reads/guardian.ts","../src/panoptic/v2/reads/safeMode.ts","../src/panoptic/v2/reads/queryUtils.ts","../src/panoptic/v2/reads/liquidity.ts","../src/panoptic/v2/formatters/percentage.ts","../src/panoptic/v2/formatters/poolFormatters.ts","../src/panoptic/v2/formatters/tokenList.ts","../src/panoptic/v2/formatters/display.ts","../src/panoptic/v2/reads/accountGreeks.ts","../src/panoptic/v2/reads/margin.ts","../src/panoptic/v2/reads/hedge.ts","../src/panoptic/v2/reads/collateralSharePrice.ts","../src/panoptic/v2/reads/collateralTotalAssets.ts","../src/panoptic/v2/reads/buyingPower.ts","../src/panoptic/v2/simulations/creditWrap.ts","../src/panoptic/v2/simulations/simulateDispatch.ts","../src/panoptic/v2/simulations/tokenShortfallRecovery.ts","../src/panoptic/v2/reads/openPositionPreview.ts","../src/panoptic/v2/reads/nativeTokenPrice.ts","../src/panoptic/v2/reads/history.ts","../src/panoptic/v2/reads/uniswapFeeHistory.ts","../src/panoptic/v2/reads/streamiaHistory.ts","../src/panoptic/v2/reads/uniswapPool.ts","../src/panoptic/v2/reads/uniswapLpPosition.ts","../src/panoptic/v2/reads/priceHistory.ts","../src/panoptic/v2/reads/enrichment.ts","../src/panoptic/v2/sync/getSyncStatus.ts","../src/panoptic/v2/sync/tradeHistory.ts","../src/panoptic/v2/sync/chunkTracking.ts","../src/panoptic/v2/sync/pendingPositions.ts","../src/panoptic/v2/sync/eventReconstruction.ts","../src/panoptic/v2/simulations/simulateBatchDispatch.ts","../src/panoptic/v2/simulations/simulateClosePosition.ts","../src/panoptic/v2/simulations/simulateForceExercise.ts","../src/panoptic/v2/simulations/simulateLiquidate.ts","../src/panoptic/v2/simulations/simulateSettle.ts","../src/panoptic/v2/simulations/simulateVault.ts","../src/panoptic/v2/simulations/sfpm.ts","../src/panoptic/v2/simulations/simulateSwap.ts","../src/panoptic/v2/utils/priceConvert.ts","../src/panoptic/v2/simulations/oneTokenFlow.ts","../src/panoptic/v2/abis/poolManager.ts","../src/panoptic/v2/events/watchEvents.ts","../src/panoptic/v2/events/subscription.ts","../src/panoptic/v2/events/poller.ts"],"sourcesContent":["/**\n * Timestamp-to-block resolution via RPC binary search.\n * No subgraph dependency — uses only eth_getBlockByNumber.\n * @module v2/clients/blocksByTimestamp\n */\n\nimport type { PublicClient } from 'viem'\n\n/**\n * Parameters for resolveBlockNumbers.\n */\nexport interface ResolveBlockNumbersParams {\n /** viem PublicClient */\n client: PublicClient\n /** Array of Unix timestamps (seconds) to resolve to block numbers */\n timestamps: number[]\n}\n\n/**\n * Resolve an array of Unix timestamps to the closest block numbers via RPC binary search.\n *\n * All binary searches run in parallel, sharing an in-flight-deduped block cache\n * so concurrent searches for nearby timestamps avoid redundant RPC calls.\n *\n * @param params - The parameters\n * @returns Array of block numbers in the same order as the input timestamps\n *\n * @example\n * ```typescript\n * const blocks = await resolveBlockNumbers({\n * client,\n * timestamps: [1700000000, 1700003600, 1700007200],\n * })\n * // blocks: [18500000n, 18500300n, 18500600n]\n * ```\n */\nexport async function resolveBlockNumbers(params: ResolveBlockNumbersParams): Promise<bigint[]> {\n const { client, timestamps } = params\n\n if (timestamps.length === 0) return []\n\n const latestBlock = await client.getBlock({ blockTag: 'latest', includeTransactions: false })\n const latestNumber = latestBlock.number\n const latestTimestamp = Number(latestBlock.timestamp)\n\n // Cache + in-flight dedup: avoids redundant RPC calls across parallel searches\n const cache = new Map<bigint, number>()\n cache.set(latestNumber, latestTimestamp)\n cache.set(0n, 0) // genesis is always timestamp 0 (close enough)\n\n const inflight = new Map<bigint, Promise<number>>()\n\n function getTimestamp(blockNumber: bigint): Promise<number> {\n const cached = cache.get(blockNumber)\n if (cached !== undefined) return Promise.resolve(cached)\n\n const existing = inflight.get(blockNumber)\n if (existing) return existing\n\n const promise = client.getBlock({ blockNumber, includeTransactions: false }).then((block) => {\n const ts = Number(block.timestamp)\n cache.set(blockNumber, ts)\n inflight.delete(blockNumber)\n return ts\n })\n inflight.set(blockNumber, promise)\n return promise\n }\n\n /**\n * Binary search for the last block whose timestamp <= targetTimestamp.\n */\n async function searchBlock(targetTimestamp: number, low: bigint, high: bigint): Promise<bigint> {\n // Clamp: if target is beyond latest, return latest\n if (targetTimestamp >= latestTimestamp) return latestNumber\n\n while (high - low > 1n) {\n const mid = (low + high) / 2n\n const midTs = await getTimestamp(mid)\n\n if (midTs <= targetTimestamp) {\n low = mid\n } else {\n high = mid\n }\n }\n\n return low\n }\n\n // Run all binary searches in parallel — shared cache deduplicates common midpoints\n const results = await Promise.all(timestamps.map((ts) => searchBlock(ts, 0n, latestNumber)))\n\n return results\n}\n\n/**\n * Parameters for estimateBlockNumbers.\n */\nexport interface EstimateBlockNumbersParams {\n /** viem PublicClient */\n client: PublicClient\n /** Array of Unix timestamps (seconds) to resolve to block numbers */\n timestamps: number[]\n /**\n * Bootstrap block-time used only to pick the anchor block (seconds).\n * The final estimate uses the *measured* rate between latest and anchor,\n * so this only affects which sample point we draw — not accuracy on the\n * sampled window. Default 12 (Ethereum L1).\n */\n fallbackBlockTimeSec?: number\n}\n\n/**\n * Estimate block numbers for the given Unix timestamps using a 2-RPC linear\n * extrapolation. Trades binary-search accuracy (~25 RPCs) for ~2 RPCs.\n *\n * Suitable for chart-style use cases where the consumer plots tens-to-hundreds\n * of evenly-spaced points and a ±N-block error is invisible. Not suitable when\n * exact block correspondence is required (e.g. event log ranges).\n *\n * Algorithm:\n * 1. Fetch `latest` block.\n * 2. Use `fallbackBlockTimeSec` to estimate an anchor block roughly co-temporal\n * with the *earliest* requested timestamp.\n * 3. Fetch the anchor block.\n * 4. Compute the measured average block time over [anchor, latest].\n * 5. Linearly extrapolate every requested timestamp from `latest`.\n *\n * If the sampled window is degenerate (e.g. anchor too close to latest, or\n * timestamps near genesis), falls back to {@link resolveBlockNumbers}.\n */\nexport async function estimateBlockNumbers(params: EstimateBlockNumbersParams): Promise<bigint[]> {\n const { client, timestamps, fallbackBlockTimeSec = 12 } = params\n\n if (timestamps.length === 0) return []\n\n const latest = await client.getBlock({ blockTag: 'latest', includeTransactions: false })\n const latestNum = latest.number\n const latestTs = Number(latest.timestamp)\n\n const earliest = Math.min(...timestamps)\n const secAgoMax = Math.max(0, latestTs - earliest)\n\n // All requested timestamps are now-or-future\n if (secAgoMax === 0) return timestamps.map(() => latestNum)\n\n const blocksBackEst = BigInt(Math.floor(secAgoMax / fallbackBlockTimeSec))\n const anchorNum = blocksBackEst >= latestNum ? 1n : latestNum - blocksBackEst\n const anchor = await client.getBlock({\n blockNumber: anchorNum,\n includeTransactions: false,\n })\n\n const numDelta = latestNum - anchor.number\n const tsDelta = latestTs - Number(anchor.timestamp)\n\n // Degenerate sample window — fall back to exact resolution.\n if (numDelta <= 0n || tsDelta <= 0) {\n return resolveBlockNumbers({ client, timestamps })\n }\n\n const avgBlockTimeSec = tsDelta / Number(numDelta)\n\n return timestamps.map((ts) => {\n const secAgo = latestTs - ts\n if (secAgo <= 0) return latestNum\n const blocksAgo = BigInt(Math.round(secAgo / avgBlockTimeSec))\n return blocksAgo >= latestNum ? 1n : latestNum - blocksAgo\n })\n}\n","/**\n * Multicall utilities for the Panoptic v2 SDK.\n * Uses viem's built-in multicall for same-block consistency.\n * @module v2/clients/multicall\n */\n\nimport type { Abi, Address, ContractFunctionArgs, ContractFunctionName, PublicClient } from 'viem'\n\nimport type { BlockMeta } from '../types'\nimport { getBlockMeta } from './blockMeta'\n\n/**\n * A contract call to include in a multicall batch.\n */\nexport interface MulticallContract<\n TAbi extends Abi = Abi,\n TFunctionName extends ContractFunctionName<TAbi, 'pure' | 'view'> = ContractFunctionName<\n TAbi,\n 'pure' | 'view'\n >,\n> {\n /** Contract address */\n address: Address\n /** Contract ABI */\n abi: TAbi\n /** Function name to call */\n functionName: TFunctionName\n /** Function arguments */\n args?: ContractFunctionArgs<TAbi, 'pure' | 'view', TFunctionName>\n}\n\n/**\n * Parameters for multicallRead.\n */\nexport interface MulticallReadParams<TContracts extends readonly MulticallContract[]> {\n /** viem PublicClient */\n client: PublicClient\n /** Array of contract calls to batch */\n contracts: TContracts\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Whether to allow failures (default: false) */\n allowFailure?: boolean\n}\n\n/**\n * Result type for a single multicall contract result.\n */\nexport type MulticallResult<T> =\n | { status: 'success'; result: T }\n | { status: 'failure'; error: Error }\n\n/**\n * Perform a batched multicall read with block metadata.\n * All calls are executed at the same block for consistency.\n *\n * @param params - The multicall parameters\n * @returns Results array with block metadata\n */\nexport async function multicallRead<TContracts extends readonly MulticallContract[]>(\n params: MulticallReadParams<TContracts>,\n): Promise<{\n results: MulticallResult<unknown>[]\n _meta: BlockMeta\n}> {\n const { client, contracts, blockNumber, allowFailure = false } = params\n\n // Get the block number to use (latest if not specified)\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n // Execute multicall and get block meta in parallel\n const [multicallResults, _meta] = await Promise.all([\n client.multicall({\n contracts: contracts as unknown as Parameters<typeof client.multicall>['0']['contracts'],\n blockNumber: targetBlockNumber,\n allowFailure: true, // Always allow failure internally to handle gracefully\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Map results to our format\n const results: MulticallResult<unknown>[] = multicallResults.map((result) => {\n if (result.status === 'success') {\n return { status: 'success' as const, result: result.result }\n } else {\n // If allowFailure is false and we have a failure, throw\n if (!allowFailure) {\n throw result.error\n }\n return { status: 'failure' as const, error: result.error }\n }\n })\n\n return { results, _meta }\n}\n","/**\n * Factory utility functions for the Panoptic v2 SDK.\n * @module v2/utils/factory\n */\n\n/**\n * Decoded Panoptic NFT metadata from a base64-encoded token URI.\n */\nexport type PanopticNFTMetadata = {\n name: string\n description: string\n attributes: [\n {\n trait_type: 'Rarity'\n value: string\n },\n {\n trait_type: 'Strategy'\n value: string\n },\n {\n trait_type: 'ChainId'\n value: string\n },\n ]\n image: string\n}\n\n/**\n * Decode a base64-encoded Panoptic NFT token URI into metadata.\n *\n * @param tokenURI - The base64-encoded data URI string\n * @returns Parsed NFT metadata object, or undefined if input is invalid\n */\nexport function decodePanopticTokenURI(tokenURI: string): PanopticNFTMetadata | undefined {\n if (tokenURI === undefined || tokenURI === '') {\n return undefined\n }\n const parts = tokenURI.split('data:application/json;base64,')\n if (parts.length < 2 || parts[1] === '') {\n return undefined\n }\n try {\n const decoded = atob(parts[1])\n return JSON.parse(decoded) as PanopticNFTMetadata\n } catch {\n return undefined\n }\n}\n","/**\n * Evenly-spaced block number interpolation utility.\n * @module v2/utils/interpolateBlocks\n */\n\nimport { InvalidHistoryRangeError } from '../errors/sdk'\n\n/**\n * Generate evenly-spaced block numbers between start and end (pure math, no RPC).\n *\n * @param startBlock - First block in the range\n * @param endBlock - Last block in the range\n * @param points - Number of evenly-spaced data points to generate\n * @returns Array of interpolated block numbers\n *\n * @throws {InvalidHistoryRangeError} if startBlock > endBlock or points < 0\n */\nexport function interpolateBlocks(startBlock: bigint, endBlock: bigint, points: number): bigint[] {\n if (!Number.isFinite(points) || !Number.isSafeInteger(points)) {\n throw new InvalidHistoryRangeError(`points must be a finite safe integer, got ${points}`)\n }\n if (points < 0) {\n throw new InvalidHistoryRangeError(`points must be >= 0, got ${points}`)\n }\n if (startBlock > endBlock) {\n throw new InvalidHistoryRangeError(\n `startBlock (${startBlock}) must be <= endBlock (${endBlock})`,\n )\n }\n if (points === 0) return []\n if (points === 1) return [endBlock]\n const range = endBlock - startBlock\n return Array.from(\n { length: points },\n (_, i) => startBlock + (range * BigInt(i)) / BigInt(points - 1),\n )\n}\n","/**\n * Encode SFPM swap calldata (mint + burn wrapped in a single multicall).\n * @module v2/sfpmSwap/calldata\n */\nimport { type Hex, encodeFunctionData } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport type { SfpmSwapPlan } from './types'\n\n/** Encoded calldata for an SFPM swap. */\nexport interface SfpmSwapCalldata {\n /** The `SFPM.multicall(bytes[])` calldata to send to {@link SfpmSwapPlan.sfpmAddress}. */\n multicallData: Hex\n /** The inner `mintTokenizedPosition` calldata (index 0 of the multicall). */\n mintData: Hex\n /** The inner `burnTokenizedPosition` calldata (index 1 of the multicall). */\n burnData: Hex\n}\n\n/**\n * Encode the `multicall([mint, burn])` for a swap plan.\n *\n * The order is always `[mint, burn]` — the ERC1155 must be minted before it is\n * burned. Which call carries the inverted (swap) limits is decided in the plan.\n */\nexport function buildSfpmSwapCalldata(plan: SfpmSwapPlan): SfpmSwapCalldata {\n const mintData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'mintTokenizedPosition',\n args: [\n plan.poolKey,\n plan.tokenId,\n plan.positionSize,\n plan.mintTickLimits[0],\n plan.mintTickLimits[1],\n ],\n })\n const burnData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'burnTokenizedPosition',\n args: [\n plan.poolKey,\n plan.tokenId,\n plan.positionSize,\n plan.burnTickLimits[0],\n plan.burnTickLimits[1],\n ],\n })\n const multicallData = encodeFunctionData({\n abi: sfpmV3Abi,\n functionName: 'multicall',\n args: [[mintData, burnData]],\n })\n return { multicallData, mintData, burnData }\n}\n","/**\n * Resolve / ensure a Uniswap v3 pool is registered on the SFPM.\n * @module v2/sfpmSwap/init\n */\nimport type { Address, PublicClient, WalletClient } from 'viem'\nimport { getAddress, zeroAddress } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport { PanopticError, WrongUniswapPoolError } from '../errors'\nimport { DEFAULT_VEGOID } from '../tokenId'\n\nexport interface FetchSfpmV3PoolIdParams {\n client: PublicClient\n sfpmAddress: Address\n token0: Address\n token1: Address\n /** Uniswap fee tier (e.g. 500 for 0.05%). */\n fee: number\n /** Vegoid; defaults to the SDK {@link DEFAULT_VEGOID}. Must match the market's other pools. */\n vegoid?: number\n}\n\n/**\n * Resolve the `uint64` SFPM poolId for a Uniswap v3 pool, initializing it if needed.\n *\n * `initializeAMMPool` is permissionless and idempotent and **returns the poolId**\n * whether or not the pool was already registered, so a `simulateContract` call is\n * enough to learn the id without sending a transaction. Always resolve the id this\n * way rather than encoding it offline — the SFPM can collision-increment ids.\n */\nexport async function fetchSfpmV3PoolId(params: FetchSfpmV3PoolIdParams): Promise<bigint> {\n const { client, sfpmAddress, token0, token1, fee } = params\n const vegoid = params.vegoid ?? Number(DEFAULT_VEGOID)\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'initializeAMMPool',\n args: [token0, token1, fee, vegoid],\n })\n return BigInt(result)\n}\n\nexport interface EnsureSfpmV3PoolInitializedParams extends FetchSfpmV3PoolIdParams {\n wallet: WalletClient\n /** Expected underlying Uniswap v3 pool; if provided, the resolved id is verified against it. */\n expectedPool?: Address\n}\n\nexport interface EnsureSfpmV3PoolInitializedResult {\n poolId: bigint\n /** True if an `initializeAMMPool` transaction was sent (pool was not yet registered). */\n initialized: boolean\n}\n\n/**\n * Ensure a Uniswap v3 pool is registered on the SFPM, sending `initializeAMMPool`\n * only if it is not already registered. Returns the resolved poolId.\n *\n * When `expectedPool` is given, the resolved id is checked to map back to it via\n * `getUniswapV3PoolFromId` — guards against a wrong token/fee triple.\n */\nexport async function ensureSfpmV3PoolInitialized(\n params: EnsureSfpmV3PoolInitializedParams,\n): Promise<EnsureSfpmV3PoolInitializedResult> {\n const { client, wallet, sfpmAddress, token0, token1, fee, expectedPool } = params\n const vegoid = params.vegoid ?? Number(DEFAULT_VEGOID)\n\n const poolId = await fetchSfpmV3PoolId({ client, sfpmAddress, token0, token1, fee, vegoid })\n\n const registered = await client.readContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n\n let initialized = false\n let resolved = registered\n if (getAddress(registered) === zeroAddress) {\n const account = wallet.account\n if (account === undefined) throw new PanopticError('wallet client has no account')\n const hash = await wallet.writeContract({\n account,\n chain: wallet.chain ?? null,\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'initializeAMMPool',\n args: [token0, token1, fee, vegoid],\n })\n await client.waitForTransactionReceipt({ hash })\n initialized = true\n // Re-read only after we sent initializeAMMPool; an already-registered pool\n // reuses the first read.\n resolved = await client.readContract({\n address: sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n }\n\n if (expectedPool !== undefined && getAddress(resolved) !== getAddress(expectedPool)) {\n throw new WrongUniswapPoolError(\n new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`),\n )\n }\n\n return { poolId, initialized }\n}\n","/**\n * Build an SFPM off-venue swap plan (tokenId + per-call tick limits).\n * @module v2/sfpmSwap/plan\n */\nimport { encodeAbiParameters } from 'viem'\n\nimport { PanopticError } from '../errors'\nimport { createTokenIdBuilder } from '../tokenId'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport type { SfpmSwapPlan, SfpmSwapPlanParams } from './types'\n\n/** Wide, non-inverted band for the paired (non-swapping) call — never triggers a swap. */\nconst WIDE_LIMITS: [number, number] = [Number(MIN_TICK) + 1, Number(MAX_TICK) - 1]\n\n/**\n * Convert a slippage tolerance in bps to a conservative Uniswap tick distance.\n *\n * Ticks are 1.0001^tick, so each tick ≈ 1 bps. This walks up powers of 1.0001\n * until the cumulative price move covers `slippageBps`, matching the hedger-bot's\n * dispatch-path helper so both swap paths agree on band width.\n */\nexport function slippageBpsToTickDistance(slippageBps: bigint): bigint {\n if (slippageBps < 0n || slippageBps > 1000n) {\n throw new PanopticError(`slippage bps ${slippageBps} out of bounds (0..1000)`)\n }\n if (slippageBps === 0n) return 0n\n let numerator = 1n\n let denominator = 1n\n let ticks = 0n\n while (numerator * 10_000n < denominator * (10_000n + slippageBps)) {\n numerator *= 10_001n\n denominator *= 10_000n\n ticks += 1n\n }\n return ticks\n}\n\n/**\n * Build the swap plan.\n *\n * Mechanism (verified in the Phase 0 fork test):\n * - A single-leg **loan** tokenId (width=0, isLong=false, `asset == tokenType`) moves\n * exactly `positionSize` of the `tokenType` token when its call carries inverted\n * tick limits (`low > high`); the paired call uses a wide band and moves nothing.\n * - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.\n * - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the\n * **output** token index.\n *\n * The inverted band is centered on `currentTick` at ±`slippageBpsToTickDistance`,\n * which the SFPM re-sorts and enforces as an open interval on the post-swap tick.\n */\nexport function buildSfpmSwapPlan(params: SfpmSwapPlanParams): SfpmSwapPlan {\n const { sfpmAddress, poolAddress, poolId, kind, zeroForOne, amount, currentTick, slippageBps } =\n params\n\n if (amount <= 0n) throw new PanopticError(`swap amount must be positive (got ${amount})`)\n\n const distance = slippageBpsToTickDistance(slippageBps)\n if (distance < 1n) {\n // low > high must hold strictly to trigger the swap, and the post-swap tick\n // check is an open interval — a zero-width band can never pass.\n throw new PanopticError(\n `slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`,\n )\n }\n\n // exactIn → tokenType = input token; exactOut → tokenType = output token.\n const tokenType = kind === 'exactIn' ? (zeroForOne ? 0n : 1n) : zeroForOne ? 1n : 0n\n\n const tokenId = createTokenIdBuilder(poolId)\n .addLoan({ asset: tokenType, tokenType, strike: 0n })\n .build()\n\n const d = Number(distance)\n // Inverted (swap-triggering) band: low > high, clamped to the valid tick range\n // so an extreme tolerance near a range extreme can't produce an unrepresentable\n // limit.\n const low = Math.min(Number(MAX_TICK), currentTick + d)\n const high = Math.max(Number(MIN_TICK), currentTick - d)\n if (low <= high) {\n throw new PanopticError(\n `slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`,\n )\n }\n const invertedLimits: [number, number] = [low, high]\n const swapOn: 'mint' | 'burn' = kind === 'exactIn' ? 'mint' : 'burn'\n\n return {\n sfpmAddress,\n poolAddress,\n poolKey: encodeAbiParameters([{ type: 'address' }], [poolAddress]),\n tokenId,\n positionSize: amount,\n mintTickLimits: swapOn === 'mint' ? invertedLimits : WIDE_LIMITS,\n burnTickLimits: swapOn === 'burn' ? invertedLimits : WIDE_LIMITS,\n swapOn,\n kind,\n }\n}\n","/**\n * Quote an SFPM off-venue swap by simulating the actual multicall.\n * @module v2/sfpmSwap/quote\n */\nimport { type Address, type PublicClient, type StateOverride, decodeFunctionResult } from 'viem'\n\nimport { semiFungiblePositionManagerV3Abi as sfpmV3Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError, parsePanopticError } from '../errors'\nimport type { SimulationResult } from '../types'\nimport { buildSfpmSwapCalldata } from './calldata'\nimport type { SfpmSwapPlan, SfpmSwapQuote } from './types'\n\nconst UINT128 = 1n << 128n\nconst INT128_MAX = (1n << 127n) - 1n\n\n/** Extract the two signed 128-bit slots from a packed `LeftRightSigned` int256. */\nfunction unpackLeftRightSigned(packed: bigint): { right: bigint; left: bigint } {\n const u = packed < 0n ? packed + (1n << 256n) : packed\n const toInt128 = (half: bigint): bigint => (half > INT128_MAX ? half - UINT128 : half)\n return {\n right: toInt128(u & (UINT128 - 1n)), // token0\n left: toInt128((u >> 128n) & (UINT128 - 1n)), // token1\n }\n}\n\n/** Wrap an unknown thrown value as a PanopticError, decoding Panoptic reverts when possible. */\nfunction toPanopticError(err: unknown): PanopticError {\n if (err instanceof PanopticError) return err\n const parsed = parsePanopticError(err)\n if (parsed) return parsed.error\n return new PanopticError(\n err instanceof Error ? err.message : 'SFPM swap simulation failed',\n err instanceof Error ? err : undefined,\n )\n}\n\nexport interface QuoteSfpmSwapParams {\n client: PublicClient\n /** Plan from {@link buildSfpmSwapPlan}. */\n plan: SfpmSwapPlan\n /** Caller executing the swap (the Safe in production); must hold the input token. */\n account: Address\n /**\n * Optional viem state overrides — e.g. to grant the input-token allowance to the\n * SFPM and/or fund the account so the quote works before approvals exist. In\n * production (Safe already approved + funded) this can be omitted.\n */\n stateOverride?: StateOverride\n blockNumber?: bigint\n}\n\n/**\n * Quote a swap by simulating `SFPM.multicall([mint, burn])` and decoding the swap\n * call's `totalMoved` return. Authoritative — captures the width-0 loan-leg wei\n * rounding a raw QuoterV2 quote would miss.\n */\nexport async function quoteSfpmSwap(\n params: QuoteSfpmSwapParams,\n): Promise<SimulationResult<SfpmSwapQuote>> {\n const { client, plan, account, stateOverride, blockNumber } = params\n const { mintData, burnData } = buildSfpmSwapCalldata(plan)\n const _meta = await getBlockMeta({ client, blockNumber })\n\n try {\n const { result } = await client.simulateContract({\n account,\n address: plan.sfpmAddress,\n abi: sfpmV3Abi,\n functionName: 'multicall',\n args: [[mintData, burnData]],\n blockNumber,\n stateOverride,\n })\n\n const swapIndex = plan.swapOn === 'mint' ? 0 : 1\n const decoded = decodeFunctionResult({\n abi: sfpmV3Abi,\n functionName: plan.swapOn === 'mint' ? 'mintTokenizedPosition' : 'burnTokenizedPosition',\n data: (result as readonly `0x${string}`[])[swapIndex],\n }) as readonly [readonly bigint[], bigint, number]\n\n const finalTick = Number(decoded[2])\n const { right, left } = unpackLeftRightSigned(decoded[1])\n const inSlot = [right, left].find((s) => s > 0n)\n const outSlot = [right, left].find((s) => s < 0n)\n if (inSlot === undefined || outSlot === undefined) {\n return {\n success: false,\n error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),\n _meta,\n }\n }\n\n return {\n success: true,\n data: { amountIn: inSlot, amountOut: -outSlot, finalTick },\n gasEstimate: 0n,\n _meta,\n }\n } catch (err) {\n return { success: false, error: toPanopticError(err), _meta }\n }\n}\n","/**\n * SFPM read functions — poolId resolution, enforced tick limits, chunk liquidity.\n *\n * @module v2/reads/sfpm\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n semiFungiblePositionManagerV3Abi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { ChunkLimitError } from '../errors'\nimport type { BlockMeta, PoolKey } from '../types'\nimport { MAX_TRACKED_CHUNKS } from '../utils/constants'\n\n// ---------------------------------------------------------------------------\n// getUniswapV3PoolFromId\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link getUniswapV3PoolFromId}.\n */\nexport interface GetUniswapV3PoolFromIdParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManagerV3 address */\n sfpmAddress: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/**\n * Resolve an SFPM poolId to its corresponding Uniswap V3 pool address.\n *\n * Calls `SemiFungiblePositionManagerV3.getUniswapV3PoolFromId(poolId)`.\n */\nexport async function getUniswapV3PoolFromId(\n params: GetUniswapV3PoolFromIdParams,\n): Promise<Address> {\n const { client, sfpmAddress, poolId } = params\n return client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV3Abi,\n functionName: 'getUniswapV3PoolFromId',\n args: [poolId],\n })\n}\n\n// ---------------------------------------------------------------------------\n// getUniswapV4PoolKeyFromId\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link getUniswapV4PoolKeyFromId}.\n */\nexport interface GetUniswapV4PoolKeyFromIdParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManagerV4 address */\n sfpmAddress: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/**\n * Resolve an SFPM poolId to its corresponding Uniswap V4 pool key.\n *\n * Calls `SemiFungiblePositionManagerV4.getUniswapV4PoolKeyFromId(poolId)`.\n */\nexport async function getUniswapV4PoolKeyFromId(\n params: GetUniswapV4PoolKeyFromIdParams,\n): Promise<PoolKey> {\n const { client, sfpmAddress, poolId } = params\n const raw = await client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getUniswapV4PoolKeyFromId',\n args: [poolId],\n })\n return {\n currency0: raw.currency0,\n currency1: raw.currency1,\n fee: BigInt(raw.fee),\n tickSpacing: BigInt(raw.tickSpacing),\n hooks: raw.hooks,\n }\n}\n\n// ---------------------------------------------------------------------------\n// getEnforcedTickLimits\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getEnforcedTickLimits.\n */\nexport interface GetEnforcedTickLimitsParams {\n /** viem PublicClient */\n client: PublicClient\n /** SFPM address (from getPool().metadata.sfpmAddress) */\n sfpmAddress: Address\n /** Encoded pool ID (from getPool().poolId) */\n poolId: bigint\n}\n\n/**\n * Result from getEnforcedTickLimits.\n */\nexport interface EnforcedTickLimits {\n minEnforcedTick: number\n maxEnforcedTick: number\n}\n\n/**\n * Get the enforced tick limits for a pool from the SFPM.\n *\n * @param params - The parameters\n * @returns The min and max enforced ticks\n */\nexport async function getEnforcedTickLimits(\n params: GetEnforcedTickLimitsParams,\n): Promise<EnforcedTickLimits> {\n const { client, sfpmAddress, poolId } = params\n\n const [minTick, maxTick] = await client.readContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getEnforcedTickLimits',\n args: [poolId],\n })\n\n return {\n minEnforcedTick: minTick,\n maxEnforcedTick: maxTick,\n }\n}\n\n// ---------------------------------------------------------------------------\n// getChunkLiquidities\n// ---------------------------------------------------------------------------\n\nexport interface ChunkInput {\n /** Owner address (panopticPool address for Panoptic chunks) */\n owner: Address\n /** 0 or 1 */\n tokenType: bigint\n tickLower: bigint\n tickUpper: bigint\n}\n\nexport interface ChunkLiquidityResult {\n /** Liquidity currently deployed in Uniswap */\n netLiquidity: bigint\n /** Liquidity removed by long holders */\n removedLiquidity: bigint\n /** Total liquidity deposited by shorts (net + removed) */\n totalLiquidity: bigint\n /** Alias for totalLiquidity (shorts deposited all of it) */\n shortLiquidity: bigint\n /** Alias for removedLiquidity (longs removed this much) */\n longLiquidity: bigint\n}\n\nexport interface GetChunkLiquiditiesParams {\n client: PublicClient\n /** SFPM address */\n sfpmAddress: Address\n /** Pool key bytes (from getPool().metadata.poolKeyBytes) */\n poolKeyBytes: `0x${string}`\n /** Chunks to query */\n chunks: ChunkInput[]\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\nexport interface GetChunkLiquiditiesResult {\n /** One result per input chunk */\n results: ChunkLiquidityResult[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Fetch liquidity breakdown for a batch of chunks via SFPM.getAccountLiquidity().\n *\n * Uses multicall for efficiency. Returns one result per input chunk,\n * along with block metadata for freshness tracking.\n */\nexport async function getChunkLiquidities(\n params: GetChunkLiquiditiesParams,\n): Promise<GetChunkLiquiditiesResult> {\n const { client, sfpmAddress, poolKeyBytes, chunks } = params\n\n if (chunks.length > MAX_TRACKED_CHUNKS) {\n throw new ChunkLimitError(BigInt(chunks.length), 0n)\n }\n\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n\n if (chunks.length === 0) return { results: [], _meta }\n\n // Batch all getAccountLiquidity calls\n const multicallResults = await client.multicall({\n contracts: chunks.map((chunk) => ({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'getAccountLiquidity' as const,\n args: [\n poolKeyBytes,\n chunk.owner,\n chunk.tokenType,\n Number(chunk.tickLower),\n Number(chunk.tickUpper),\n ],\n })),\n allowFailure: true,\n })\n\n const results = multicallResults.map((result) => {\n if (result.status === 'failure') {\n return {\n netLiquidity: 0n,\n removedLiquidity: 0n,\n totalLiquidity: 0n,\n shortLiquidity: 0n,\n longLiquidity: 0n,\n }\n }\n\n const packed = result.result as bigint\n // LeftRightUnsigned: right 128 bits = netLiquidity, left 128 bits = removedLiquidity\n const netLiquidity = packed & ((1n << 128n) - 1n)\n const removedLiquidity = packed >> 128n\n const totalLiquidity = netLiquidity + removedLiquidity\n\n return {\n netLiquidity,\n removedLiquidity,\n totalLiquidity,\n shortLiquidity: totalLiquidity,\n longLiquidity: removedLiquidity,\n }\n })\n\n return { results, _meta }\n}\n","/**\n * Factory read functions for the Panoptic v2 SDK.\n *\n * Supports both PanopticFactoryV3 (Uniswap V3) and PanopticFactoryV4 (Uniswap V4).\n *\n * @module v2/reads/factory\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { zeroAddress } from 'viem'\n\nimport { panopticFactoryV3Abi, panopticFactoryV4Abi } from '../../../generated'\nimport type { PoolKey } from '../types'\nimport { getUniswapV3PoolFromId, getUniswapV4PoolKeyFromId } from './sfpm'\n\n// ---------------------------------------------------------------------------\n// Shared reads (identical signature on both V3 and V4)\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getFactoryTokenURI.\n */\nexport interface GetFactoryTokenURIParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** Token ID (encoded pool address) */\n tokenId: bigint\n}\n\n/**\n * Get the token URI from a PanopticFactory NFT.\n */\nexport async function getFactoryTokenURI(params: GetFactoryTokenURIParams): Promise<string> {\n const { client, factoryAddress, version, tokenId } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'tokenURI',\n args: [tokenId],\n })\n}\n\n/**\n * Parameters for getFactoryOwnerOf.\n */\nexport interface GetFactoryOwnerOfParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** Token ID (encoded pool address) */\n tokenId: bigint\n}\n\n/**\n * Get the owner of a PanopticFactory NFT.\n */\nexport async function getFactoryOwnerOf(params: GetFactoryOwnerOfParams): Promise<Address> {\n const { client, factoryAddress, version, tokenId } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'ownerOf',\n args: [tokenId],\n })\n}\n\n/**\n * Parameters for getFactoryConstructMetadata.\n */\nexport interface GetFactoryConstructMetadataParams {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Factory version */\n version: 'v3' | 'v4'\n /** PanopticPool address (or predicted address) */\n panopticPoolAddress: Address\n /** Token 0 symbol */\n symbol0: string\n /** Token 1 symbol */\n symbol1: string\n /** Fee tier */\n fee: bigint\n}\n\n/**\n * Construct NFT metadata for a pool via the factory contract.\n */\nexport async function getFactoryConstructMetadata(\n params: GetFactoryConstructMetadataParams,\n): Promise<string> {\n const { client, factoryAddress, version, panopticPoolAddress, symbol0, symbol1, fee } = params\n const abi = version === 'v3' ? panopticFactoryV3Abi : panopticFactoryV4Abi\n\n return client.readContract({\n address: factoryAddress,\n abi,\n functionName: 'constructMetadata',\n args: [panopticPoolAddress, symbol0, symbol1, fee],\n })\n}\n\n// ---------------------------------------------------------------------------\n// V3-specific reads\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for getPanopticPoolAddress on a V3 factory.\n */\nexport interface GetPanopticPoolAddressV3Params {\n /** Public client */\n client: PublicClient\n /** PanopticFactoryV3 address */\n factoryAddress: Address\n /** Uniswap V3 pool address */\n univ3pool: Address\n /** Risk engine address */\n riskEngine: Address\n}\n\n/**\n * Parameters for getPanopticPoolAddress on a V4 factory.\n */\nexport interface GetPanopticPoolAddressV4Params {\n /** Public client */\n client: PublicClient\n /** PanopticFactoryV4 address */\n factoryAddress: Address\n /** V4 pool key */\n poolKey: PoolKey\n /** Risk engine address */\n riskEngine: Address\n}\n\n/** Versioned params for {@link getPanopticPoolAddress}. Use `version` to select V3 or V4. */\nexport type GetPanopticPoolAddressParams =\n | ({ version: 'v3' } & GetPanopticPoolAddressV3Params)\n | ({ version: 'v4' } & GetPanopticPoolAddressV4Params)\n\n/**\n * Get the PanopticPool address for a given pool and risk engine.\n */\nexport async function getPanopticPoolAddress(\n params: GetPanopticPoolAddressParams,\n): Promise<Address> {\n const { client, factoryAddress, riskEngine } = params\n\n if (params.version === 'v3') {\n return client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'getPanopticPool',\n args: [params.univ3pool, riskEngine],\n })\n }\n\n return client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'getPanopticPool',\n args: [\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n ],\n })\n}\n\n// ---------------------------------------------------------------------------\n// minePoolAddress\n// ---------------------------------------------------------------------------\n\n/**\n * Common mining parameters shared between V3 and V4.\n */\ninterface MinePoolAddressCommon {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Deployer address (msg.sender for deployment) */\n deployerAddress: Address\n /** Risk engine address */\n riskEngine: Address\n /** Starting salt (uint96) */\n salt: bigint\n /** Number of mining iterations */\n loops: bigint\n /** Minimum rarity target */\n minTargetRarity: bigint\n}\n\nexport interface MinePoolAddressV3Params extends MinePoolAddressCommon {\n /** Uniswap V3 pool address */\n v3Pool: Address\n}\n\nexport interface MinePoolAddressV4Params extends MinePoolAddressCommon {\n /** V4 pool key */\n poolKey: PoolKey\n}\n\n/** Versioned params for {@link minePoolAddress}. Use `version` to select V3 or V4. */\nexport type MinePoolAddressParams =\n | ({ version: 'v3' } & MinePoolAddressV3Params)\n | ({ version: 'v4' } & MinePoolAddressV4Params)\n\n/**\n * Result of pool address mining.\n */\nexport interface MinePoolAddressResult {\n /** Best salt found */\n bestSalt: bigint\n /** Highest rarity achieved */\n highestRarity: bigint\n}\n\n/**\n * Mine for an optimal pool address salt with high rarity.\n */\nexport async function minePoolAddress(\n params: MinePoolAddressParams,\n): Promise<MinePoolAddressResult> {\n const { client, factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } =\n params\n\n let result: readonly [bigint, bigint]\n\n if (params.version === 'v3') {\n result = await client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'minePoolAddress',\n args: [deployerAddress, params.v3Pool, riskEngine, salt, loops, minTargetRarity],\n })\n } else {\n result = await client.readContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'minePoolAddress',\n args: [\n deployerAddress,\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n salt,\n loops,\n minTargetRarity,\n ],\n })\n }\n\n return { bestSalt: BigInt(result[0]), highestRarity: result[1] }\n}\n\n// ---------------------------------------------------------------------------\n// simulateDeployNewPool\n// ---------------------------------------------------------------------------\n\ninterface SimulateDeployNewPoolCommon {\n /** Public client */\n client: PublicClient\n /** PanopticFactory address */\n factoryAddress: Address\n /** Account address (deployer) */\n account: Address\n /** Risk engine address */\n riskEngine: Address\n /** Salt (uint96) */\n salt: bigint\n}\n\nexport interface SimulateDeployNewPoolV3Params extends SimulateDeployNewPoolCommon {\n /** Token 0 address */\n token0: Address\n /** Token 1 address */\n token1: Address\n /** Fee tier (uint24) */\n fee: bigint\n}\n\nexport interface SimulateDeployNewPoolV4Params extends SimulateDeployNewPoolCommon {\n /** V4 pool key */\n poolKey: PoolKey\n}\n\nexport type SimulateDeployNewPoolParams =\n | ({ version: 'v3' } & SimulateDeployNewPoolV3Params)\n | ({ version: 'v4' } & SimulateDeployNewPoolV4Params)\n\n/**\n * Simulate a pool deployment to get the predicted pool address.\n *\n * Uses `simulateContract` on `deployNewPool` — the return value is the new pool address\n * without actually executing the transaction.\n */\nexport async function simulateDeployNewPool(params: SimulateDeployNewPoolParams): Promise<Address> {\n const { client, factoryAddress, account, riskEngine, salt } = params\n\n if (params.version === 'v3') {\n const { result } = await client.simulateContract({\n address: factoryAddress,\n abi: panopticFactoryV3Abi,\n functionName: 'deployNewPool',\n args: [params.token0, params.token1, Number(params.fee), riskEngine, salt],\n account,\n })\n return result\n }\n\n const { result } = await client.simulateContract({\n address: factoryAddress,\n abi: panopticFactoryV4Abi,\n functionName: 'deployNewPool',\n args: [\n {\n currency0: params.poolKey.currency0,\n currency1: params.poolKey.currency1,\n fee: Number(params.poolKey.fee),\n tickSpacing: Number(params.poolKey.tickSpacing),\n hooks: params.poolKey.hooks,\n },\n riskEngine,\n salt,\n ],\n account,\n })\n return result\n}\n\n// ---------------------------------------------------------------------------\n// getPanopticPoolFromPoolId\n// ---------------------------------------------------------------------------\n\n/**\n * Common parameters for {@link getPanopticPoolFromPoolId}.\n */\ninterface GetPanopticPoolFromPoolIdCommon {\n /** Public client */\n client: PublicClient\n /** SFPM address */\n sfpmAddress: Address\n /** PanopticFactory address */\n factoryAddress: Address\n /** Risk engine address */\n riskEngine: Address\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n}\n\n/** Versioned params for {@link getPanopticPoolFromPoolId}. */\nexport type GetPanopticPoolFromPoolIdParams =\n | ({ version: 'v3' } & GetPanopticPoolFromPoolIdCommon)\n | ({ version: 'v4' } & GetPanopticPoolFromPoolIdCommon)\n\n/**\n * Resolve an SFPM poolId to its PanopticPool address.\n *\n * Chains two on-chain lookups:\n * 1. SFPM: poolId → Uniswap pool address (V3) or pool key (V4)\n * 2. Factory: Uniswap pool + riskEngine → PanopticPool address\n */\nexport async function getPanopticPoolFromPoolId(\n params: GetPanopticPoolFromPoolIdParams,\n): Promise<Address> {\n const { client, sfpmAddress, factoryAddress, riskEngine, poolId, version } = params\n\n if (version === 'v3') {\n const univ3pool = await getUniswapV3PoolFromId({ client, sfpmAddress, poolId })\n return getPanopticPoolAddress({\n version: 'v3',\n client,\n factoryAddress,\n univ3pool,\n riskEngine,\n })\n }\n\n const poolKey = await getUniswapV4PoolKeyFromId({ client, sfpmAddress, poolId })\n return getPanopticPoolAddress({\n version: 'v4',\n client,\n factoryAddress,\n poolKey,\n riskEngine,\n })\n}\n\n// ---------------------------------------------------------------------------\n// resolvePanopticPoolFromPoolId (version-agnostic)\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for {@link resolvePanopticPoolFromPoolId}.\n */\nexport interface ResolvePanopticPoolFromPoolIdParams {\n /** Public client */\n client: PublicClient\n /** The SFPM pool identifier (uint64) */\n poolId: bigint\n /** Risk engine address */\n riskEngine: Address\n /** V3 SFPM + Factory addresses (omit if V3 is not deployed) */\n v3?: {\n sfpmAddress: Address\n factoryAddress: Address\n }\n /** V4 SFPM + Factory addresses (omit if V4 is not deployed) */\n v4?: {\n sfpmAddress: Address\n factoryAddress: Address\n }\n}\n\n/**\n * Result of {@link resolvePanopticPoolFromPoolId}.\n */\nexport interface ResolvePanopticPoolFromPoolIdResult {\n /** The resolved PanopticPool address */\n panopticPoolAddress: Address\n /** Which version matched */\n version: 'v3' | 'v4'\n}\n\n/**\n * Resolve an SFPM poolId to its PanopticPool address without knowing the version.\n *\n * Tries both V3 and V4 lookups in parallel. The factory returns `address(0)` for\n * non-existent pools, so the non-zero result identifies the correct version.\n *\n * At least one of `v3` or `v4` must be provided.\n *\n * @throws {PanopticValidationError} If no version config is provided or neither resolves.\n */\nexport async function resolvePanopticPoolFromPoolId(\n params: ResolvePanopticPoolFromPoolIdParams,\n): Promise<ResolvePanopticPoolFromPoolIdResult> {\n const { client, poolId, riskEngine, v3, v4 } = params\n\n if (!v3 && !v4) {\n throw new Error('At least one of v3 or v4 must be provided')\n }\n\n const isNotFoundError = (err: unknown): boolean => {\n // Contract reverts (e.g. pool not registered) are \"not found\".\n // RPC / ABI / network errors should propagate.\n if (typeof err === 'object' && err !== null && 'name' in err) {\n const name = (err as { name: string }).name\n return name === 'ContractFunctionExecutionError' || name === 'ContractFunctionRevertedError'\n }\n return false\n }\n\n const results = await Promise.all([\n v3\n ? getPanopticPoolFromPoolId({\n version: 'v3',\n client,\n sfpmAddress: v3.sfpmAddress,\n factoryAddress: v3.factoryAddress,\n riskEngine,\n poolId,\n }).catch((err) => {\n if (isNotFoundError(err)) return zeroAddress\n throw err\n })\n : Promise.resolve(zeroAddress),\n v4\n ? getPanopticPoolFromPoolId({\n version: 'v4',\n client,\n sfpmAddress: v4.sfpmAddress,\n factoryAddress: v4.factoryAddress,\n riskEngine,\n poolId,\n }).catch((err) => {\n if (isNotFoundError(err)) return zeroAddress\n throw err\n })\n : Promise.resolve(zeroAddress),\n ])\n\n const [v3Result, v4Result] = results\n\n if (v3Result !== zeroAddress) {\n return { panopticPoolAddress: v3Result, version: 'v3' }\n }\n if (v4Result !== zeroAddress) {\n return { panopticPoolAddress: v4Result, version: 'v4' }\n }\n\n throw new Error(`No PanopticPool found for poolId ${poolId}`)\n}\n","/**\n * Client-side (off-chain) implementation of minePoolAddress.\n *\n * Replicates the on-chain PanopticFactory mining loop entirely in TypeScript,\n * eliminating RPC round-trips. The result is identical to the on-chain computation.\n *\n * Algorithm:\n * For each candidate salt (uint96):\n * 1. Pack a bytes32 salt from deployer, pool identifier, riskEngine, and iteration salt\n * 2. Predict the CREATE3 deployed address (via proxy)\n * 3. Score by leading hex zeros (\"rarity\")\n * 4. Track the best salt; stop early if minTargetRarity is reached\n *\n * @module v2/reads/minePoolAddressLocal\n */\n\nimport type { Address, Hex } from 'viem'\nimport { encodeAbiParameters, keccak256 } from 'viem'\n\nimport { PanopticValidationError } from '../errors'\nimport type { PoolKey } from '../types'\nimport type {\n MinePoolAddressResult,\n MinePoolAddressV3Params,\n MinePoolAddressV4Params,\n} from './factory'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Mining params for PanopticFactoryV3 — no RPC client needed. */\nexport type MinePoolAddressLocalV3Params = Omit<MinePoolAddressV3Params, 'client'>\n\n/** Mining params for PanopticFactoryV4 — no RPC client needed. */\nexport type MinePoolAddressLocalV4Params = Omit<MinePoolAddressV4Params, 'client'>\n\nexport type MinePoolAddressLocalParams =\n | ({ version: 'v3' } & MinePoolAddressLocalV3Params)\n | ({ version: 'v4' } & MinePoolAddressLocalV4Params)\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * keccak256 of the CREATE3 proxy initcode used by ClonesWithImmutableArgs.\n * Source: packages/panoptic-v2-core/lib/clones-with-immutable-args/src/ClonesWithImmutableArgs.sol\n */\nconst CREATE3_PROXY_BYTECODE_HASH =\n '0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f' as Hex\n\nconst MASK_80 = (1n << 80n) - 1n\nconst MASK_40 = (1n << 40n) - 1n\nconst MASK_96 = (1n << 96n) - 1n\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/** Encode a BigInt as a big-endian fixed-length byte array. */\nfunction bigintToBytes(value: bigint, byteLength: number): Uint8Array {\n const bytes = new Uint8Array(byteLength)\n let v = value\n for (let i = byteLength - 1; i >= 0; i--) {\n bytes[i] = Number(v & 0xffn)\n v >>= 8n\n }\n return bytes\n}\n\n/** Parse a 0x-prefixed address into 20 bytes. */\nfunction addressToBytes(addr: Address): Uint8Array {\n const hex = addr.slice(2).padStart(40, '0')\n const bytes = new Uint8Array(20)\n for (let i = 0; i < 20; i++) {\n bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\n/** Parse a 0x-prefixed 32-byte hex string into bytes. */\nfunction hex32ToBytes(hex: Hex): Uint8Array {\n const h = hex.slice(2).padStart(64, '0')\n const bytes = new Uint8Array(32)\n for (let i = 0; i < 32; i++) {\n bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\n/**\n * Compute the CREATE3 deployed address for a given factory and packed salt.\n *\n * Mirrors `ClonesWithImmutableArgs.addressOfClone3(salt)` (with `address(this)` = factory):\n * proxy = CREATE2(factory, salt, PROXY_BYTECODE_HASH)\n * deployed = CREATE1(proxy, nonce=1)\n *\n * Returns the deployed address as a uint160 BigInt.\n */\nfunction addressOfClone3(factory: Address, salt: bigint): bigint {\n const saltBytes = bigintToBytes(salt, 32)\n\n // CREATE2: keccak256(0xff ++ factory ++ salt ++ proxyBytecodeHash) — 85 bytes total\n const create2Input = new Uint8Array(85)\n create2Input[0] = 0xff\n create2Input.set(addressToBytes(factory), 1) // bytes 1–20\n create2Input.set(saltBytes, 21) // bytes 21–52\n create2Input.set(hex32ToBytes(CREATE3_PROXY_BYTECODE_HASH), 53) // bytes 53–84\n\n const proxyHash = keccak256(create2Input, 'bytes')\n const proxyAddress = proxyHash.slice(12) // rightmost 20 bytes\n\n // CREATE1 nonce=1: keccak256(0xd694 ++ proxy ++ 0x01) — 23 bytes total\n const create1Input = new Uint8Array(23)\n create1Input[0] = 0xd6\n create1Input[1] = 0x94\n create1Input.set(proxyAddress, 2) // bytes 2–21\n create1Input[22] = 0x01\n\n const deployedHash = keccak256(create1Input, 'bytes')\n\n // Convert rightmost 20 bytes to uint160 BigInt\n let addr = 0n\n for (let i = 12; i < 32; i++) {\n addr = (addr << 8n) | BigInt(deployedHash[i])\n }\n return addr\n}\n\n/**\n * Count leading hex-zero characters in a 160-bit address value.\n *\n * Mirrors `PanopticMath.numberOfLeadingHexZeros(addr)`.\n * Returns 40 for the zero address.\n */\nexport function numberOfLeadingHexZeros(addrInt: bigint): number {\n if (addrInt === 0n) return 40\n let x = addrInt\n let r = 0\n if (x >= 0x100000000000000000000000000000000n) {\n x >>= 128n\n r += 32\n }\n if (x >= 0x10000000000000000n) {\n x >>= 64n\n r += 16\n }\n if (x >= 0x100000000n) {\n x >>= 32n\n r += 8\n }\n if (x >= 0x10000n) {\n x >>= 16n\n r += 4\n }\n if (x >= 0x100n) {\n x >>= 8n\n r += 2\n }\n if (x >= 0x10n) {\n r += 1\n }\n return 39 - r\n}\n\n/**\n * Construct the bytes32 CREATE3 salt for PanopticFactoryV3.\n *\n * Mirrors:\n * bytes32(abi.encodePacked(\n * uint80(uint160(deployerAddress) >> 80), // bits [159:80] of deployer → 10 bytes\n * uint40(uint160(v3Pool) >> 120), // bits [159:120] of v3Pool → 5 bytes\n * uint40(uint160(riskEngine) >> 120), // bits [159:120] of riskEngine→ 5 bytes\n * salt // uint96 → 12 bytes\n * ))\n */\nfunction computeSaltPrefixV3(\n deployerAddress: Address,\n v3Pool: Address,\n riskEngine: Address,\n): bigint {\n const deployer80 = (BigInt(deployerAddress) >> 80n) & MASK_80\n const pool40 = (BigInt(v3Pool) >> 120n) & MASK_40\n const risk40 = (BigInt(riskEngine) >> 120n) & MASK_40\n return (deployer80 << 176n) | (pool40 << 136n) | (risk40 << 96n)\n}\n\n/**\n * Compute the Uniswap V4 PoolId for a PoolKey.\n *\n * Mirrors `PoolId.toId(key)` = keccak256 of the ABI-encoded PoolKey struct\n * (5 fields × 32 bytes = 160 bytes).\n */\nexport function computePoolIdV4(poolKey: PoolKey): bigint {\n const fee = Number(poolKey.fee)\n if (!Number.isInteger(fee) || fee < 0 || fee >= 2 ** 24) {\n throw new PanopticValidationError(`fee out of uint24 range: ${fee}`)\n }\n const tickSpacing = Number(poolKey.tickSpacing)\n if (!Number.isInteger(tickSpacing) || tickSpacing < -(2 ** 23) || tickSpacing > 2 ** 23 - 1) {\n throw new PanopticValidationError(`tickSpacing out of int24 range: ${tickSpacing}`)\n }\n const encoded = encodeAbiParameters(\n [\n { type: 'address' },\n { type: 'address' },\n { type: 'uint24' },\n { type: 'int24' },\n { type: 'address' },\n ],\n [\n poolKey.currency0,\n poolKey.currency1,\n Number(poolKey.fee),\n Number(poolKey.tickSpacing),\n poolKey.hooks,\n ],\n )\n return BigInt(keccak256(encoded))\n}\n\n/**\n * Construct the bytes32 CREATE3 salt for PanopticFactoryV4.\n *\n * Mirrors:\n * bytes32(abi.encodePacked(\n * uint80(uint160(deployerAddress) >> 80),\n * uint40(uint256(PoolId.unwrap(key.toId())) >> 120), // bits [159:120] of poolId\n * uint40(uint160(riskEngine) >> 120),\n * salt\n * ))\n */\nfunction computeSaltPrefixV4(\n deployerAddress: Address,\n poolKey: PoolKey,\n riskEngine: Address,\n): bigint {\n const deployer80 = (BigInt(deployerAddress) >> 80n) & MASK_80\n const poolId40 = (computePoolIdV4(poolKey) >> 120n) & MASK_40\n const risk40 = (BigInt(riskEngine) >> 120n) & MASK_40\n return (deployer80 << 176n) | (poolId40 << 136n) | (risk40 << 96n)\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Mine for an optimal Panoptic pool address salt, running entirely off-chain.\n *\n * Equivalent to calling `minePoolAddress` on the factory contract but with zero\n * RPC round-trips. The result is identical to the on-chain computation.\n *\n * Iterates `loops` times starting from `salt`, tracking the highest-rarity address\n * found. Stops early when `minTargetRarity` is reached.\n *\n * @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.\n * @returns The best salt found and its rarity (number of leading hex zeros).\n */\nexport function minePoolAddressLocal(params: MinePoolAddressLocalParams): MinePoolAddressResult {\n const { factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params\n\n if (salt < 0n || loops < 0n || minTargetRarity < 0n) {\n throw new PanopticValidationError('salt, loops, and minTargetRarity must be non-negative')\n }\n if (salt + loops > (1n << 96n) - 1n) {\n throw new PanopticValidationError('salt + loops exceeds uint96 range')\n }\n\n let bestSalt = salt\n let highestRarity = 0n\n const maxSalt = salt + loops\n\n // Precompute the invariant high-bit prefix once outside the loop\n const saltPrefix =\n params.version === 'v3'\n ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine)\n : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine)\n\n for (let currentSalt = salt; currentSalt < maxSalt; currentSalt++) {\n const newSalt = saltPrefix | (currentSalt & MASK_96)\n\n const addrInt = addressOfClone3(factoryAddress, newSalt)\n const rarity = BigInt(numberOfLeadingHexZeros(addrInt))\n\n if (rarity > highestRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n }\n\n if (rarity >= minTargetRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n break\n }\n }\n\n return { bestSalt, highestRarity }\n}\n\n// ---------------------------------------------------------------------------\n// Async variant (yields to the event loop between chunks)\n// ---------------------------------------------------------------------------\n\n/** Number of iterations per chunk before yielding back to the event loop. */\nconst CHUNK_SIZE = 5000n\n\n/**\n * Async version of {@link minePoolAddressLocal} that yields to the event loop\n * between chunks of iterations, preventing the browser UI from freezing.\n *\n * @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.\n * @returns The best salt found and its rarity (number of leading hex zeros).\n */\nexport async function minePoolAddressLocalAsync(\n params: MinePoolAddressLocalParams,\n): Promise<MinePoolAddressResult> {\n const { factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params\n\n let bestSalt = salt\n let highestRarity = 0n\n const maxSalt = salt + loops\n\n const saltPrefix =\n params.version === 'v3'\n ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine)\n : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine)\n\n let currentSalt = salt\n while (currentSalt < maxSalt) {\n const chunkEnd = currentSalt + CHUNK_SIZE < maxSalt ? currentSalt + CHUNK_SIZE : maxSalt\n let done = false\n\n for (; currentSalt < chunkEnd; currentSalt++) {\n const newSalt = saltPrefix | (currentSalt & MASK_96)\n const addrInt = addressOfClone3(factoryAddress, newSalt)\n const rarity = BigInt(numberOfLeadingHexZeros(addrInt))\n\n if (rarity > highestRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n }\n\n if (rarity >= minTargetRarity) {\n highestRarity = rarity\n bestSalt = currentSalt\n done = true\n break\n }\n }\n\n if (done) break\n\n // Yield to the event loop so the UI stays responsive\n await new Promise<void>((resolve) => setTimeout(resolve, 0))\n }\n\n return { bestSalt, highestRarity }\n}\n","/**\n * Premia read functions for the Panoptic v2 SDK.\n * @module v2/reads/premia\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta, Position, TokenIdLeg } from '../types'\nimport { decodePosition, decodeTickSpacing } from '../utils/option-encoding-v2'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\n\n/**\n * Premia data for an account.\n */\nexport interface AccountPremia {\n /** Total short premium owed to the account for token 0 */\n shortPremium0: bigint\n /** Total short premium owed to the account for token 1 */\n shortPremium1: bigint\n /** Total long premium owed by the account for token 0 */\n longPremium0: bigint\n /** Total long premium owed by the account for token 1 */\n longPremium1: bigint\n /** Whether pending (unsettled) premium was included */\n includePendingPremium: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getAccountPremia.\n */\nexport interface GetAccountPremiaParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds held by the account */\n tokenIds: bigint[]\n /** Whether to include pending (unsettled) premium (default: true) */\n includePendingPremium?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get premia totals for an account.\n *\n * Returns the total short and long premium across all positions.\n * Short premium is owed TO the account (earned from selling options).\n * Long premium is owed BY the account (paid for buying options).\n *\n * @param params - The parameters\n * @returns Premia totals with block metadata\n *\n * @example\n * ```typescript\n * const premia = await getAccountPremia({\n * client,\n * poolAddress,\n * account,\n * tokenIds: [tokenId1, tokenId2],\n * includePendingPremium: true,\n * })\n *\n * console.log('Short premium earned:', premia.shortPremium0, premia.shortPremium1)\n * console.log('Long premium owed:', premia.longPremium0, premia.longPremium1)\n * ```\n */\nexport async function getAccountPremia(params: GetAccountPremiaParams): Promise<AccountPremia> {\n const {\n client,\n poolAddress,\n account,\n tokenIds,\n includePendingPremium = true,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Handle empty position list\n if (tokenIds.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlockNumber }))\n return {\n shortPremium0: 0n,\n shortPremium1: 0n,\n longPremium0: 0n,\n longPremium1: 0n,\n includePendingPremium,\n _meta,\n }\n }\n\n const [[shortPremiumPacked, longPremiumPacked], _meta] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, includePendingPremium, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Decode LeftRightUnsigned values (right = token0, left = token1)\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n return {\n shortPremium0: shortPremium.right,\n shortPremium1: shortPremium.left,\n longPremium0: longPremium.right,\n longPremium1: longPremium.left,\n includePendingPremium,\n _meta,\n }\n}\n\n/**\n * Position with premia data.\n */\nexport interface PositionWithPremia extends Position {\n // Position already has all fields from the base Position interface\n}\n\n/**\n * Result from getPositionsWithPremia.\n */\nexport interface PositionsWithPremiaResult {\n /** Positions with full data */\n positions: PositionWithPremia[]\n /** Total short premium owed to the account for token 0 */\n shortPremium0: bigint\n /** Total short premium owed to the account for token 1 */\n shortPremium1: bigint\n /** Total long premium owed by the account for token 0 */\n longPremium0: bigint\n /** Total long premium owed by the account for token 1 */\n longPremium1: bigint\n /** Whether pending (unsettled) premium was included */\n includePendingPremium: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPositionsWithPremia.\n */\nexport interface GetPositionsWithPremiaParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds held by the account */\n tokenIds: bigint[]\n /** Whether to include pending (unsettled) premium (default: true) */\n includePendingPremium?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get positions with per-position premia data.\n *\n * Uses multicall to batch individual getFullPositionsData calls\n * for each position, giving us per-position premia in a single RPC request.\n *\n * @param params - The parameters\n * @returns Positions with premia and totals with block metadata\n *\n * @example\n * ```typescript\n * const result = await getPositionsWithPremia({\n * client,\n * poolAddress,\n * account,\n * tokenIds: [tokenId1, tokenId2],\n * })\n *\n * for (const position of result.positions) {\n * console.log('Position:', position.tokenId)\n * console.log('Premia:', position.premiaOwed0, position.premiaOwed1)\n * }\n * console.log('Total short premium:', result.shortPremium0, result.shortPremium1)\n * ```\n */\nexport async function getPositionsWithPremia(\n params: GetPositionsWithPremiaParams,\n): Promise<PositionsWithPremiaResult> {\n const {\n client,\n poolAddress,\n account,\n tokenIds,\n includePendingPremium = true,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Handle empty position list\n if (tokenIds.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlockNumber }))\n return {\n positions: [],\n shortPremium0: 0n,\n shortPremium1: 0n,\n longPremium0: 0n,\n longPremium1: 0n,\n includePendingPremium,\n _meta,\n }\n }\n\n // Build multicall contracts - one getFullPositionsData call per tokenId\n // This gives us per-position premia\n const contracts = tokenIds.map((tokenId) => ({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData' as const,\n args: [account, includePendingPremium, [tokenId]] as const,\n }))\n\n // Execute multicall and get block metadata\n const [multicallResults, _meta] = await Promise.all([\n client.multicall({\n contracts,\n blockNumber: targetBlockNumber,\n allowFailure: true,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // Build positions and accumulate totals\n const positions: PositionWithPremia[] = []\n let totalShortPremium0 = 0n\n let totalShortPremium1 = 0n\n let totalLongPremium0 = 0n\n let totalLongPremium1 = 0n\n\n for (let i = 0; i < tokenIds.length; i++) {\n const tokenId = tokenIds[i]\n const result = multicallResults[i]\n\n // Skip failed calls\n if (result.status !== 'success') {\n continue\n }\n\n const [shortPremiumPacked, longPremiumPacked, balances] = result.result\n\n // Decode per-position premia\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n // Accumulate totals\n totalShortPremium0 += shortPremium.right\n totalShortPremium1 += shortPremium.left\n totalLongPremium0 += longPremium.right\n totalLongPremium1 += longPremium.left\n\n // Get balance data (should be single element array)\n const balanceData = balances[0]\n if (balanceData === undefined) {\n continue\n }\n\n // Decode the PositionBalance\n const positionSize = balanceData & ((1n << 128n) - 1n)\n\n // Skip positions with zero size\n if (positionSize === 0n) {\n continue\n }\n\n const poolUtilization0 = (balanceData >> 128n) & 0xffffn\n const poolUtilization1 = (balanceData >> 144n) & 0xffffn\n\n // tickAtMint is int24 at bits 160-183\n let tickAtMint = (balanceData >> 160n) & 0xffffffn\n if (tickAtMint > 0x7fffffn) {\n tickAtMint = tickAtMint - 0x1000000n\n }\n\n const timestampAtMint = (balanceData >> 184n) & 0xffffffffn\n const blockAtMint = (balanceData >> 216n) & ((1n << 39n) - 1n)\n const swapAtMint = balanceData >> 255n === 1n\n\n // Decode the tokenId to get legs\n const decoded = decodePosition(tokenId)\n const tickSpacing = decodeTickSpacing(tokenId)\n\n // Convert decoded legs to TokenIdLeg format\n const legs: TokenIdLeg[] = decoded.legs.map((leg) => {\n const width = leg.width\n const strike = leg.strike\n const tickLower = strike - (width * tickSpacing) / 2n\n const tickUpper = strike + (width * tickSpacing) / 2n\n\n return {\n index: BigInt(leg.index),\n asset: leg.asset,\n optionRatio: leg.optionRatio,\n isLong: leg.isLong === 1n,\n tokenType: leg.tokenType,\n riskPartner: leg.riskPartner,\n strike,\n width,\n tickLower,\n tickUpper,\n }\n })\n\n // Calculate net premia for this position\n // Positive = position has earned premium (short), Negative = position owes premium (long)\n const premiaOwed0 = shortPremium.right - longPremium.right\n const premiaOwed1 = shortPremium.left - longPremium.left\n\n positions.push({\n tokenId,\n positionSize,\n owner: account,\n poolAddress,\n legs,\n poolUtilization0AtMint: poolUtilization0,\n poolUtilization1AtMint: poolUtilization1,\n tickAtMint,\n timestampAtMint,\n blockNumberAtMint: blockAtMint,\n swapAtMint,\n premiaOwed0,\n premiaOwed1,\n assetIndex: legs.length > 0 ? legs[0].asset : 0n,\n _meta,\n })\n }\n\n return {\n positions,\n shortPremium0: totalShortPremium0,\n shortPremium1: totalShortPremium1,\n longPremium0: totalLongPremium0,\n longPremium1: totalLongPremium1,\n includePendingPremium,\n _meta,\n }\n}\n","/**\n * Collateral estimation functions for the Panoptic v2 SDK.\n *\n * These functions require the PanopticQuery contract which provides\n * on-chain calculation capabilities for collateral requirements.\n *\n * @module v2/reads/collateralEstimate\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError } from '../errors'\nimport { sqrtPriceX96ToTick, tickToSqrtPriceX96 } from '../formatters/tick'\nimport { type TokenFlow, simulateWithTokenFlow } from '../simulations/tokenFlow'\nimport type { StorageAdapter } from '../storage'\nimport { getTrackedPositionIds } from '../sync/getTrackedPositionIds'\nimport { addLegToTokenId, countLegs, decodeAllLegs } from '../tokenId/encoding'\nimport type { BlockMeta } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\n\n/**\n * Max int24 (2^23 - 1), used as the per-position `effectiveLiquidityLimit` (the\n * 3rd element of the dispatch tickAndSpreadLimits triplet). Passing this lets the\n * contract clamp to its real on-chain `maxSpread()` ceiling, matching the live\n * trade. Passing 0 instead forces the limit to 0, so any long-leg removal reverts\n * with EffectiveLiquidityAboveThreshold and ITM/size measurements silently\n * collapse (see PanopticPool._mintInSFPMAndUpdateCollateral / _checkLiquiditySpread).\n */\nconst MAX_EFFECTIVE_LIQUIDITY_LIMIT = 8388607\n\n/**\n * Collateral estimate result.\n */\nexport interface CollateralEstimate {\n /** Required collateral for token 0 */\n required0: bigint\n /** Required collateral for token 1 */\n required1: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for estimateCollateralRequired.\n */\nexport interface EstimateCollateralRequiredParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to estimate collateral for */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Optional: Tick to calculate collateral at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Maximum value of a Solidity `uint64`. `PanopticQuery.getRequiredBase` computes\n * the requirement for a synthetic position sized at `type(uint64).max`, so the\n * returned value must be scaled down to the caller's actual `positionSize`.\n */\nconst MAX_UINT64 = 2n ** 64n - 1n\n\n/**\n * `getRequiredBase` returns `type(uint128).max` as an error sentinel (invalid\n * tokenId or reverting `getMargin`). Detect it so we don't scale a garbage value.\n */\nexport const REQUIRED_BASE_ERROR_SENTINEL = 2n ** 128n - 1n\n\n/**\n * Estimate the collateral required to open a position.\n *\n * Note: This function uses PanopticQuery.getRequiredBase for estimation, which\n * computes the requirement at `type(uint64).max` size and 0% utilization. Since\n * the requirement is linear in size, the raw result is scaled by\n * `positionSize / type(uint64).max` to yield the requirement for the requested\n * size. Returns collateral requirement in terms of token0.\n *\n * @param params - The parameters\n * @returns Estimated collateral requirements with block metadata\n */\nexport async function estimateCollateralRequired(\n params: EstimateCollateralRequiredParams,\n): Promise<CollateralEstimate> {\n const { client, poolAddress, tokenId, positionSize, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Get current tick if not provided\n let effectiveTick: bigint\n if (atTick !== undefined) {\n effectiveTick = atTick\n } else {\n const currentTickResult = await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n // Bridge type from panopticPoolV2Abi (number | bigint) to bigint\n effectiveTick = BigInt(currentTickResult)\n }\n\n const [required0, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getRequiredBase',\n args: [poolAddress, tokenId, Number(effectiveTick)],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // getRequiredBase computes the requirement at type(uint64).max size. The\n // requirement is linear in size, so scale down to the requested positionSize.\n // Guard against the error sentinel (type(uint128).max) so we don't scale it.\n const scaled0 =\n required0 >= REQUIRED_BASE_ERROR_SENTINEL ? required0 : (required0 * positionSize) / MAX_UINT64\n\n // PanopticQuery.getRequiredBase returns collateral requirement in terms of token0\n // For token1 requirement, would need additional conversion or separate call\n return {\n required0: scaled0,\n required1: 0n, // Not available from getRequiredBase (token0-denominated only)\n _meta,\n }\n}\n\n/**\n * Max position size result.\n */\nexport interface MaxPositionSize {\n /** Refined maximum position size at current market conditions */\n maxSize: bigint\n /** Maximum position size at 0% utilization (best case / upper bound) */\n maxSizeAtMinUtil: bigint\n /** Maximum position size at 100% utilization (worst case / lower bound) */\n maxSizeAtMaxUtil: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getMaxPositionSize.\n */\nexport interface GetMaxPositionSizeParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to check max size for */\n tokenId: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /**\n * Existing position IDs held by the account.\n * - If provided, uses these directly\n * - If not provided but storage + chainId given, fetches from getTrackedPositionIds()\n * - If neither provided, assumes empty array (new account with no positions)\n */\n existingPositionIds?: bigint[]\n /** Storage adapter for auto-fetching positions (requires chainId) */\n storage?: StorageAdapter\n /** Chain ID (required if using storage) */\n chainId?: bigint\n /** Whether to refine with dispatch simulation (default: true) */\n refine?: boolean\n /** Precision for binary search as percentage (default: 1 = 1%) */\n precisionPct?: number\n /** Whether to swap tokens at mint (affects collateral requirements, default: false) */\n swapAtMint?: boolean\n /**\n * Whether the solvency simulation may count accrued premia as collateral. MUST match the\n * mint (which uses `false`) — passing `true` credits premia the mint won't, so the search\n * returns a size larger than the account can actually mint. Defaults to `false`.\n */\n usePremiaAsCollateral?: boolean\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get the maximum position size an account can open given their current collateral.\n *\n * Uses PanopticQuery.getMaxPositionSizeBounds to get bounds at 0% and 100% utilization,\n * then refines with dispatch simulations to find the exact max at current conditions.\n *\n * @param params - The parameters\n * @returns Maximum position size with bounds and block metadata\n */\nexport async function getMaxPositionSize(\n params: GetMaxPositionSizeParams,\n): Promise<MaxPositionSize> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n queryAddress,\n existingPositionIds,\n storage,\n chainId,\n refine = true,\n precisionPct = 1,\n swapAtMint = false,\n usePremiaAsCollateral = false,\n blockNumber,\n } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Get existing position IDs\n let positionIds: bigint[]\n if (existingPositionIds !== undefined) {\n // Use explicitly provided position IDs\n positionIds = existingPositionIds\n } else if (storage && chainId !== undefined) {\n // Fetch from local cache via getTrackedPositionIds\n positionIds = await getTrackedPositionIds({\n chainId,\n poolAddress,\n account,\n storage,\n })\n } else {\n // Assume new account with no existing positions\n positionIds = []\n }\n // Get bounds and block meta in parallel\n const [boundsResult, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getMaxPositionSizeBounds',\n args: [poolAddress, positionIds, account, tokenId],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [maxSizeAtMinUtil, maxSizeAtMaxUtil] = boundsResult\n\n // If bounds are equal or very close, or refinement disabled, return conservative estimate\n const precisionDivisor = BigInt(Math.floor(100 / precisionPct))\n if (\n !refine ||\n maxSizeAtMinUtil === maxSizeAtMaxUtil ||\n maxSizeAtMinUtil - maxSizeAtMaxUtil <= maxSizeAtMaxUtil / precisionDivisor\n ) {\n return {\n maxSize: maxSizeAtMaxUtil,\n maxSizeAtMinUtil,\n maxSizeAtMaxUtil,\n _meta,\n }\n }\n\n // Binary search between widened bounds using dispatch simulation\n // Widen by 2x in each direction to account for swapAtMint price impact\n const maxSize = await binarySearchMaxSize({\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds: positionIds,\n low: maxSizeAtMaxUtil / 2n,\n high: maxSizeAtMinUtil * 2n,\n precisionDivisor,\n swapAtMint,\n usePremiaAsCollateral,\n })\n\n return {\n maxSize,\n maxSizeAtMinUtil,\n maxSizeAtMaxUtil,\n _meta,\n }\n}\n\n/**\n * Parallel search to find max position size using dispatch simulation.\n * Tests 5 points per round (sextiles), narrowing the range by 6x each iteration.\n */\nasync function binarySearchMaxSize(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n low: bigint\n high: bigint\n precisionDivisor: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}): Promise<bigint> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n precisionDivisor,\n swapAtMint,\n usePremiaAsCollateral,\n } = params\n let { low, high } = params\n\n const trySize = (positionSize: bigint) =>\n tryDispatchSimulation({\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n positionSize,\n swapAtMint,\n usePremiaAsCollateral,\n })\n\n while (high - low > 1n && high - low > low / precisionDivisor) {\n const range = high - low\n const p1 = low + range / 6n\n const p2 = low + (range * 2n) / 6n\n const p3 = low + (range * 3n) / 6n\n const p4 = low + (range * 4n) / 6n\n const p5 = low + (range * 5n) / 6n\n\n const [s1, s2, s3, s4, s5] = await Promise.all([\n trySize(p1),\n trySize(p2),\n trySize(p3),\n trySize(p4),\n trySize(p5),\n ])\n\n if (s5) {\n low = p5\n } else if (s4) {\n low = p4\n high = p5\n } else if (s3) {\n low = p3\n high = p4\n } else if (s2) {\n low = p2\n high = p3\n } else if (s1) {\n low = p1\n high = p2\n } else {\n high = p1\n }\n }\n\n return low\n}\n\n/**\n * Try to simulate opening a position with the given size.\n */\nasync function tryDispatchSimulation(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n tokenId: bigint\n existingPositionIds: bigint[]\n positionSize: bigint\n swapAtMint: boolean\n usePremiaAsCollateral: boolean\n}): Promise<boolean> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n existingPositionIds,\n positionSize,\n swapAtMint,\n usePremiaAsCollateral,\n } = params\n\n try {\n // Build final position list (existing + new position)\n const finalPositionIdList = [...existingPositionIds, tokenId]\n\n // Build tick limits based on swapAtMint flag:\n // - swapAtMint=true: descending order (high, low) triggers SFPM swap\n // - swapAtMint=false: ascending order (low, high) no swap\n //\n // The third element is the per-position `effectiveLiquidityLimit`; see the\n // MAX_EFFECTIVE_LIQUIDITY_LIMIT definition for why 0 must not be used here.\n const tickLimits: readonly [number, number, number] = swapAtMint\n ? [887272, -887272, MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n : [-887272, 887272, MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n\n // Encode dispatch call\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId],\n finalPositionIdList,\n [positionSize],\n [tickLimits],\n usePremiaAsCollateral, // must match the mint (default false) so the max is mintable\n 0n, // builderCode\n ],\n })\n\n // Use PanopticPool.multicall to simulate\n await client.simulateContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'multicall',\n args: [[callData]],\n account,\n })\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Parameters for getRequiredCreditForITM.\n */\nexport interface GetRequiredCreditForITMParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenId to check */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Existing position IDs held by the account (defaults to empty) */\n existingPositionIds?: bigint[]\n /**\n * Whether the position will be minted with a token swap (Zap). Controls the\n * dispatch tickLimit direction and therefore what the measured flow looks like:\n * - `true` (default): descending tickLimits → SFPM swap → flow consolidated to\n * the single token the mint would swap into.\n * - `false`: ascending tickLimits → no swap → the true two-sided flow (both\n * tokens), matching a cover-at-mint open.\n * Must match the swapAtMint used at mint for the measurement to be meaningful.\n */\n swapAtMint?: boolean\n /** Optional block number for simulation */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Result for getRequiredCreditForITM.\n */\nexport interface RequiredCreditForITM {\n /**\n * Required credit in token0 to neutralize ITM exposure.\n * Positive = credit needed (deposit), negative = loan proceeds (receive).\n */\n creditAmount0: bigint\n /**\n * Required credit in token1 to neutralize ITM exposure.\n * Positive = credit needed (deposit), negative = loan proceeds (receive).\n */\n creditAmount1: bigint\n /** The raw token flow from simulation */\n tokenFlow: TokenFlow\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Get the required credit (or loan) amount for an ITM position.\n *\n * Simulates opening the position with swapAtMint=true (descending tickLimits)\n * to get single-sided token flow. The token flow represents the ITM amount\n * that would need to be neutralized with a credit (or loan if negative).\n *\n * @param params - The parameters\n * @returns Required credit amounts with token flow and block metadata\n * @throws PanopticError - If simulation fails\n *\n * @example\n * ```typescript\n * const result = await getRequiredCreditForITM({\n * client,\n * poolAddress,\n * account,\n * tokenId,\n * positionSize: 1n,\n * })\n *\n * if (result.creditAmount0 > 0n) {\n * console.log('Need credit of', result.creditAmount0, 'token0')\n * } else if (result.creditAmount0 < 0n) {\n * console.log('Position yields loan of', -result.creditAmount0, 'token0')\n * }\n * ```\n */\nexport async function getRequiredCreditForITM(\n params: GetRequiredCreditForITMParams,\n): Promise<RequiredCreditForITM> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n positionSize,\n existingPositionIds = [],\n swapAtMint = true,\n blockNumber,\n } = params\n\n // Same-block guarantee: if the caller pins both a blockNumber and a pre-fetched\n // _meta, they must agree — otherwise the simulation (targetBlockNumber) and the\n // returned metadata would describe different blocks.\n if (\n blockNumber !== undefined &&\n params._meta !== undefined &&\n params._meta.blockNumber !== blockNumber\n ) {\n throw new PanopticError(\n 'getRequiredCreditForITM: blockNumber and _meta.blockNumber disagree; cannot guarantee same-block consistency',\n )\n }\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Build final position list (existing + new position)\n const finalPositionIdList = [...existingPositionIds, tokenId]\n\n // Encode dispatch call. The tickLimit direction encodes swapAtMint:\n // - swapAtMint=true (Zap): descending (MAX_TICK > MIN_TICK) triggers the SFPM swap,\n // consolidating the flow into the single token the mint swaps into.\n // - swapAtMint=false (Cover): ascending (MIN_TICK < MAX_TICK) does no swap, giving the\n // true two-sided flow. This must match the mint's swapAtMint for the measured flow to\n // reflect what actually happens at open.\n // The 3rd element is the per-position effectiveLiquidityLimit: use the max so the contract\n // clamps to its real maxSpread() ceiling (matching the live trade). Passing 0 here collapses\n // ITM measurement for positions with a long-leg removal (see MAX_EFFECTIVE_LIQUIDITY_LIMIT).\n const tickTriplet: readonly [number, number, number] = swapAtMint\n ? [Number(MAX_TICK), Number(MIN_TICK), MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n : [Number(MIN_TICK), Number(MAX_TICK), MAX_EFFECTIVE_LIQUIDITY_LIMIT]\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId], // positionIdList: positions being minted\n finalPositionIdList,\n [positionSize],\n [tickTriplet],\n false, // usePremiaAsCollateral\n 0n, // builderCode\n ],\n })\n\n // Simulate with token flow measurement and get block meta in parallel\n const [result, _meta] = await Promise.all([\n simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n if (!result.success || !result.tokenFlow) {\n throw new PanopticError(result.error ?? 'Token flow simulation failed')\n }\n\n // The token flow deltas represent the ITM amount:\n // - Negative delta = user deposits (credit needed)\n // - Positive delta = user receives (loan proceeds)\n // We invert the sign so positive = credit needed, negative = loan\n return {\n creditAmount0: -result.tokenFlow.delta0,\n creditAmount1: -result.tokenFlow.delta1,\n tokenFlow: result.tokenFlow,\n _meta,\n }\n}\n\n/**\n * Parameters for getItmAmounts.\n */\nexport interface GetItmAmountsParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticQuery address (holds the getItmAmounts view) */\n queryAddress: Address\n /** PanopticPool address the position would be minted on */\n poolAddress: Address\n /** The option position (may already include width=0 neutralizing legs) */\n tokenId: bigint\n /** Position size (number of contracts) */\n positionSize: bigint\n /** Optional block number */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getItmAmounts: the net in-the-money amounts a mint of `tokenId` would\n * accumulate in the SFPM before the mint-time netting swap.\n */\nexport interface ItmAmounts {\n /** Net ITM amount of token0 (SFPM sign convention). */\n itm0: bigint\n /** Net ITM amount of token1. */\n itm1: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Read the net `itmAmounts` a mint of `tokenId` would produce, via\n * `PanopticQuery.getItmAmounts`. This is the swap-independent, per-leg-linear\n * projection that drives the SFPM's mint-time netting swap: the swap only fires\n * when `itmAmounts != 0`. Sizing width=0 legs so the combined tokenId returns\n * (~0, ~0) here makes the mint swap dust — regardless of Zap vs cover.\n *\n * @param params - The parameters\n * @returns The net itm0/itm1 with block metadata\n */\nexport async function getItmAmounts(params: GetItmAmountsParams): Promise<ItmAmounts> {\n const { client, queryAddress, poolAddress, tokenId, positionSize, blockNumber } = params\n\n // Same-block guarantee (see getRequiredCreditForITM): a pinned blockNumber and a\n // pre-fetched _meta must describe the same block.\n if (\n blockNumber !== undefined &&\n params._meta !== undefined &&\n params._meta.blockNumber !== blockNumber\n ) {\n throw new PanopticError(\n 'getItmAmounts: blockNumber and _meta.blockNumber disagree; cannot guarantee same-block consistency',\n )\n }\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getItmAmounts',\n args: [poolAddress, tokenId, positionSize],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [itm0, itm1] = result as readonly [bigint, bigint]\n return { itm0, itm1, _meta }\n}\n\n/**\n * Dust threshold (token1 value units) below which an itm amount is treated as\n * zero — negligible token flow not worth a neutralizing leg. token0 amounts are\n * converted to token1 value at the current tick before comparison so a tiny\n * high-decimal amount can't masquerade as real flow.\n */\nconst FLOW_NEUTRAL_DUST_THRESHOLD = 1000n\n\nconst Q192 = 1n << 192n\nconst POOL_ID_MASK = (1n << 64n) - 1n\n\n/**\n * Floor integer square root for bigints (Newton's method). Exact for all\n * non-negative inputs — no float precision loss for values above 2^53.\n */\nfunction isqrt(value: bigint): bigint {\n if (value < 0n) throw new PanopticError('isqrt of negative number')\n if (value < 2n) return value\n let x = value\n let y = (x + 1n) >> 1n\n while (y < x) {\n x = y\n y = (x + value / x) >> 1n\n }\n return x\n}\n\n/**\n * Solve a single width=0 neutralizing leg sized to offset a token's signed itm.\n *\n * The leg moves `tokenIndex`'s token (`tokenType = tokenIndex`) and is denominated\n * in the opposite asset (`asset = 1 - tokenIndex`) so `asset ≠ tokenType` and the\n * notional scales continuously by strike: `notional ≈ positionSize · 1.0001^signed`.\n * `signedAmount` is the itm to cancel (the leg's itm contribution is `-signedAmount`):\n * positive itm ⇒ a short LOAN leg (isLong=0), negative itm ⇒ a long CREDIT leg (isLong=1).\n *\n * Width=0 legs never mint Uniswap liquidity (see SFPM `_createPositionInAMM`), so their\n * strike is NOT grid-constrained — we use full 1-tick granularity for the tightest sizing.\n * The closed form `positionSize·1.0001^strike` matches the contract's width-2-chunk\n * `getAmountsMoved` to within ~dust, so no correction loop is needed.\n * Throws `PanopticError` if the required strike leaves the valid (exclusive) tick range.\n */\nfunction buildNeutralLeg(\n tokenIndex: 0n | 1n,\n signedAmount: bigint,\n positionSize: bigint,\n): NeutralLeg {\n const absAmount = signedAmount < 0n ? -signedAmount : signedAmount\n const legAsset = tokenIndex === 0n ? 1n : 0n\n const legIsLong = signedAmount < 0n\n\n // 1.0001^signedStrike = absAmount / positionSize\n // sqrtKrawX96 = sqrt(absAmount / positionSize) · 2^96 = isqrt(absAmount · 2^192 / positionSize)\n const sqrtKrawX96 = isqrt((absAmount * Q192) / positionSize)\n\n let signedTick: bigint\n try {\n signedTick = sqrtPriceX96ToTick(sqrtKrawX96)\n } catch {\n throw new PanopticError(\n 'Cannot create flow-neutral position: neutralizing strike out of bounds',\n )\n }\n\n // TokenId.validate() rejects strike == MIN_TICK/MAX_TICK, so keep strictly inside.\n if (signedTick <= MIN_TICK || signedTick >= MAX_TICK) {\n throw new PanopticError(\n 'Cannot create flow-neutral position: neutralizing strike out of bounds',\n )\n }\n\n // signedStrike = (asset === 0 ? strike : -strike) — invert to recover the encoded\n // strike (mirrors getLegValueWidth0's convention).\n const strike = legAsset === 0n ? signedTick : -signedTick\n\n return {\n strike,\n asset: legAsset,\n tokenType: tokenIndex,\n isCredit: legIsLong,\n }\n}\n\n/**\n * Assemble a tokenId with the neutralizing legs (self-partnered, width=0) placed either\n * BEFORE or AFTER the base legs.\n *\n * The leg at index 0 sets the position's swap frame (the token the Zap sources) and the\n * canonical `positionSize` denomination, so placement is asset-directed:\n * - `prepend=false` (default, e.g. PUTs): base legs keep their indices (option leg stays\n * at index 0); neutral legs are appended at `baseLegCount..`.\n * - `prepend=true` (e.g. CALLs): neutral legs occupy indices `0..k-1` and the base legs\n * shift by `k` (riskPartner remapped: self-partners follow their new index, cross\n * partners +k). This puts the credit leg first so the mint swap is asset-token\n * friendly for a call.\n */\nfunction assembleNeutralTokenId(\n poolId: bigint,\n baseTokenId: bigint,\n neutralLegs: NeutralLeg[],\n prepend: boolean,\n): bigint {\n let out = poolId\n const baseLegs = decodeAllLegs(baseTokenId)\n const k = BigInt(neutralLegs.length)\n const shift = prepend ? k : 0n\n\n if (prepend) {\n neutralLegs.forEach((leg, i) => {\n const index = BigInt(i)\n out = addLegToTokenId(out, {\n index,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: 1n,\n isLong: leg.isCredit ? 1n : 0n,\n riskPartner: index,\n strike: leg.strike,\n width: 0n,\n })\n })\n }\n\n for (const leg of baseLegs) {\n const newIndex = leg.index + shift\n const newRiskPartner = leg.riskPartner === leg.index ? newIndex : leg.riskPartner + shift\n out = addLegToTokenId(out, {\n index: newIndex,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: leg.optionRatio,\n isLong: leg.isLong ? 1n : 0n,\n riskPartner: newRiskPartner,\n strike: leg.strike,\n width: leg.width,\n })\n }\n\n if (!prepend) {\n const base = BigInt(baseLegs.length)\n neutralLegs.forEach((leg, i) => {\n const index = base + BigInt(i)\n out = addLegToTokenId(out, {\n index,\n asset: leg.asset,\n tokenType: leg.tokenType,\n optionRatio: 1n,\n isLong: leg.isCredit ? 1n : 0n,\n riskPartner: index,\n strike: leg.strike,\n width: 0n,\n })\n })\n }\n\n return out\n}\n\n/**\n * Parameters for createFlowNeutralTokenId.\n */\nexport interface CreateFlowNeutralTokenIdParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address the position would be minted on */\n poolAddress: Address\n /** Account address (whose collateral flow the neutralization targets) */\n account: Address\n /** The base tokenId (without neutralizing legs) */\n tokenId: bigint\n /** Position size (number of contracts) — unchanged by this function */\n positionSize: bigint\n /**\n * PanopticQuery address. When provided, the position's true intrinsic (`getItmAmounts`)\n * gates neutralization: an OTM position (no ITM) gets NO leg, even though its realized\n * flow is non-zero from the open commission. Without it, OTM detection falls back to the\n * commission-inclusive realized flow, which spuriously neutralizes the fee.\n */\n queryAddress?: Address\n /** Existing position IDs held by the account (defaults to empty) */\n existingPositionIds?: bigint[]\n /**\n * Whether the position will be minted with a token swap (Zap). Must match the\n * mint: the neutralization targets the NET token flow under this swap mode, so a\n * mismatch would neutralize the wrong quantity. Defaults to `true`.\n */\n swapAtMint?: boolean\n /**\n * Size at which to MEASURE the base flow that sizes the neutralizing leg(s). The leg\n * strikes are position-size-independent (the flow is linear in size), so measuring at a\n * small affordable reference and reusing the result for `positionSize` yields the same\n * legs. Set this below `positionSize` to avoid the un-neutralized base dispatch reverting\n * with NotEnoughTokens at large sizes under Cover (the gross ITM would exceed the\n * account's balance even though the neutralized mint nets ~0). Defaults to `positionSize`;\n * clamped to `positionSize` if larger.\n */\n referenceSize?: bigint\n /** Optional block number (pins base + verify measurements to one block) */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * A single width=0 neutralizing leg emitted by {@link createFlowNeutralTokenId}.\n */\nexport interface NeutralLeg {\n /** The encoded strike of the leg (sign follows the `asset === 0 ? +t : -t` convention). */\n strike: bigint\n /** Asset (0n or 1n) of the leg. Always `1n - tokenType` (asset ≠ tokenType, so it is strike-tunable). */\n asset: bigint\n /** Token type (0n or 1n) — the token this leg neutralizes (its itm slot). */\n tokenType: bigint\n /** true = credit leg (isLong, offsets negative itm), false = loan leg (short, offsets positive itm). */\n isCredit: boolean\n}\n\n/**\n * Result of createFlowNeutralTokenId.\n */\nexport interface FlowNeutralTokenId {\n /**\n * New tokenId with the neutralizing legs appended after the base legs (base legs keep\n * their original indices, so the option leg stays at index 0). Equals the original\n * tokenId when OTM (`neutralLegs` empty).\n */\n tokenId: bigint\n /**\n * Position size to use when opening this tokenId. Always equal to the input\n * `positionSize` — neutralizing legs are sized via their strike, not by\n * rescaling the position.\n */\n positionSize: bigint\n /**\n * The neutralizing legs added, appended after the base legs. 0 entries = OTM/no leg;\n * 1 = the single dominant-token neutralizing leg (single-leg neutralization).\n */\n neutralLegs: NeutralLeg[]\n /** The BASE position's net-flow measurement (what the legs offset). */\n originalCredit: RequiredCreditForITM\n /**\n * The COMBINED (neutralized) position's actual token flow under the mint's swap,\n * from a verify re-measurement. Use this for the Account-Balances display and to\n * gate the mint — its `delta0/delta1` are the residual net transfer (≈ dust).\n */\n neutralizedTokenFlow: TokenFlow\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Create a flow-neutral tokenId by adding width=0 credit/loan leg(s) that zero the\n * position's NET token transfer at mint — the amount the user would otherwise send/receive\n * (and be surprised by at burn).\n *\n * Each leg is sized against the **realized net flow**, measured by\n * {@link getRequiredCreditForITM} under the mint's own `swapAtMint`. Verified on-chain: a\n * width=0 leg's marginal effect on its token's flow is LINEAR and 1:1 with its notional\n * (`positionSize · 1.0001^strike`, matching the contract's `getAmountsMoved`). So sizing the\n * notional to `|net flow|` and solving the strike directly drives the residual to ~dust in\n * ONE shot — no fixed-point loop. (Example: flow 122.08 USDC → strike −228275 → residual\n * −0.032 USDC.)\n *\n * How many legs, keyed on swap mode:\n * - **Zap** (`swapAtMint=true`): the mint swap consolidates the flow into ONE token and a\n * width=0 leg can only move the asset axis afterwards, so we add a single leg on the\n * dominant token; the smaller side is a swap artifact left as dust.\n * - **Cover** (`swapAtMint=false`): no swap, so the flow is genuinely two-sided and each\n * token's flow is independent — we add one leg PER token above dust (up to 2), each\n * sized 1:1 to its own side. This neutralizes both sides of e.g. a two-leg straddle.\n * Each width=0 leg has `asset ≠ tokenType` (strike-tunable):\n * - token0 flow ← width=0 call leg (tokenType0, asset1)\n * - token1 flow ← width=0 put leg (tokenType1, asset0)\n * `creditAmount = −delta`: a positive amount (user would deposit) → a short LOAN leg;\n * negative (user would receive) → a long CREDIT leg. `neutralizedTokenFlow` is a single\n * verify measurement of the combined position under the ACTUAL mint swap mode.\n *\n * Neutral legs (self-partnered, width=0) are placed so index 0 carries the correct swap\n * frame: for a single-leg CALL (option `tokenType === asset`) they are PREPENDED so the\n * credit leg leads and the mint swap is asset-token friendly; for a PUT (and any multi-leg\n * base) they are APPENDED so the option leg stays at index 0. `positionSize` is never\n * modified.\n *\n * @param params - The parameters\n * @returns The flow-neutral tokenId, the neutralizing legs, the base net-flow\n * measurement, and the combined position's residual flow. `neutralLegs` is empty\n * when the position is OTM (input tokenId returned unchanged).\n * @throws PanopticError if positionSize <= 0, base legs + 1 > 4, the current tick\n * is unavailable, or a neutralizing strike falls outside the valid tick range.\n */\nexport async function createFlowNeutralTokenId(\n params: CreateFlowNeutralTokenIdParams,\n): Promise<FlowNeutralTokenId> {\n const {\n client,\n poolAddress,\n account,\n tokenId,\n positionSize,\n existingPositionIds,\n swapAtMint = true,\n referenceSize,\n queryAddress,\n blockNumber,\n } = params\n\n if (positionSize <= 0n) {\n throw new PanopticError('positionSize must be positive to create flow-neutral position')\n }\n\n // Measure the base flow at a (possibly smaller) reference size to keep the un-neutralized\n // dispatch affordable; strikes are size-independent so the legs are identical. Verify runs\n // on the neutralized position at the full positionSize (which nets ~0, so it's affordable).\n const measureSize =\n referenceSize !== undefined && referenceSize > 0n && referenceSize < positionSize\n ? referenceSize\n : positionSize\n\n const legCount = countLegs(tokenId)\n if (legCount >= 4n) {\n throw new PanopticError('Cannot append neutralizing leg: tokenId already has 4 legs')\n }\n\n const poolId = tokenId & POOL_ID_MASK\n\n // Leg-0 placement of the neutral leg is asset-directed (it sets the mint's swap frame /\n // positionSize denomination). For a single-leg CALL (option leg's tokenType === asset)\n // the credit leg must lead so the swap sources the asset token; for a PUT the option leg\n // stays at index 0 and the neutral leg is appended. Multi-leg bases always append (their\n // neutralization is handled in a separate commit).\n const baseLegs = decodeAllLegs(tokenId)\n const prependNeutral = baseLegs.length === 1 && baseLegs[0].tokenType === baseLegs[0].asset\n\n // Size the neutral leg against the REALIZED (post-swap) net flow, measured by dispatch\n // under the mint's own `swapAtMint`. Empirically (verified on-chain against a live pool)\n // the leg's marginal effect on this flow is LINEAR and 1:1 with its notional: a width=0\n // leg of notional N (positionSize·1.0001^strike) shifts the measured net flow by exactly\n // N in that token. So sizing notional = |base net flow| and computing the strike directly\n // drives the residual to ~dust in ONE shot — no fixed-point loop.\n // creditAmount = −delta: positive = user deposits, negative = user receives.\n const credit = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId,\n positionSize: measureSize,\n existingPositionIds,\n swapAtMint,\n blockNumber,\n _meta: params._meta,\n })\n\n const tickBefore = credit.tokenFlow.tickBefore\n if (tickBefore === null) {\n throw new PanopticError('Cannot create flow-neutral position: current tick unavailable')\n }\n // Value-aware compare: convert a token0 amount into token1 at the current price\n // (P = 1.0001^tick = sqrtP^2 / 2^192) so token0/token1 flows compare in one unit.\n const sqrtPX96 = tickToSqrtPriceX96(tickBefore)\n const valueAbs = (index: 0n | 1n, amount: bigint): bigint => {\n const abs = amount < 0n ? -amount : amount\n return index === 0n ? (abs * sqrtPX96 * sqrtPX96) / Q192 : abs\n }\n const flowFor = (index: 0n | 1n): bigint =>\n index === 0n ? credit.creditAmount0 : credit.creditAmount1\n\n // OTM gate on true INTRINSIC (getItmAmounts), not the realized flow. The realized\n // getAssetsOf flow includes the open commission, so an OTM position shows non-zero flow\n // (a fee, not ITM) — neutralizing it builds a spurious leg and moves tokens the mint\n // wouldn't. `getItmAmounts` is 0 for an OTM position, so this correctly skips it. Falls\n // back to the realized-flow dust check when no queryAddress is supplied.\n if (queryAddress !== undefined) {\n const itm = await getItmAmounts({\n client,\n queryAddress,\n poolAddress,\n tokenId,\n positionSize: measureSize,\n blockNumber: blockNumber ?? credit._meta.blockNumber,\n _meta: credit._meta,\n })\n if (\n valueAbs(0n, itm.itm0) <= FLOW_NEUTRAL_DUST_THRESHOLD &&\n valueAbs(1n, itm.itm1) <= FLOW_NEUTRAL_DUST_THRESHOLD\n ) {\n return {\n tokenId,\n positionSize,\n neutralLegs: [],\n originalCredit: credit,\n neutralizedTokenFlow: credit.tokenFlow,\n _meta: credit._meta,\n }\n }\n }\n\n // OTM — no net flow to neutralize (both sides negligible). This guard only avoids\n // building a leg with an out-of-bounds (log of ~0) strike; it is NOT a convergence\n // threshold.\n if (\n valueAbs(0n, credit.creditAmount0) <= FLOW_NEUTRAL_DUST_THRESHOLD &&\n valueAbs(1n, credit.creditAmount1) <= FLOW_NEUTRAL_DUST_THRESHOLD\n ) {\n return {\n tokenId,\n positionSize,\n neutralLegs: [],\n originalCredit: credit,\n neutralizedTokenFlow: credit.tokenFlow,\n _meta: credit._meta,\n }\n }\n\n // Which token(s) get a neutralizing leg:\n // - Zap (swapAtMint=true): the mint swap consolidates the flow to ONE token, and a\n // width=0 leg can only move the asset axis afterwards, so we neutralize just the\n // SINGLE dominant token; the smaller side is a swap artifact left as dust.\n // - Cover (swapAtMint=false): there is NO swap, so the flow is genuinely two-sided and\n // each token's flow is independent — neutralize EACH side above dust (up to 2 legs),\n // every leg sized 1:1 to its own token's net flow.\n const indices: (0n | 1n)[] = swapAtMint\n ? [valueAbs(0n, credit.creditAmount0) >= valueAbs(1n, credit.creditAmount1) ? 0n : 1n]\n : ([0n, 1n] as const).filter((i) => valueAbs(i, flowFor(i)) > FLOW_NEUTRAL_DUST_THRESHOLD)\n\n if (legCount + BigInt(indices.length) > 4n) {\n throw new PanopticError(\n `Cannot add ${indices.length} neutralizing leg(s): tokenId would exceed 4 legs`,\n )\n }\n\n // Legs sized from the flow measured at `measureSize`; strikes are size-independent so\n // they hold at the full positionSize.\n const neutralLegs = indices.map((i) => buildNeutralLeg(i, flowFor(i), measureSize))\n const combined = assembleNeutralTokenId(poolId, tokenId, neutralLegs, prependNeutral)\n\n // Verify/display: measure the COMBINED (neutralized) position's residual flow under the\n // ACTUAL mint swap mode at the FULL positionSize so the Account-Balances display and mint\n // gating reflect what the user will experience. The neutralized position nets ~0, so this\n // is affordable even when the un-neutralized base at full size would not be. If it still\n // reverts (edge: sits exactly at the solvency limit), fall back to the reference-size\n // measurement so we return a valid tokenId rather than throwing.\n const pinnedBlock = blockNumber ?? credit._meta.blockNumber\n let residual: RequiredCreditForITM\n try {\n residual = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId: combined,\n positionSize,\n existingPositionIds,\n swapAtMint,\n blockNumber: pinnedBlock,\n _meta: credit._meta,\n })\n } catch {\n residual = await getRequiredCreditForITM({\n client,\n poolAddress,\n account,\n tokenId: combined,\n positionSize: measureSize,\n existingPositionIds,\n swapAtMint,\n blockNumber: pinnedBlock,\n _meta: credit._meta,\n })\n }\n\n return {\n tokenId: combined,\n positionSize,\n neutralLegs,\n originalCredit: credit,\n neutralizedTokenFlow: residual.tokenFlow,\n _meta: credit._meta,\n }\n}\n\n/**\n * Parameters for getMaxWithdrawable.\n */\nexport interface GetMaxWithdrawableParams {\n /** viem PublicClient */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Position IDs held by the account (required for solvency-checked withdraw) */\n positionIdList: bigint[]\n /** Upper bound for the binary search (e.g. user's total assets in this tracker) */\n totalAssets: bigint\n /** Whether to use premia as collateral (default: false) */\n usePremiaAsCollateral?: boolean\n /** Precision for binary search as percentage (default: 1 = 1%) */\n precisionPct?: number\n}\n\n/**\n * Find the maximum withdrawable amount from a CollateralTracker using binary search.\n *\n * When a user has open positions, the standard `maxWithdraw()` returns 0 because\n * the basic ERC4626 withdraw doesn't check solvency. The overloaded\n * `withdraw(assets, receiver, owner, positionIdList, usePremiaAsCollateral)` does\n * check solvency, so we binary search for the largest amount that doesn't revert.\n *\n * @param params - The parameters\n * @returns Maximum withdrawable amount in underlying asset units\n */\nexport async function getMaxWithdrawable(\n params: GetMaxWithdrawableParams,\n): Promise<{ maxWithdrawable: bigint; _meta: BlockMeta }> {\n const {\n client,\n collateralTrackerAddress,\n account,\n positionIdList,\n totalAssets,\n usePremiaAsCollateral = false,\n precisionPct = 1,\n } = params\n\n const _meta = await getBlockMeta({ client })\n\n if (totalAssets <= 0n || positionIdList.length === 0) {\n // No positions: use the standard maxWithdraw\n const maxWithdraw = await client.readContract({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxWithdraw',\n args: [account],\n })\n return { maxWithdrawable: maxWithdraw, _meta }\n }\n\n const precisionDivisor = BigInt(Math.floor(100 / precisionPct))\n let low = 0n\n let high = totalAssets\n\n while (high - low > 1n && high - low > low / precisionDivisor) {\n const mid = low + (high - low) / 2n\n\n const success = await tryWithdrawSimulation({\n client,\n collateralTrackerAddress,\n account,\n assets: mid,\n positionIdList,\n usePremiaAsCollateral,\n })\n\n if (success) {\n low = mid\n } else {\n high = mid\n }\n }\n\n return { maxWithdrawable: low, _meta }\n}\n\n/**\n * Parameters for getMaxRedeem.\n */\nexport interface GetMaxRedeemParams {\n /** viem PublicClient */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Read the maximum number of shares an account can redeem from a CollateralTracker.\n *\n * This is the ERC4626 `maxRedeem(owner)`, i.e. `min(availableShares, balanceOf(owner))`,\n * and returns 0 when the account has open positions (legs). Redeeming exactly this many\n * shares burns the account's full (available) share balance, so a MAX withdraw leaves no\n * rounding dust — unlike an assets-based `withdraw`, which round-trips shares↔assets.\n *\n * @param params - The parameters\n * @returns Maximum redeemable shares with block metadata\n */\nexport async function getMaxRedeem(\n params: GetMaxRedeemParams,\n): Promise<{ maxRedeem: bigint; _meta: BlockMeta }> {\n const { client, collateralTrackerAddress, account, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [maxRedeem, _meta] = await Promise.all([\n client.readContract({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxRedeem',\n args: [account],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { maxRedeem, _meta }\n}\n\n/**\n * Try to simulate a solvency-checked withdraw with the given amount.\n */\nasync function tryWithdrawSimulation(params: {\n client: PublicClient\n collateralTrackerAddress: Address\n account: Address\n assets: bigint\n positionIdList: bigint[]\n usePremiaAsCollateral: boolean\n}): Promise<boolean> {\n const {\n client,\n collateralTrackerAddress,\n account,\n assets,\n positionIdList,\n usePremiaAsCollateral,\n } = params\n\n try {\n await client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'withdraw',\n args: [assets, account, account, positionIdList, usePremiaAsCollateral],\n account,\n })\n return true\n } catch {\n return false\n }\n}\n","/**\n * ERC4626 vault preview functions for the Panoptic v2 SDK.\n *\n * The CollateralTracker contract implements ERC4626, providing standard\n * vault functionality for depositing/withdrawing collateral.\n *\n * @module v2/reads/erc4626\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Parameters for ERC4626 preview functions.\n */\nexport interface ERC4626PreviewParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Which token's collateral tracker to query (0 or 1) */\n tokenIndex: 0 | 1\n /** Amount to preview */\n amount: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched collateral tracker address */\n collateralTrackerAddress?: Address\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * ERC4626 preview result.\n */\nexport interface ERC4626PreviewResult {\n /** The resulting amount (shares or assets depending on function) */\n result: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Helper to get collateral tracker address.\n */\nasync function getCollateralTrackerAddress(\n client: PublicClient,\n poolAddress: Address,\n tokenIndex: 0 | 1,\n providedAddress?: Address,\n): Promise<Address> {\n if (providedAddress) return providedAddress\n\n return client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: tokenIndex === 0 ? 'collateralToken0' : 'collateralToken1',\n })\n}\n\n/**\n * Preview the amount of shares that would be minted for a deposit.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewDeposit(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewDeposit',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of assets that would be returned for a withdrawal.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewWithdraw(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewWithdraw',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of assets required for a mint.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewMint(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewMint',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Preview the amount of shares that would be burned for a redeem.\n *\n * @param params - The parameters\n * @returns Preview result with block metadata\n */\nexport async function previewRedeem(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewRedeem',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Convert an amount of assets to shares.\n *\n * @param params - The parameters\n * @returns Conversion result with block metadata\n */\nexport async function convertToShares(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'convertToShares',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n\n/**\n * Convert an amount of shares to assets.\n *\n * @param params - The parameters\n * @returns Conversion result with block metadata\n */\nexport async function convertToAssets(params: ERC4626PreviewParams): Promise<ERC4626PreviewResult> {\n const { client, poolAddress, tokenIndex, amount, blockNumber, collateralTrackerAddress } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const trackerAddress = await getCollateralTrackerAddress(\n client,\n poolAddress,\n tokenIndex,\n collateralTrackerAddress,\n )\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'convertToAssets',\n args: [amount],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n return { result, _meta }\n}\n","/**\n * PanopticGuardian read functions for the Panoptic v2 SDK.\n *\n * The Guardian can lock a pool into close-only mode. Unlocking is a two-step\n * timelocked flow: `requestUnlock(pool)` schedules an unlock ETA, and after the\n * ETA matures `executeUnlock(pool)` clears the lock. This module reads the\n * pending-unlock state so the UI can surface a countdown while a pool is locked.\n *\n * @module v2/reads/guardian\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticGuardianAbi, panopticPoolV2Abi, riskEngineAbi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Parameters for getGuardianUnlockState.\n */\nexport interface GetGuardianUnlockStateParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Optional RiskEngine address (skips the pool.riskEngine() read) */\n riskEngineAddress?: Address\n /** Optional PanopticGuardian address (skips the riskEngine.GUARDIAN() read) */\n guardianAddress?: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Guardian pool-unlock state.\n */\nexport interface GuardianUnlockState {\n /** Resolved PanopticGuardian contract address */\n guardianAddress: Address\n /** Unlock ETA as a Unix timestamp (seconds); 0n when no unlock is pending */\n unlockEta: bigint\n /** True when an unlock has been requested but not yet executed */\n hasPendingUnlock: boolean\n /** True when the pending unlock's timelock has elapsed and it can be executed */\n isReady: boolean\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Read the Guardian pending-unlock state for a pool.\n *\n * Resolves the Guardian address from the pool's RiskEngine when not provided,\n * then reads `unlockEta` and `isPoolUnlockReady` from the PanopticGuardian in a\n * single multicall pinned to the same block.\n *\n * @param params - The parameters\n * @returns Guardian unlock state with block metadata\n */\nexport async function getGuardianUnlockState(\n params: GetGuardianUnlockStateParams,\n): Promise<GuardianUnlockState> {\n const { client, poolAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Only reuse caller-supplied metadata when it matches the block we read at,\n // otherwise data and metadata would come from different blocks.\n const reusableMeta =\n params._meta && params._meta.blockNumber === targetBlockNumber ? params._meta : undefined\n\n // Resolve the RiskEngine (immutable) unless caller supplied it.\n const riskEngineAddress =\n params.riskEngineAddress ??\n (await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'riskEngine',\n blockNumber: targetBlockNumber,\n }))\n\n // Resolve the Guardian (immutable) unless caller supplied it.\n const guardianAddress =\n params.guardianAddress ??\n (await client.readContract({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n functionName: 'GUARDIAN',\n blockNumber: targetBlockNumber,\n }))\n\n const [results, _meta] = await Promise.all([\n client.multicall({\n contracts: [\n {\n address: guardianAddress,\n abi: panopticGuardianAbi,\n functionName: 'unlockEta',\n args: [poolAddress],\n },\n {\n address: guardianAddress,\n abi: panopticGuardianAbi,\n functionName: 'isPoolUnlockReady',\n args: [poolAddress],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n }),\n reusableMeta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [unlockEta, isReady] = results\n\n return {\n guardianAddress,\n unlockEta,\n hasPendingUnlock: unlockEta > 0n,\n isReady,\n _meta,\n }\n}\n","/**\n * Safe mode check functions for the Panoptic v2 SDK.\n *\n * Safe mode is a protective mechanism that activates when pool conditions\n * become dangerous (e.g., extreme price movements or liquidity issues).\n *\n * @module v2/reads/safeMode\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta, SafeModeState as OracleSafeModeState } from '../types'\n\n/**\n * Safe mode status values.\n */\nexport const SafeModeStatus = {\n /** Pool is operating normally */\n NORMAL: 0n,\n /** No new leveraged positions allowed */\n NO_LEVERAGE: 1n,\n /** No swaps allowed */\n NO_SWAP: 2n,\n /** Close-only mode */\n CLOSE_ONLY: 3n,\n} as const\n\nexport type SafeModeStatusValue = (typeof SafeModeStatus)[keyof typeof SafeModeStatus]\n\n/**\n * Safe mode state for bot preflight and operation guards.\n */\nexport type SafeModeState = OracleSafeModeState\n\n/**\n * Parameters for getSafeMode.\n */\nexport interface GetSafeModeParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get the current safe mode status of a pool.\n *\n * Safe mode is activated when:\n * - Pool liquidity drops below safe thresholds\n * - Price volatility exceeds safe limits\n * - Administrative pause is triggered\n *\n * @param params - The parameters\n * @returns Safe mode state with block metadata\n */\nexport async function getSafeMode(params: GetSafeModeParams): Promise<SafeModeState> {\n const { client, poolAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [safeModeRaw, _meta] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'isSafeMode',\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // isSafeMode returns uint8:\n // 0 = normal, 1 = no leverage, 2 = no swap, 3 = close only\n const status = BigInt(safeModeRaw) as SafeModeStatusValue\n\n switch (status) {\n case SafeModeStatus.NO_LEVERAGE:\n return {\n mode: 'restricted',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: true,\n reason: 'All positions require 100% collateral',\n _meta,\n }\n case SafeModeStatus.NO_SWAP:\n return {\n mode: 'restricted',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: false,\n reason: 'Swaps are disabled',\n _meta,\n }\n case SafeModeStatus.CLOSE_ONLY:\n return {\n mode: 'emergency',\n canMint: false,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: false,\n reason: 'Pool is in close-only mode',\n _meta,\n }\n default:\n return {\n mode: 'normal',\n canMint: true,\n canBurn: true,\n canForceExercise: true,\n canLiquidate: true,\n canSwapAtMint: true,\n _meta,\n }\n }\n}\n","/**\n * Additional utility functions using PanopticQuery contract.\n *\n * These functions provide enhanced analysis capabilities for portfolio management,\n * risk visualization, and TokenId optimization.\n *\n * @module v2/reads/queryUtils\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Portfolio value result (without premia).\n */\nexport interface PortfolioValue {\n /** Value in token 0 */\n value0: bigint\n /** Value in token 1 */\n value1: bigint\n /** Tick at which value was calculated */\n atTick: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPortfolioValue.\n */\nexport interface GetPortfolioValueParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** Optional: Tick to calculate value at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get portfolio value (NAV) without premia.\n *\n * This calculates the net asset value of the portfolio based on Uniswap liquidity\n * at a given tick, excluding accumulated premia. Useful for PnL tracking separate\n * from liquidation value.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Portfolio value with block metadata\n */\nexport async function getPortfolioValue(params: GetPortfolioValueParams): Promise<PortfolioValue> {\n const { client, poolAddress, account, tokenIds, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Skip getCurrentTick RPC call when atTick is provided\n const [currentTickResult, _meta] = await Promise.all([\n atTick != null\n ? Promise.resolve(atTick)\n : client\n .readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n .then((r) => BigInt(r)),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const effectiveTick = currentTickResult\n\n const result = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue',\n args: [poolAddress, account, Number(effectiveTick), tokenIds],\n blockNumber: targetBlockNumber,\n })\n\n const [value0, value1] = result\n\n return {\n value0,\n value1,\n atTick: effectiveTick,\n _meta,\n }\n}\n\n/**\n * Collateral data point across tick range.\n */\nexport interface CollateralDataPoint {\n /** Tick value */\n tick: bigint\n /** Collateral balance at this tick */\n balance: bigint\n /** Required collateral at this tick */\n required: bigint\n}\n\n/**\n * Collateral analysis across tick range result.\n */\nexport interface CollateralAcrossTicks {\n /** Array of data points (301 points from liquidation range) */\n dataPoints: CollateralDataPoint[]\n /** Liquidation price below current (null if none) */\n liquidationPriceDown: bigint | null\n /** Liquidation price above current (null if none) */\n liquidationPriceUp: bigint | null\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for checkCollateralAcrossTicks.\n */\nexport interface CheckCollateralAcrossTicksParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Check collateral balance vs requirement across a range of ticks.\n *\n * This function returns 301 data points spanning a range around the current price,\n * including liquidation prices. Perfect for charting liquidation risk in a UI.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Collateral analysis across ticks with block metadata\n */\nexport async function checkCollateralAcrossTicks(\n params: CheckCollateralAcrossTicksParams,\n): Promise<CollateralAcrossTicks> {\n const { client, poolAddress, account, tokenIds, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'checkCollateralListOutput',\n args: [poolAddress, account, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [balanceRequired, tickData, liquidationPrices] = result\n\n // MIN_TICK and MAX_TICK indicate no liquidation at that boundary\n const MIN_TICK = -887272n\n const MAX_TICK = 887272n\n\n // Convert to data points\n const dataPoints: CollateralDataPoint[] = balanceRequired.map((point, index) => ({\n tick: BigInt(tickData[index]),\n balance: point[0],\n required: point[1],\n }))\n\n // Convert from number (abitype default for int24) to bigint (viem runtime type)\n const liqPriceDown = BigInt(liquidationPrices[0])\n const liqPriceUp = BigInt(liquidationPrices[1])\n\n return {\n dataPoints,\n liquidationPriceDown: liqPriceDown === MIN_TICK ? null : liqPriceDown,\n liquidationPriceUp: liqPriceUp === MAX_TICK ? null : liqPriceUp,\n _meta,\n }\n}\n\n/**\n * Parameters for optimizeTokenIdRiskPartners.\n */\nexport interface OptimizeTokenIdRiskPartnersParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** TokenId to optimize */\n tokenId: bigint\n /** Optional: Tick to optimize at (defaults to current tick) */\n atTick?: bigint\n /** PanopticQuery address (required for this function) */\n queryAddress: Address\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Optimize risk partner assignments for a TokenId.\n *\n * Tests all valid risk partner permutations and returns the TokenId with\n * the lowest collateral requirement. Useful when building positions to\n * maximize capital efficiency.\n *\n * ## Same-Block Guarantee\n * Optimization is performed at a single block.\n *\n * Note: Only works for tokenIds with 2+ legs. Single-leg positions return unchanged.\n *\n * @param params - The parameters\n * @returns Optimized TokenId\n */\nexport async function optimizeTokenIdRiskPartners(\n params: OptimizeTokenIdRiskPartnersParams,\n): Promise<bigint> {\n const { client, poolAddress, tokenId, atTick, queryAddress, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n // Get current tick if not provided\n let effectiveTick: bigint\n if (atTick !== undefined) {\n effectiveTick = atTick\n } else {\n const currentTickResult = await client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlockNumber,\n })\n // Bridge type from panopticPoolV2Abi (number | bigint) to bigint\n effectiveTick = BigInt(currentTickResult)\n }\n\n const optimizedTokenId = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'optimizeRiskPartners',\n args: [poolAddress, Number(effectiveTick), tokenId],\n blockNumber: targetBlockNumber,\n })\n\n return optimizedTokenId\n}\n","/**\n * Pool liquidity distribution read function using PanopticQuery.\n *\n * @module v2/reads/liquidity\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n/**\n * Result of getPoolLiquidities.\n */\nexport interface PoolLiquidities {\n /** Tick values for each data point */\n ticks: bigint[]\n /** Net liquidity at each tick */\n liquidityNets: bigint[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPoolLiquidities.\n */\nexport interface GetPoolLiquiditiesParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery address */\n queryAddress: Address\n /** Starting tick of the range */\n startTick: bigint\n /** Number of ticks to query */\n nTicks: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Get cumulative liquidity distribution across a tick range.\n *\n * Wraps `PanopticQuery.getTickNets()` to return tick data and net liquidity\n * for each tick in the specified range.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - The parameters\n * @returns Tick data and liquidity nets with block metadata\n */\nexport async function getPoolLiquidities(\n params: GetPoolLiquiditiesParams,\n): Promise<PoolLiquidities> {\n const { client, poolAddress, queryAddress, startTick, nTicks, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNets',\n args: [poolAddress, Number(startTick), nTicks],\n blockNumber: targetBlockNumber,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [tickData, liquidityNets] = result\n\n return {\n ticks: [...tickData],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n","/**\n * Percentage and ratio formatters.\n *\n * All formatters require explicit precision - no hidden defaults.\n *\n * @module v2/formatters/percentage\n */\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n if (denominator === 0n) {\n return '0'\n }\n\n const isNegative = numerator < 0n !== denominator < 0n\n const absNumerator = numerator < 0n ? -numerator : numerator\n const absDenominator = denominator < 0n ? -denominator : denominator\n\n const scale = TEN ** precision\n const scaled = (absNumerator * scale + absDenominator / 2n) / absDenominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n const sign = isNegative ? '-' : ''\n\n if (precision === 0n) {\n return `${sign}${integerPart}`\n }\n\n return `${sign}${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Format basis points as a percentage string.\n * 100 bps = 1%\n *\n * @param bps - Basis points value\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatBps(50n, 2n) // \"0.50%\"\n * formatBps(50n, 1n) // \"0.5%\"\n * formatBps(100n, 2n) // \"1.00%\"\n * formatBps(1500n, 2n) // \"15.00%\"\n * formatBps(-50n, 2n) // \"-0.50%\"\n * ```\n */\nexport function formatBps(bps: bigint, precision: bigint): string {\n const isNegative = bps < 0n\n const absBps = isNegative ? -bps : bps\n\n // bps to percentage: divide by 100\n // Scale up for precision, then divide\n const scaleFactor = 10n ** precision\n const scaled = (absBps * scaleFactor) / 100n\n const integerPart = scaled / scaleFactor\n const fractionalPart = scaled % scaleFactor\n\n const fractionalStr = fractionalPart.toString().padStart(Number(precision), '0')\n const sign = isNegative ? '-' : ''\n\n return precision > 0n ? `${sign}${integerPart}.${fractionalStr}%` : `${sign}${integerPart}%`\n}\n\n/**\n * Format utilization as a percentage string.\n * Utilization is stored as 0n-10000n, where 10000n = 100%.\n *\n * @param util - Utilization value (0-10000)\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatUtilization(7500n, 2n) // \"75.00%\"\n * formatUtilization(7500n, 0n) // \"75%\"\n * formatUtilization(10000n, 2n) // \"100.00%\"\n * formatUtilization(123n, 2n) // \"1.23%\"\n * ```\n */\nexport function formatUtilization(util: bigint, precision: bigint): string {\n // util is in basis points (10000 = 100%)\n return formatBps(util, precision)\n}\n\n/**\n * Parse a percentage string to basis points.\n *\n * @param percent - Percentage string (e.g., \"1.5%\" or \"1.5\")\n * @returns Basis points value\n *\n * @example\n * ```typescript\n * parseBps(\"1.5%\") // 150n\n * parseBps(\"1.5\") // 150n\n * parseBps(\"100%\") // 10000n\n * parseBps(\"0.5%\") // 50n\n * ```\n */\nexport function parseBps(percent: string): bigint {\n // Remove % suffix if present\n const cleaned = percent.trim().replace(/%$/, '')\n const isNegative = cleaned.startsWith('-')\n const absValue = isNegative ? cleaned.slice(1) : cleaned\n\n const [integerStr, fractionalStr = ''] = absValue.split('.')\n\n // Convert to basis points: multiply by 100\n // Handle up to 2 decimal places in the percentage\n const paddedFractional = fractionalStr.padEnd(2, '0').slice(0, 2)\n\n const integerPart = BigInt(integerStr || '0') * 100n\n const fractionalPart = BigInt(paddedFractional || '0')\n\n const result = integerPart + fractionalPart\n return isNegative ? -result : result\n}\n\n/**\n * Format a ratio as a percentage string.\n *\n * @param numerator - Numerator of the ratio\n * @param denominator - Denominator of the ratio\n * @param precision - Number of decimal places to display\n * @returns Formatted percentage string\n *\n * @example\n * ```typescript\n * formatRatioPercent(1n, 4n, 1n) // \"25.0%\"\n * formatRatioPercent(3n, 4n, 2n) // \"75.00%\"\n * ```\n */\nexport function formatRatioPercent(\n numerator: bigint,\n denominator: bigint,\n precision: bigint,\n): string {\n const scaledNumerator = numerator * 100n\n return `${formatRatio(scaledNumerator, denominator, precision)}%`\n}\n","/**\n * Pool-bound formatters factory.\n *\n * Creates formatter functions that capture pool context (token decimals)\n * for less verbose call sites in single-pool UI components.\n *\n * @module v2/formatters/poolFormatters\n */\n\nimport { formatTokenAmount, parseTokenAmount } from './amount'\nimport { priceToTick, tickToPrice, tickToPriceDecimalScaled } from './tick'\n\n/**\n * Pool-bound formatters interface.\n *\n * These formatters capture the pool's token decimals, so you don't need\n * to pass them at every call site.\n */\nexport interface PoolFormatters {\n /** Token0 decimals */\n readonly decimals0: bigint\n /** Token1 decimals */\n readonly decimals1: bigint\n\n /**\n * Convert tick to raw price (1.0001^tick).\n */\n tickToPrice(tick: bigint): string\n\n /**\n * Convert tick to decimal-scaled price (token1 per token0).\n */\n tickToPriceScaled(tick: bigint, precision: bigint): string\n\n /**\n * Convert tick to decimal-scaled inverse price (token0 per token1).\n */\n tickToInversePriceScaled(tick: bigint, precision: bigint): string\n\n /**\n * Convert a price (token1 per token0) to tick.\n */\n priceToTick(price: string): bigint\n\n /**\n * Format token0 amount with specified precision.\n */\n formatAmount0(amount: bigint, precision: bigint): string\n\n /**\n * Format token1 amount with specified precision.\n */\n formatAmount1(amount: bigint, precision: bigint): string\n\n /**\n * Parse token0 amount string to raw units.\n */\n parseAmount0(amount: string): bigint\n\n /**\n * Parse token1 amount string to raw units.\n */\n parseAmount1(amount: string): bigint\n}\n\n/**\n * Pool metadata required to create pool-bound formatters.\n */\nexport interface PoolFormatterConfig {\n /** Token0 decimals */\n decimals0: bigint\n /** Token1 decimals */\n decimals1: bigint\n}\n\n/**\n * Create pool-bound formatters that capture token decimals.\n *\n * Use this factory when working with a single pool to avoid passing\n * decimals at every call site.\n *\n * @param config - Pool configuration with token decimals\n * @returns Pool-bound formatter functions\n *\n * @example\n * ```typescript\n * // Get pool data\n * const pool = await getPool({ client, poolAddress })\n *\n * // Create formatters bound to this pool\n * const fmt = createPoolFormatters({\n * decimals0: pool.token0Decimals,\n * decimals1: pool.token1Decimals,\n * })\n *\n * // Now use without passing decimals each time\n * const priceStr = fmt.tickToPriceScaled(position.currentTick, 4n)\n * const amount0Str = fmt.formatAmount0(collateral.assets, 4n)\n * const amount1Str = fmt.formatAmount1(premia.token1, 2n)\n *\n * // Parse user input\n * const rawAmount0 = fmt.parseAmount0(\"1.5\")\n * const rawAmount1 = fmt.parseAmount1(\"3000\")\n * ```\n */\nexport function createPoolFormatters(config: PoolFormatterConfig): PoolFormatters {\n const { decimals0, decimals1 } = config\n\n return {\n decimals0,\n decimals1,\n\n tickToPrice(tick: bigint): string {\n return tickToPrice(tick)\n },\n\n tickToPriceScaled(tick: bigint, precision: bigint): string {\n return tickToPriceDecimalScaled(tick, decimals0, decimals1, precision)\n },\n\n tickToInversePriceScaled(tick: bigint, precision: bigint): string {\n // Swap decimals for inverse price\n return tickToPriceDecimalScaled(tick, decimals1, decimals0, precision)\n },\n\n priceToTick(price: string): bigint {\n return priceToTick(price, decimals0, decimals1)\n },\n\n formatAmount0(amount: bigint, precision: bigint): string {\n return formatTokenAmount(amount, decimals0, precision)\n },\n\n formatAmount1(amount: bigint, precision: bigint): string {\n return formatTokenAmount(amount, decimals1, precision)\n },\n\n parseAmount0(amount: string): bigint {\n return parseTokenAmount(amount, decimals0)\n },\n\n parseAmount1(amount: string): bigint {\n return parseTokenAmount(amount, decimals1)\n },\n }\n}\n","/**\n * Token list integration utilities.\n *\n * Provides helpers for integrating with standard token lists\n * (e.g., Uniswap token list, CoinGecko token list).\n *\n * @module v2/formatters/tokenList\n */\n\nimport type { Address } from 'viem'\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n const scale = TEN ** precision\n const scaled = (numerator * scale + denominator / 2n) / denominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n\n if (precision === 0n) {\n return integerPart.toString()\n }\n\n return `${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Generate a token list ID for external token list integration.\n *\n * Token lists use a standardized format: `chainId:address`\n * This is compatible with most token list standards.\n *\n * @param chainId - The chain ID\n * @param address - The token address\n * @returns Token list ID string\n *\n * @example\n * ```typescript\n * getTokenListId(1n, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')\n * // \"1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\"\n *\n * getTokenListId(11155111n, '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14')\n * // \"11155111:0xfff9976782d46cc05630d1f6ebab18b2324d6b14\"\n * ```\n */\nexport function getTokenListId(chainId: bigint, address: Address): string {\n return `${chainId}:${address.toLowerCase()}`\n}\n\n/**\n * Parse a token list ID back to chain ID and address.\n *\n * @param tokenListId - The token list ID string\n * @returns Object with chainId and address\n *\n * @example\n * ```typescript\n * parseTokenListId(\"1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\")\n * // { chainId: 1n, address: \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\" }\n * ```\n */\nexport function parseTokenListId(tokenListId: string): {\n chainId: bigint\n address: Address\n} {\n const [chainIdStr, address] = tokenListId.split(':')\n if (!chainIdStr || !address) {\n throw new Error(`Invalid token list ID: ${tokenListId}`)\n }\n return {\n chainId: BigInt(chainIdStr),\n address: address as Address,\n }\n}\n\n/**\n * Generate a pool ID string for display purposes.\n *\n * @param token0Symbol - Symbol of token0\n * @param token1Symbol - Symbol of token1\n * @param feeBps - Fee in basis points (e.g., 500n for 0.05%)\n * @returns Pool ID string\n *\n * @example\n * ```typescript\n * getPoolDisplayId('WETH', 'USDC', 500n)\n * // \"WETH/USDC 0.05%\"\n *\n * getPoolDisplayId('WBTC', 'ETH', 3000n)\n * // \"WBTC/ETH 0.30%\"\n * ```\n */\nexport function getPoolDisplayId(\n token0Symbol: string,\n token1Symbol: string,\n feeBps: bigint,\n): string {\n return `${token0Symbol}/${token1Symbol} ${formatFeeTier(feeBps)}`\n}\n\n/**\n * Format a fee tier for display.\n *\n * @param feeBps - Fee in basis points (e.g., 500n for 0.05%)\n * @returns Fee tier string\n *\n * @example\n * ```typescript\n * formatFeeTier(500n) // \"0.05%\"\n * formatFeeTier(3000n) // \"0.30%\"\n * formatFeeTier(10000n) // \"1.0%\"\n * ```\n */\nexport function formatFeeTier(feeBps: bigint): string {\n const precision = feeBps < 10000n ? 2n : 1n\n const feeStr = formatRatio(feeBps, 10_000n, precision)\n return `${feeStr}%`\n}\n","/**\n * General display formatters for UI components.\n *\n * These are utility formatters for common display needs like\n * addresses, timestamps, and durations.\n *\n * @module v2/formatters/display\n */\n\nimport { formatTokenAmount } from './amount'\n\nconst TEN = 10n\n\nfunction formatRatio(numerator: bigint, denominator: bigint, precision: bigint): string {\n if (precision < 0n) {\n throw new RangeError('Precision must be non-negative')\n }\n\n const scale = TEN ** precision\n const scaled = (numerator * scale + denominator / 2n) / denominator\n const integerPart = scaled / scale\n const fractionalPart = scaled % scale\n\n if (precision === 0n) {\n return integerPart.toString()\n }\n\n return `${integerPart}.${fractionalPart.toString().padStart(Number(precision), '0')}`\n}\n\n/**\n * Truncate an address for display.\n *\n * @param address - Full address\n * @param chars - Characters to show on each side (default: 4)\n * @returns Truncated address like \"0x1234...5678\"\n *\n * @example\n * ```typescript\n * truncateAddress('0x1234567890abcdef1234567890abcdef12345678')\n * // \"0x1234...5678\"\n *\n * truncateAddress('0x1234567890abcdef1234567890abcdef12345678', 6)\n * // \"0x123456...345678\"\n * ```\n */\nexport function truncateAddress(address: string, chars = 4): string {\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(address.length) <= minLength) return address\n return `${address.slice(0, Number(charsBig + 2n))}...${address.slice(-Number(charsBig))}`\n}\n\n/**\n * Format a Unix timestamp as an ISO date string (YYYY-MM-DD).\n *\n * @param timestamp - Unix timestamp in seconds\n * @returns ISO date string\n *\n * @example\n * ```typescript\n * formatTimestamp(1700000000n) // \"2023-11-14\"\n * ```\n */\nexport function formatTimestamp(timestamp: bigint): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toISOString().split('T')[0]\n}\n\n/**\n * Format a Unix timestamp as an ISO datetime string.\n *\n * @param timestamp - Unix timestamp in seconds\n * @returns ISO datetime string\n *\n * @example\n * ```typescript\n * formatDatetime(1700000000n) // \"2023-11-14T22:13:20.000Z\"\n * ```\n */\nexport function formatDatetime(timestamp: bigint): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toISOString()\n}\n\n/**\n * Format a Unix timestamp as a locale-aware date string.\n *\n * @param timestamp - Unix timestamp in seconds\n * @param locale - Locale string (default: system locale)\n * @param options - Intl.DateTimeFormat options\n * @returns Formatted date string\n *\n * @example\n * ```typescript\n * formatTimestampLocale(1700000000n)\n * // \"11/14/2023\" (US locale)\n *\n * formatTimestampLocale(1700000000n, 'de-DE')\n * // \"14.11.2023\" (German locale)\n * ```\n */\nexport function formatTimestampLocale(\n timestamp: bigint,\n locale?: string,\n options?: Intl.DateTimeFormatOptions,\n): string {\n const ms = timestamp * 1000n\n return new Date(Number(ms)).toLocaleDateString(locale, options)\n}\n\n/**\n * Format a duration in milliseconds as a human-readable string.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted duration string\n *\n * @example\n * ```typescript\n * formatDuration(1500n) // \"1.5s\"\n * formatDuration(150n) // \"150ms\"\n * formatDuration(90000n) // \"1m 30s\"\n * formatDuration(3661000n) // \"1h 1m\"\n * ```\n */\nexport function formatDuration(ms: bigint): string {\n const isNegative = ms < 0n\n const absMs = isNegative ? -ms : ms\n const sign = isNegative ? '-' : ''\n\n if (absMs < 1000n) {\n return `${sign}${absMs}ms`\n }\n\n if (absMs < 60000n) {\n const tenthsTotal = (absMs + 50n) / 100n\n const seconds = tenthsTotal / 10n\n const tenths = tenthsTotal % 10n\n return `${sign}${seconds}.${tenths}s`\n }\n\n if (absMs < 3600000n) {\n const minutes = absMs / 60000n\n const seconds = ((absMs % 60000n) + 500n) / 1000n\n return seconds > 0n ? `${sign}${minutes}m ${seconds}s` : `${sign}${minutes}m`\n }\n\n const hours = absMs / 3600000n\n const minutes = ((absMs % 3600000n) + 30000n) / 60000n\n return minutes > 0n ? `${sign}${hours}h ${minutes}m` : `${sign}${hours}h`\n}\n\n/**\n * Format a duration in seconds as a human-readable string.\n *\n * @param seconds - Duration in seconds\n * @returns Formatted duration string\n */\nexport function formatDurationSeconds(seconds: bigint): string {\n return formatDuration(seconds * 1000n)\n}\n\n/**\n * Format a block number for display.\n *\n * @param blockNumber - The block number\n * @returns Formatted block number with commas\n *\n * @example\n * ```typescript\n * formatBlockNumber(18000000n) // \"18,000,000\"\n * ```\n */\nexport function formatBlockNumber(blockNumber: bigint): string {\n return blockNumber.toLocaleString()\n}\n\n/**\n * Format a gas amount for display.\n *\n * @param gas - Gas units\n * @returns Formatted gas string\n */\nexport function formatGas(gas: bigint): string {\n return gas.toLocaleString()\n}\n\n/**\n * Format a transaction hash for display (truncated).\n *\n * @param hash - Full transaction hash\n * @param chars - Characters to show on each side (default: 6)\n * @returns Truncated hash like \"0x123456...abcdef\"\n *\n * @example\n * ```typescript\n * formatTxHash('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef')\n * // \"0x123456...abcdef\"\n * ```\n */\nexport function formatTxHash(hash: string, chars = 6): string {\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(hash.length) <= minLength) return hash\n return `${hash.slice(0, Number(charsBig + 2n))}...${hash.slice(-Number(charsBig))}`\n}\n\nfunction formatHex(value: bigint): string {\n return `0x${value.toString(16)}`\n}\n\n/**\n * Format a TokenId as a hex string.\n *\n * @param tokenId - TokenId value\n * @returns Hex string representation\n */\nexport function formatTokenIdHex(tokenId: bigint): string {\n return formatHex(tokenId)\n}\n\n/**\n * Format a PoolId as a hex string.\n *\n * @param poolId - PoolId value\n * @returns Hex string representation\n */\nexport function formatPoolIdHex(poolId: bigint): string {\n return formatHex(poolId)\n}\n\n/**\n * Format a TokenId as a shortened hex string.\n *\n * @param tokenId - TokenId value\n * @param chars - Characters to show on each side (default: 4)\n * @returns Truncated hex string like \"0x1234...abcd\"\n */\nexport function formatTokenIdShort(tokenId: bigint, chars = 4): string {\n const hex = formatHex(tokenId)\n const charsBig = BigInt(chars)\n const minLength = charsBig * 2n + 4n\n if (BigInt(hex.length) <= minLength) return hex\n return `${hex.slice(0, Number(charsBig + 2n))}...${hex.slice(-Number(charsBig))}`\n}\n\n/**\n * Format a large number with K/M/B suffixes.\n *\n * @param value - The numeric value\n * @param precision - Number of decimal places (default: 1n)\n * @returns Formatted string with suffix\n *\n * @example\n * ```typescript\n * formatCompact(1234n) // \"1.2K\"\n * formatCompact(1234567n) // \"1.2M\"\n * formatCompact(1234567890n) // \"1.2B\"\n * formatCompact(999n) // \"999\"\n * ```\n */\nexport function formatCompact(value: bigint, precision: bigint = 1n): string {\n const isNegative = value < 0n\n const absValue = isNegative ? -value : value\n\n let formatted: string\n\n if (absValue < 1000n) {\n formatted = absValue.toString()\n } else if (absValue < 1_000_000n) {\n formatted = `${formatRatio(absValue, 1000n, precision)}K`\n } else if (absValue < 1_000_000_000n) {\n formatted = `${formatRatio(absValue, 1_000_000n, precision)}M`\n } else {\n formatted = `${formatRatio(absValue, 1_000_000_000n, precision)}B`\n }\n\n return isNegative ? `-${formatted}` : formatted\n}\n\n/**\n * Format a wei amount as a display string.\n *\n * @param wei - Amount in wei\n * @returns Formatted string with unit\n */\nexport function formatWei(wei: bigint): string {\n return `${wei} wei`\n}\n\n/**\n * Format a wei amount as gwei.\n *\n * @param wei - Amount in wei\n * @param precision - Number of decimal places to display\n * @returns Formatted string with unit\n */\nexport function formatGwei(wei: bigint, precision: bigint): string {\n return `${formatTokenAmount(wei, 9n, precision)} gwei`\n}\n","/**\n * Account greeks calculation using stored position data.\n *\n * This module provides functions to calculate account-level greeks\n * using position data stored by syncPositions(). Only the current tick\n * is fetched via RPC - all other data comes from storage.\n *\n * @module v2/reads/accountGreeks\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError, StorageDataNotFoundError } from '../errors'\nimport { tickToSqrtPriceX96 } from '../formatters'\nimport {\n type PositionGreeksResult,\n calculatePositionDelta,\n calculatePositionGamma,\n calculatePositionValue,\n} from '../greeks'\nimport type { StorageAdapter } from '../storage'\nimport { getPoolMetaKey, getPositionMetaKey, getPositionsKey, jsonSerializer } from '../storage'\nimport type { BlockMeta, StoredPoolMeta, StoredPositionData } from '../types'\nimport { type CollateralAddresses, getAccountCollateral } from './account'\n\nconst Q192 = 1n << 192n\n\n/**\n * Parameters for getAccountGreeks.\n */\nexport interface GetAccountGreeksParams {\n /** viem PublicClient (only used to fetch current tick) */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Storage adapter containing synced position data */\n storage: StorageAdapter\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /**\n * When true, include collateral token balance as linear delta.\n * Requires `assetIndex` to specify which token is the asset.\n */\n includeCollateral?: boolean\n /**\n * Which token is the \"asset\" (the directional exposure token).\n * 0n = token0 is asset, 1n = token1 is asset.\n * Required when `includeCollateral` is true.\n */\n assetIndex?: 0n | 1n\n /** Optional pre-fetched collateral addresses (used when includeCollateral is true) */\n collateralAddresses?: CollateralAddresses\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getAccountGreeks.\n *\n * Returns both granular breakdown (positions vs collateral) and computed totals.\n * - `positionsDelta` / `positionsValue`: Options exposure only\n * - `collateralDelta` / `collateralValue`: Collateral in the pool\n * - `totalDelta` / `totalValue`: Sum of both (use for net portfolio greeks)\n *\n * All values are in natural token smallest units (no WAD scaling).\n * - Value/gamma: numeraire token smallest units\n * - Delta: asset token smallest units\n */\nexport interface AccountGreeksResult {\n // --- Position greeks (options only) ---\n /** Sum of position values (numeraire smallest units, options only) */\n positionsValue: bigint\n /** Sum of position deltas (asset smallest units, options only) */\n positionsDelta: bigint\n /** Sum of position gammas (numeraire smallest units) */\n positionsGamma: bigint\n\n // --- Collateral greeks ---\n /**\n * Value of collateral holdings: asset balance × price + numeraire balance.\n * In numeraire smallest units. 0n when includeCollateral is not set.\n */\n collateralValue: bigint\n /**\n * Linear delta from the asset token's collateral balance (asset smallest units).\n * 0n when includeCollateral is not set.\n */\n collateralDelta: bigint\n\n // --- Computed totals ---\n /** Total portfolio value = positionsValue + collateralValue */\n totalValue: bigint\n /** Total portfolio delta = positionsDelta + collateralDelta */\n totalDelta: bigint\n\n // --- Metadata ---\n /** Number of positions included */\n positionCount: bigint\n /** Per-position greeks breakdown */\n positions: Array<{\n tokenId: bigint\n greeks: PositionGreeksResult\n }>\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Calculate account-level greeks using stored position data.\n *\n * This function reads position data from storage (populated by syncPositions)\n * and calculates greeks client-side. Only the current tick is fetched via RPC.\n *\n * @param params - The parameters\n * @returns Account greeks with per-position breakdown\n * @throws StorageDataNotFoundError if required data is not in storage\n * @throws PanopticError if includeCollateral is true but assetIndex is not provided\n *\n * @example\n * ```typescript\n * // First sync positions to populate storage\n * await syncPositions({ client, chainId, poolAddress, account, storage })\n *\n * // Then calculate greeks from stored data\n * const greeks = await getAccountGreeks({\n * client,\n * chainId,\n * poolAddress,\n * account,\n * storage,\n * })\n *\n * console.log('Positions delta:', greeks.positionsDelta)\n * ```\n */\nexport async function getAccountGreeks(\n params: GetAccountGreeksParams,\n): Promise<AccountGreeksResult> {\n const {\n client,\n chainId,\n poolAddress,\n account,\n storage,\n blockNumber,\n includeCollateral,\n assetIndex,\n collateralAddresses,\n } = params\n\n // 0. Validate: includeCollateral requires assetIndex\n if (includeCollateral && assetIndex === undefined) {\n throw new PanopticError('assetIndex is required when includeCollateral is true')\n }\n\n // 1. Read pool metadata from storage\n const poolMetaKey = getPoolMetaKey(chainId, poolAddress)\n const poolMetaRaw = await storage.get(poolMetaKey)\n if (!poolMetaRaw) {\n throw new StorageDataNotFoundError('poolMeta', poolMetaKey)\n }\n const poolMeta = jsonSerializer.parse(poolMetaRaw) as StoredPoolMeta\n\n // 2. Read position IDs from storage\n const positionsKey = getPositionsKey(chainId, poolAddress, account)\n const positionsRaw = await storage.get(positionsKey)\n if (!positionsRaw) {\n throw new StorageDataNotFoundError('positions', positionsKey)\n }\n const positionIds = jsonSerializer.parse(positionsRaw) as bigint[]\n\n // 3. If no positions and no collateral requested, return zeros\n if (positionIds.length === 0 && !includeCollateral) {\n const targetBlock = blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber: targetBlock }))\n\n return {\n positionsValue: 0n,\n positionsDelta: 0n,\n positionsGamma: 0n,\n collateralValue: 0n,\n collateralDelta: 0n,\n totalValue: 0n,\n totalDelta: 0n,\n positionCount: 0n,\n positions: [],\n _meta,\n }\n }\n\n // 4. Read position metadata for each position from storage\n const storedPositions = await Promise.all(\n positionIds.map(async (tokenId) => {\n const posMetaKey = getPositionMetaKey(chainId, poolAddress, tokenId)\n const posMetaRaw = await storage.get(posMetaKey)\n if (!posMetaRaw) {\n throw new StorageDataNotFoundError('positionMeta', posMetaKey)\n }\n return jsonSerializer.parse(posMetaRaw) as StoredPositionData\n }),\n )\n\n // 5. Fetch current tick (+ collateral if requested) from RPC\n const targetBlock = blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n const [currentTick, _meta, collateral] = await Promise.all([\n client.readContract({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n blockNumber: targetBlock,\n }),\n params._meta ?? getBlockMeta({ client, blockNumber: targetBlock }),\n includeCollateral\n ? getAccountCollateral({\n client,\n poolAddress,\n account,\n blockNumber: targetBlock,\n collateralAddresses,\n _meta: params._meta,\n })\n : undefined,\n ])\n\n // 6. Calculate greeks for each position\n let positionsValue = 0n\n let positionsDelta = 0n\n let positionsGamma = 0n\n const positions: AccountGreeksResult['positions'] = []\n\n for (const pos of storedPositions) {\n const input = {\n legs: pos.legs,\n currentTick: BigInt(currentTick),\n mintTick: pos.tickAtMint,\n positionSize: pos.positionSize,\n poolTickSpacing: poolMeta.tickSpacing,\n assetIndex,\n }\n\n const value = calculatePositionValue(input)\n const delta = calculatePositionDelta(input)\n const gamma = calculatePositionGamma(input)\n\n positionsValue += value\n positionsDelta += delta\n positionsGamma += gamma\n\n positions.push({\n tokenId: pos.tokenId,\n greeks: { value, delta, gamma },\n })\n }\n\n // 7. Collateral value and delta\n let collateralValue = 0n\n let collateralDelta = 0n\n\n if (collateral) {\n const isAssetToken0 = assetIndex === 0n\n const assetBal = isAssetToken0 ? collateral.token0.assets : collateral.token1.assets\n const otherBal = isAssetToken0 ? collateral.token1.assets : collateral.token0.assets\n const sqrtPriceX96 = tickToSqrtPriceX96(BigInt(currentTick))\n\n // assetBal * price converts asset smallest units to numeraire smallest units\n // otherBal is already in numeraire smallest units\n if (isAssetToken0) {\n // price = token1/token0 = sqrtPriceX96² / 2¹⁹²\n collateralValue = (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192 + otherBal\n } else {\n // price = token0/token1 = 2¹⁹² / sqrtPriceX96²\n collateralValue = (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96) + otherBal\n }\n collateralDelta = assetBal\n }\n\n return {\n positionsValue,\n positionsDelta,\n positionsGamma,\n collateralValue,\n collateralDelta,\n totalValue: positionsValue + collateralValue,\n totalDelta: positionsDelta + collateralDelta,\n positionCount: BigInt(positionIds.length),\n positions,\n _meta,\n }\n}\n\n/**\n * Parameters for calculateAccountGreeksPure.\n */\nexport interface CalculateAccountGreeksPureParams {\n /** Stored position data */\n positions: StoredPositionData[]\n /** Pool tick spacing */\n tickSpacing: bigint\n /** Ticks at which to evaluate greeks (one or more) */\n atTicks: bigint[]\n /**\n * Collateral balances [token0Assets, token1Assets] in token smallest units.\n * When provided, both tokens are included in totalValue and the\n * asset token's balance is added to totalDelta.\n */\n collateralAssets?: [bigint, bigint]\n /** Override for leg.asset on all legs (0n = token0 is asset, 1n = token1). Defaults to 0n. */\n assetIndex?: bigint\n}\n\n/**\n * Result of calculateAccountGreeksPure.\n *\n * Arrays are parallel to the input `atTicks` — index i corresponds to `atTicks[i]`.\n * Totals include both position greeks and collateral contributions.\n * All values in natural token smallest units (no WAD scaling).\n */\nexport interface AccountGreeksCurveResult {\n /** Total value at each tick: positions + collateral (numeraire smallest units) */\n totalValue: bigint[]\n /** Total delta at each tick: positions + asset collateral (asset smallest units) */\n totalDelta: bigint[]\n /** Total gamma at each tick: positions only (numeraire smallest units, collateral has zero gamma) */\n totalGamma: bigint[]\n /** Number of positions included */\n positionCount: bigint\n /** Per-position greeks curves (arrays parallel to atTicks) */\n positions: Array<{\n tokenId: bigint\n greeks: {\n value: bigint[]\n delta: bigint[]\n gamma: bigint[]\n }\n }>\n}\n\n/**\n * Pure function to calculate portfolio greeks across a range of ticks.\n *\n * No RPC calls — useful for plotting value/delta/gamma curves on a chart.\n * All returned arrays are parallel to the input `atTicks`.\n *\n * When `collateralAssets` is provided, both token balances are included in\n * `totalValue` (asset balance × price + numeraire balance) and\n * the asset token's balance is added to `totalDelta`.\n *\n * @param params - The parameters\n * @returns Portfolio greeks curves and per-position breakdown\n */\nexport function calculateAccountGreeksPure(\n params: CalculateAccountGreeksPureParams,\n): AccountGreeksCurveResult {\n const { positions, tickSpacing, atTicks, collateralAssets, assetIndex } = params\n const n = atTicks.length\n const isAssetToken0 = assetIndex === undefined || assetIndex === 0n\n\n // Collateral balances (already in token smallest units)\n const assetBal = collateralAssets ? collateralAssets[isAssetToken0 ? 0 : 1] : 0n\n const otherBal = collateralAssets ? collateralAssets[isAssetToken0 ? 1 : 0] : 0n\n\n if (positions.length === 0) {\n const totalValue: bigint[] = []\n const totalDelta: bigint[] = []\n for (let i = 0; i < n; i++) {\n const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i])\n const assetValueInNumeraire = isAssetToken0\n ? (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192\n : (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96)\n totalValue.push(assetValueInNumeraire + otherBal)\n totalDelta.push(assetBal)\n }\n return {\n totalValue,\n totalDelta,\n totalGamma: new Array<bigint>(n).fill(0n),\n positionCount: 0n,\n positions: [],\n }\n }\n\n const totalValue = new Array<bigint>(n).fill(0n)\n const totalDelta = new Array<bigint>(n).fill(0n)\n const totalGamma = new Array<bigint>(n).fill(0n)\n const positionResults: AccountGreeksCurveResult['positions'] = []\n\n for (const pos of positions) {\n const posValues: bigint[] = []\n const posDeltas: bigint[] = []\n const posGammas: bigint[] = []\n\n for (let i = 0; i < n; i++) {\n const input = {\n legs: pos.legs,\n currentTick: atTicks[i],\n mintTick: pos.tickAtMint,\n positionSize: pos.positionSize,\n poolTickSpacing: tickSpacing,\n assetIndex,\n }\n\n const v = calculatePositionValue(input)\n const d = calculatePositionDelta(input)\n const g = calculatePositionGamma(input)\n\n posValues.push(v)\n posDeltas.push(d)\n posGammas.push(g)\n\n totalValue[i] += v\n totalDelta[i] += d\n totalGamma[i] += g\n }\n\n positionResults.push({\n tokenId: pos.tokenId,\n greeks: { value: posValues, delta: posDeltas, gamma: posGammas },\n })\n }\n\n // Add collateral contributions at each tick\n for (let i = 0; i < n; i++) {\n const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i])\n const assetValueInNumeraire = isAssetToken0\n ? (assetBal * sqrtPriceX96 * sqrtPriceX96) / Q192\n : (assetBal * Q192) / (sqrtPriceX96 * sqrtPriceX96)\n totalValue[i] += assetValueInNumeraire + otherBal\n totalDelta[i] += assetBal\n }\n\n return {\n totalValue,\n totalDelta,\n totalGamma,\n positionCount: BigInt(positions.length),\n positions: positionResults,\n }\n}\n","/**\n * Margin buffer and distance-to-liquidation convenience function.\n *\n * Sources current and required margin directly from\n * `PanopticPool.getFullPositionsData` + `CollateralTracker.assetsOf`,\n * rather than `PanopticQuery.checkCollateral`.\n *\n * Why: `checkCollateral` returns a `currentMargin` already netted of the\n * borrowing obligation of width=0 short (\"loan\") tokenIds, and a\n * `requiredMargin` that does NOT include the loan's collateral requirement.\n * That makes buying-power usage read 0% for accounts whose collateral\n * comes mostly from a loan, and double-subtracts the loan from Net Liq\n * when downstream callers add the position MtM (which already values the\n * loan at `-notional`).\n *\n * `getFullPositionsData.collateralRequirements[]` attributes the loan as\n * a margin requirement (the accurate primitive), and `assetsOf` returns\n * the gross collateral (deposits + borrowed shares) — pairing them yields\n * a consistent gross-collateral / gross-requirement view.\n *\n * @module v2/reads/margin\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { tickToSqrtPriceX96 } from '../formatters/tick'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { type MulticallBlockCall, readBlockAndAggregate, requireReturnData } from './multicallBlock'\n\n// Sentinel ticks used by PanopticQuery to indicate \"no liquidation at this boundary\"\nconst MIN_TICK = -887272n\nconst MAX_TICK = 887272n\n\nconst FP96 = 1n << 96n\nconst Q128 = 1n << 128n\n\n/** Cap for a usage ratio with no collateral behind it. */\nconst MAX_USAGE_BPS = 1_000_000n\n\nconst bigintMax = (a: bigint, b: bigint): bigint => (a > b ? a : b)\nconst bigintMin = (a: bigint, b: bigint): bigint => (a < b ? a : b)\n\n/**\n * `RiskEngine.BP_DECREASE_BUFFER` over `PanopticPool.NO_BUFFER` — the extra\n * margin the solvency check demands at mint (and on collateral withdrawal),\n * above the maintenance requirement that governs liquidation.\n */\nconst MINT_BUFFER = 10_666_667n\nconst MINT_BUFFER_DENOMINATOR = 10_000_000n\n\n/**\n * Convert a token0 amount to its token1-equivalent at the given sqrtPriceX96.\n *\n * Matches the on-chain `PanopticMath.convert0to1` truncation, with an\n * overflow-safe branch when `sqrtPriceX96^2` would not fit in uint256.\n */\nfunction convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n // amount * (sqrtPriceX96 * sqrtPriceX96 >> 64n) >> 128n\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\n/**\n * Convert a token1 amount to its token0-equivalent at the given sqrtPriceX96.\n */\nfunction convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Parameters for {@link getMarginBuffer}.\n */\nexport interface GetMarginBufferParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions (loan/credit width=0 legs included) */\n tokenIds: bigint[]\n /** PanopticQuery address (required for liquidation prices) */\n queryAddress: Address\n /**\n * Optional pre-fetched collateral tracker addresses (saves an RPC).\n * If omitted, they are fetched from the pool.\n */\n collateralAddresses?: { collateralToken0: Address; collateralToken1: Address }\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n}\n\n/**\n * Margin buffer result with distance-to-liquidation.\n *\n * **Denomination**: Both slots are populated with the account total\n * cross-converted into a single token denomination so they can be\n * compared directly.\n *\n * - `currentMargin0` / `requiredMargin0` / `buffer0` are denominated in **token0**.\n * - `currentMargin1` / `requiredMargin1` / `buffer1` are denominated in **token1**.\n *\n * `denominatedInToken` indicates which of the two pairs is \"preferred\":\n * 0 when `currentTick < 0`, 1 otherwise — matching the historical\n * `checkCollateral` convention so downstream consumers keep working\n * without changes.\n */\nexport interface MarginBuffer {\n /** Excess margin in token0 units (positive = safe, negative = shortfall) */\n buffer0: bigint\n /** Excess margin in token1 units (positive = safe, negative = shortfall) */\n buffer1: bigint\n /** Buffer as percentage of required margin in bps (slot 0). null if no requirement. */\n bufferPercent0: bigint | null\n /** Buffer as percentage of required margin in bps (slot 1). null if no requirement. */\n bufferPercent1: bigint | null\n /** Current (gross) account collateral, denominated in token0 */\n currentMargin0: bigint\n /** Current (gross) account collateral, denominated in token1 */\n currentMargin1: bigint\n /**\n * Sum of per-position collateral requirements from\n * `getFullPositionsData.collateralRequirements[]`, denominated in token0.\n * Loans/credits (width=0) contribute correctly.\n */\n requiredMargin0: bigint\n /** Same, denominated in token1 */\n requiredMargin1: bigint\n /**\n * Which token the \"preferred\" margin values are denominated in.\n * 0 = token0 (when currentTick < 0), 1 = token1 (when currentTick >= 0).\n */\n denominatedInToken: 0 | 1\n /** Tick distance to nearest liquidation boundary (null if no liquidation boundaries) */\n liquidationDistance: bigint | null\n /** Lower liquidation tick (null if safe at MIN_TICK) */\n lowerLiquidationTick: bigint | null\n /** Upper liquidation tick (null if safe at MAX_TICK) */\n upperLiquidationTick: bigint | null\n /**\n * Collateral usage against the constraint that actually liquidates, in bps\n * (10000 = at the liquidation threshold). Null when the account holds no\n * positions.\n *\n * NOT `requiredMargin / currentMargin`. That ratio pools both collateral\n * tokens into one number, which silently assumes cross-collateral is credited\n * at 100%. It is only credited at `RiskEngine.crossBufferRatio(utilization,\n * CROSS_BUFFER_n)`, which decays linearly from the configured buffer to ZERO\n * between 90% and 95% pool utilization. Measured on mainnet with\n * CROSS_BUFFER = 100% and the token0 tracker at 91.98% utilization, only\n * 60.4% of the token0 surplus counted toward the token1 requirement — the\n * pooled ratio read 40% while this one read ~90% and liquidation was 8.7%\n * away.\n *\n * Sourced from `PanopticQuery.checkCollateral` at the current tick, which\n * applies the live cross-buffer, and reported for whichever token side is\n * tighter. Solvency requires both to hold.\n */\n crossMarginUsageBps: bigint | null\n /** Usage of the token0 side alone, in bps. Null when no positions. */\n usageBps0: bigint | null\n /** Usage of the token1 side alone, in bps. Null when no positions. */\n usageBps1: bigint | null\n /**\n * Collateral still deployable before the mint solvency check would fail,\n * in `denominatedInToken` units. Null when the account holds no positions.\n *\n * The tighter of `balance - required * BP_DECREASE_BUFFER` across the two\n * token sides, from `checkCollateral` at the current tick. NOT\n * `currentMargin - requiredMargin * buffer`, which pools both collateral\n * tokens and so credits cross-collateral at 100% regardless of the live\n * `crossBufferRatio`. On a mainnet account that pooled figure read ~24,000\n * USDC of headroom while the binding side had ~890 — and a mint requiring\n * ~2,700 USDC duly reverted with AccountInsolvent.\n */\n mintableMarginBinding: bigint | null\n /** Current tick */\n currentTick: bigint\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Get margin buffer and distance-to-liquidation for an account.\n *\n * Reads, all pinned to the same block:\n * - `getCurrentTick` (sequencing dependency for sqrtPrice conversion)\n * - `getFullPositionsData(account, true, tokenIds)` → collateralRequirements\n * - `CollateralTracker.assetsOf(account)` on both trackers → gross collateral\n * - `PanopticQuery.getLiquidationPrices(...)` → liquidation boundaries\n *\n * @param params - The parameters\n * @returns Margin buffer with liquidation distance and block metadata\n */\nexport async function getMarginBuffer(params: GetMarginBufferParams): Promise<MarginBuffer> {\n const { client, poolAddress, account, tokenIds, queryAddress, blockNumber } = params\n\n const targetBlockNumber =\n blockNumber ?? params._meta?.blockNumber ?? (await client.getBlockNumber())\n\n // Resolve collateral tracker addresses (immutable; cache-friendly).\n let collateralToken0: Address\n let collateralToken1: Address\n if (params.collateralAddresses) {\n collateralToken0 = params.collateralAddresses.collateralToken0\n collateralToken1 = params.collateralAddresses.collateralToken1\n } else {\n const addrs = await client.multicall({\n contracts: [\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken0' },\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken1' },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n })\n collateralToken0 = addrs[0]\n collateralToken1 = addrs[1]\n }\n\n const hasPositions = tokenIds.length > 0\n const calls: MulticallBlockCall[] = [\n {\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n }),\n },\n {\n target: collateralToken0,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n {\n target: collateralToken1,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n ]\n\n const positionDataIndex = hasPositions ? calls.length : null\n if (positionDataIndex !== null) {\n calls.push({\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, tokenIds],\n }),\n })\n }\n\n const liqPricesIndex = hasPositions ? calls.length : null\n if (liqPricesIndex !== null) {\n calls.push({\n target: queryAddress,\n callData: encodeFunctionData({\n abi: panopticQueryAbi,\n functionName: 'getLiquidationPrices',\n args: [poolAddress, account, tokenIds],\n }),\n })\n }\n\n // 3-arg overload: evaluates at (currentTick, fastOracleTick, slowOracleTick,\n // latestObservation) so it needs no tick input and fits this same multicall.\n // We read index 0 (currentTick) to stay consistent with the liquidation price\n // and the risk chart, which are also anchored there.\n const checkCollateralIndex = hasPositions ? calls.length : null\n if (checkCollateralIndex !== null) {\n calls.push({\n target: queryAddress,\n callData: encodeFunctionData({\n abi: panopticQueryAbi,\n functionName: 'checkCollateral',\n args: [poolAddress, account, tokenIds],\n }),\n })\n }\n\n const { _meta, results } = await readBlockAndAggregate({\n client,\n calls,\n blockNumber: targetBlockNumber,\n })\n\n const currentTickResult = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n data: requireReturnData(results, 0, 'PanopticPool.getCurrentTick'),\n })\n const currentTick = BigInt(currentTickResult)\n const assets0 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 1, 'CollateralTracker.assetsOf token0'),\n })\n const assets1 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 2, 'CollateralTracker.assetsOf token1'),\n })\n const positionDataResult =\n positionDataIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data: requireReturnData(results, positionDataIndex, 'PanopticPool.getFullPositionsData'),\n }) as readonly [bigint, bigint, readonly bigint[], readonly bigint[], readonly bigint[]])\n const liqPricesResult =\n liqPricesIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticQueryAbi,\n functionName: 'getLiquidationPrices',\n data: requireReturnData(results, liqPricesIndex, 'PanopticQuery.getLiquidationPrices'),\n }) as readonly [number, number])\n\n const checkCollateralResult =\n checkCollateralIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticQueryAbi,\n functionName: 'checkCollateral',\n data: requireReturnData(results, checkCollateralIndex, 'PanopticQuery.checkCollateral'),\n }) as readonly [readonly bigint[], readonly bigint[], readonly bigint[], readonly bigint[]])\n\n // Usage against the binding constraint, at the current tick (index 0).\n // checkCollateral has already applied the live cross-buffer, so this reflects\n // how much of the surplus in one token genuinely counts toward the other.\n let usageBps0: bigint | null = null\n let usageBps1: bigint | null = null\n let crossMarginUsageBps: bigint | null = null\n let mintableMarginBinding: bigint | null = null\n if (checkCollateralResult) {\n const [balances0, requireds0, balances1, requireds1] = checkCollateralResult\n const ratio = (required: bigint | undefined, balance: bigint | undefined): bigint | null => {\n if (required === undefined || balance === undefined) return null\n // No balance but a requirement is maximally used, not undefined.\n if (balance === 0n) return required > 0n ? MAX_USAGE_BPS : 0n\n return (required * 10_000n) / balance\n }\n usageBps0 = ratio(requireds0[0], balances0[0])\n usageBps1 = ratio(requireds1[0], balances1[0])\n if (usageBps0 !== null || usageBps1 !== null) {\n crossMarginUsageBps =\n usageBps0 === null\n ? usageBps1\n : usageBps1 === null\n ? usageBps0\n : bigintMax(usageBps0, usageBps1)\n }\n\n // Collateral still deployable before the mint solvency check would fail.\n // Per side: balance - required * mintBuffer, then the tighter of the two,\n // because the mint must satisfy BOTH. Both sides are already in\n // `denominatedInToken` units (checkCollateral branches on the same\n // sqrtPriceX96 < FP96 test), so the min is well defined.\n const mintable = (balance: bigint | undefined, required: bigint | undefined): bigint | null => {\n if (balance === undefined || required === undefined) return null\n const requiredAtMint =\n (required * MINT_BUFFER + MINT_BUFFER_DENOMINATOR - 1n) / MINT_BUFFER_DENOMINATOR\n return balance > requiredAtMint ? balance - requiredAtMint : 0n\n }\n const mintable0 = mintable(balances0[0], requireds0[0])\n const mintable1 = mintable(balances1[0], requireds1[0])\n if (mintable0 !== null || mintable1 !== null) {\n mintableMarginBinding =\n mintable0 === null\n ? mintable1\n : mintable1 === null\n ? mintable0\n : bigintMin(mintable0, mintable1)\n }\n }\n\n // Sum collateral requirements across all positions, per token.\n let required0Native = 0n\n let required1Native = 0n\n if (positionDataResult) {\n const collateralRequirements = positionDataResult[3]\n for (const packed of collateralRequirements) {\n const decoded = decodeLeftRightUnsigned(packed)\n required0Native += decoded.right // token0\n required1Native += decoded.left // token1\n }\n }\n\n // Cross-convert into a single denomination at current tick.\n // The conversion mirrors PanopticQuery.checkCollateral's effective-balance\n // shape so downstream callers keep their existing per-slot interpretation.\n const sqrtPriceX96 = tickToSqrtPriceX96(currentTick)\n const denominatedInToken: 0 | 1 = sqrtPriceX96 < FP96 ? 0 : 1\n\n // Token0-denominated totals\n const currentMargin0 = assets0 + convert1to0(assets1, sqrtPriceX96)\n const requiredMargin0 = required0Native + convert1to0(required1Native, sqrtPriceX96)\n // Token1-denominated totals\n const currentMargin1 = assets1 + convert0to1(assets0, sqrtPriceX96)\n const requiredMargin1 = required1Native + convert0to1(required0Native, sqrtPriceX96)\n\n const buffer0 = currentMargin0 - requiredMargin0\n const buffer1 = currentMargin1 - requiredMargin1\n const bufferPercent0 = requiredMargin0 === 0n ? null : (buffer0 * 10000n) / requiredMargin0\n const bufferPercent1 = requiredMargin1 === 0n ? null : (buffer1 * 10000n) / requiredMargin1\n\n // Liquidation prices: present only when the account has positions.\n let lowerLiquidationTick: bigint | null = null\n let upperLiquidationTick: bigint | null = null\n let liquidationDistance: bigint | null = null\n if (liqPricesResult) {\n const liqPriceDown = BigInt(liqPricesResult[0])\n const liqPriceUp = BigInt(liqPricesResult[1])\n lowerLiquidationTick = liqPriceDown === MIN_TICK ? null : liqPriceDown\n upperLiquidationTick = liqPriceUp === MAX_TICK ? null : liqPriceUp\n if (lowerLiquidationTick !== null && upperLiquidationTick !== null) {\n const distLower = currentTick - lowerLiquidationTick\n const distUpper = upperLiquidationTick - currentTick\n liquidationDistance = distLower < distUpper ? distLower : distUpper\n } else if (lowerLiquidationTick !== null) {\n liquidationDistance = currentTick - lowerLiquidationTick\n } else if (upperLiquidationTick !== null) {\n liquidationDistance = upperLiquidationTick - currentTick\n }\n }\n\n return {\n buffer0,\n buffer1,\n bufferPercent0,\n bufferPercent1,\n currentMargin0,\n currentMargin1,\n requiredMargin0,\n requiredMargin1,\n denominatedInToken,\n liquidationDistance,\n lowerLiquidationTick,\n upperLiquidationTick,\n crossMarginUsageBps,\n usageBps0,\n usageBps1,\n mintableMarginBinding,\n currentTick,\n _meta,\n }\n}\n","/**\n * Delta hedging utilities for the Panoptic v2 SDK.\n *\n * Provides functions to calculate loan parameters needed\n * to achieve a target delta for option positions.\n *\n * @module v2/reads/hedge\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticValidationError } from '../errors/sdk'\nimport { calculatePositionDelta } from '../greeks'\nimport { decodeTokenId } from '../tokenId'\nimport type { LegConfig } from '../tokenId/builder'\nimport type { BlockMeta } from '../types'\nimport { getPool } from './pool'\n\n/**\n * Parameters for getDeltaHedgeParams.\n */\nexport interface GetDeltaHedgeParamsInput {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Chain ID */\n chainId: bigint\n /**\n * TokenId of the option position to hedge.\n * Optional when both `currentDelta` and `asset` are provided (whole-portfolio hedging).\n */\n tokenId?: bigint\n /**\n * Position size in contracts.\n * Optional when both `currentDelta` and `asset` are provided.\n */\n positionSize?: bigint\n /** Target delta (WAD-scaled, 0n for delta-neutral) */\n targetDelta: bigint\n /** Optional: current delta if adjusting existing position (WAD-scaled) */\n currentDelta?: bigint\n /**\n * Primary asset index (0n or 1n). Used to determine hedge direction.\n * Required when `tokenId` is not provided; ignored when `tokenId` is provided.\n */\n asset?: bigint\n /** Optional: tick at mint (defaults to current tick if not provided) */\n mintTick?: bigint\n /** Optional: block number for historical queries */\n blockNumber?: bigint\n /** Optional: current tick (skips getPool() when both currentTick and tickSpacing are provided) */\n currentTick?: bigint\n /** Optional: pool tick spacing (skips getPool() when both currentTick and tickSpacing are provided) */\n tickSpacing?: bigint\n /** Optional pre-fetched block metadata (skips getBlockMeta RPC call) */\n _meta?: BlockMeta\n\n // --- Simulation convergence options ---\n\n /**\n * Simulate the hedge swap and return the post-swap tick.\n * When provided (along with `computeDeltaAtTick`), an iterative loop refines\n * the hedge size to account for AMM price impact.\n */\n simulateSwap?: (hedgeAmount: bigint, hedgeLeg: LegConfig) => Promise<{ tickAfter: bigint } | null>\n\n /**\n * Recompute portfolio delta at a given tick.\n * Required when `simulateSwap` is provided.\n */\n computeDeltaAtTick?: (tick: bigint) => bigint\n\n /** Total position size — used for convergence check (sizeDelta * 10000 / totalPositionSize) */\n totalPositionSize?: bigint\n\n /** Max simulation iterations (default 5) */\n maxSimIterations?: number\n\n /** Convergence threshold in bps (default 10). Loop stops when size change < this. */\n convergenceThresholdBps?: bigint\n}\n\n/**\n * Result of getDeltaHedgeParams.\n */\nexport interface DeltaHedgeResult {\n /** LegConfig to add to the position for hedging */\n hedgeLeg: LegConfig\n /** The hedge amount (in position size units) */\n hedgeAmount: bigint\n /** Always 'loan' — the tokenType determines the delta direction */\n hedgeType: 'loan' | 'credit'\n /** Whether the hedge position should be opened with swapAtMint */\n swapAtMint: boolean\n /** Current position delta (WAD-scaled) */\n currentDelta: bigint\n /** Target delta (WAD-scaled) */\n targetDelta: bigint\n /** Delta adjustment needed (WAD-scaled) */\n deltaAdjustment: bigint\n /** Block metadata */\n _meta: BlockMeta\n /** Number of simulation iterations used (0 if no simulateSwap) */\n simulationIterations: number\n /** Post-swap tick from final simulation (undefined if no simulation) */\n simulatedTickAfter?: bigint\n /** Whether the convergence loop converged within threshold */\n converged: boolean\n}\n\n/**\n * Calculate loan parameters to achieve target delta via swapAtMint.\n *\n * Both delta directions use loans with swapAtMint — the tokenType\n * determines whether delta is added or removed:\n *\n * - **Need positive delta** (e.g. hedging a short call):\n * Loan with tokenType = numeraire + swapAtMint.\n * Borrows numeraire (e.g. USDC), swaps to asset (e.g. ETH).\n * Net: +asset exposure → positive delta.\n *\n * - **Need negative delta** (e.g. hedging a short put):\n * Loan with tokenType = asset + swapAtMint.\n * Borrows asset (e.g. ETH), swaps to numeraire (e.g. USDC).\n * Net: −asset exposure → negative delta.\n *\n * ## Example: Delta-neutral short call\n * ```typescript\n * const hedge = await getDeltaHedgeParams({\n * client, poolAddress, chainId,\n * tokenId: shortCallTokenId,\n * positionSize: 1000000000000000n,\n * targetDelta: 0n,\n * })\n *\n * // Open the hedge as a separate position with swapAtMint\n * const hedgeTokenId = builder\n * .addLoan({ tokenType: hedge.hedgeLeg.tokenType, strike: hedge.hedgeLeg.strike })\n * .build()\n *\n * await openPosition({ ..., tokenId: hedgeTokenId,\n * positionSize: hedge.hedgeAmount, swapAtMint: hedge.swapAtMint })\n * ```\n *\n * @param params - The parameters\n * @returns Delta hedge result with LegConfig (always a loan)\n */\nexport async function getDeltaHedgeParams(\n params: GetDeltaHedgeParamsInput,\n): Promise<DeltaHedgeResult> {\n const {\n client,\n poolAddress,\n chainId,\n tokenId,\n positionSize,\n targetDelta,\n currentDelta: providedCurrentDelta,\n asset: providedAsset,\n mintTick: providedMintTick,\n blockNumber,\n currentTick: providedCurrentTick,\n tickSpacing: providedTickSpacing,\n } = params\n\n // Validate: need either tokenId or (currentDelta + asset)\n const hasTokenId = tokenId !== undefined\n const hasDirectDelta = providedCurrentDelta !== undefined && providedAsset !== undefined\n\n if (!hasTokenId && !hasDirectDelta) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams requires either `tokenId` or both `currentDelta` and `asset`',\n )\n }\n\n // Validate simulateSwap and computeDeltaAtTick are provided together\n if ((params.simulateSwap !== undefined) !== (params.computeDeltaAtTick !== undefined)) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams: simulateSwap and computeDeltaAtTick must be provided together',\n )\n }\n\n // If both currentTick and tickSpacing are provided, skip the full getPool() call\n let currentTick: bigint\n let tickSpacing: bigint\n let poolMeta: BlockMeta\n\n if (providedCurrentTick !== undefined && providedTickSpacing !== undefined) {\n currentTick = providedCurrentTick\n tickSpacing = providedTickSpacing\n poolMeta =\n params._meta ??\n (await getBlockMeta({ client, blockNumber: blockNumber ?? (await client.getBlockNumber()) }))\n } else {\n const pool = await getPool({\n client,\n poolAddress,\n chainId,\n blockNumber,\n })\n currentTick = pool.currentTick\n tickSpacing = pool.tickSpacing\n poolMeta = pool._meta\n }\n\n // Determine primary asset and current delta\n let primaryAsset: bigint\n let currentDelta: bigint\n\n if (hasTokenId) {\n // Decode the tokenId to get legs\n const decoded = decodeTokenId(tokenId)\n primaryAsset = decoded.legs.length > 0 ? decoded.legs[0].asset : 0n\n\n // Use provided mintTick or default to currentTick\n const mintTick = providedMintTick ?? currentTick\n\n // Calculate position delta if not provided\n currentDelta =\n providedCurrentDelta ??\n calculatePositionDelta({\n legs: decoded.legs,\n currentTick,\n mintTick,\n positionSize: positionSize!,\n poolTickSpacing: tickSpacing,\n })\n } else {\n // Direct delta + asset mode (whole-portfolio hedging)\n if (providedAsset !== 0n && providedAsset !== 1n) {\n throw new PanopticValidationError(\n `getDeltaHedgeParams: asset must be 0n or 1n, got ${providedAsset}`,\n )\n }\n primaryAsset = providedAsset\n currentDelta = providedCurrentDelta!\n }\n\n // deltaAdjustment = targetDelta - currentDelta\n // Positive → need to add positive delta; Negative → need to add negative delta.\n const deltaAdjustment = targetDelta - currentDelta\n\n // Delta is in asset smallest units. A loan+swapAtMint of size X gives\n // effective delta ≈ ±X (in asset smallest units). So hedgeAmount = |deltaAdjustment|.\n const absDeltaAdjustment = deltaAdjustment < 0n ? -deltaAdjustment : deltaAdjustment\n let hedgeAmount = absDeltaAdjustment\n\n const numeraire = primaryAsset === 0n ? 1n : 0n\n\n // Both directions use a loan + swapAtMint. The tokenType determines direction:\n // deltaAdjustment > 0 (need +delta): loan numeraire → swap to asset → +asset exposure\n // deltaAdjustment < 0 (need −delta): loan asset → swap to numeraire → −asset exposure\n const needPositiveDelta = deltaAdjustment > 0n\n const hedgeTokenType = needPositiveDelta ? numeraire : primaryAsset\n\n const hedgeLeg: LegConfig = {\n asset: primaryAsset,\n optionRatio: 1n,\n isLong: false, // Always a loan\n tokenType: hedgeTokenType,\n strike: (currentTick / tickSpacing) * tickSpacing, // Round to tick spacing\n width: 0n, // Loan/credit indicator\n }\n\n // --- Simulation convergence loop ---\n const {\n simulateSwap,\n computeDeltaAtTick,\n totalPositionSize,\n maxSimIterations = 5,\n convergenceThresholdBps = 10n,\n } = params\n\n let simulationIterations = 0\n let simulatedTickAfter: bigint | undefined\n let converged = true\n\n if (simulateSwap && computeDeltaAtTick) {\n if (totalPositionSize === undefined || totalPositionSize === 0n) {\n throw new PanopticValidationError(\n 'getDeltaHedgeParams: totalPositionSize is required and must be > 0 when simulateSwap is provided',\n )\n }\n\n converged = false\n\n for (let i = 0; i < maxSimIterations; i++) {\n simulationIterations = i + 1\n\n const simResult = await simulateSwap(hedgeAmount, hedgeLeg)\n if (simResult == null) break\n\n simulatedTickAfter = simResult.tickAfter\n\n // Recompute portfolio delta at the post-swap tick\n const adjustedDelta = computeDeltaAtTick(simResult.tickAfter)\n const newAdjustment = targetDelta - adjustedDelta\n const newAmount = newAdjustment < 0n ? -newAdjustment : newAdjustment\n\n // Convergence check\n const sizeDelta = newAmount > hedgeAmount ? newAmount - hedgeAmount : hedgeAmount - newAmount\n const sizeChangeBps = (sizeDelta * 10000n) / totalPositionSize\n\n hedgeAmount = newAmount\n\n if (sizeChangeBps <= convergenceThresholdBps || sizeDelta === 0n) {\n converged = true\n break\n }\n }\n }\n\n return {\n hedgeLeg,\n hedgeAmount,\n hedgeType: 'loan',\n swapAtMint: true,\n currentDelta,\n targetDelta,\n deltaAdjustment,\n _meta: poolMeta,\n simulationIterations,\n simulatedTickAfter,\n converged,\n }\n}\n","/**\n * Collateral share price read for the Panoptic v2 SDK.\n *\n * Reads totalAssets and totalSupply from two CollateralTracker contracts\n * to compute share prices. Designed for APY calculations at historical blocks.\n *\n * @module v2/reads/collateralSharePrice\n */\n\nimport type { Address, Client } from 'viem'\nimport { ContractFunctionExecutionError } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\n\n/**\n * Raw share price data for a single collateral tracker.\n */\nexport interface CollateralSharePriceData {\n totalAssets: bigint\n totalSupply: bigint\n}\n\n/**\n * Get totalAssets and totalSupply for two CollateralTracker contracts in a single multicall.\n *\n * Consumers can compute share price as `totalAssets / totalSupply` using their\n * preferred precision library (e.g. Decimal.js).\n *\n * If the collateral tracker reverts (e.g. uninitialized), returns zeros.\n *\n * @param collateralAddresses - Tuple of [token0 tracker, token1 tracker] addresses\n * @param blockNumber - Block number to query at\n * @param client - viem Client\n * @returns Tuple of raw share price data\n */\nexport async function getCollateralSharePrices(\n collateralAddresses: [Address, Address],\n blockNumber: bigint,\n client: Client,\n): Promise<[CollateralSharePriceData, CollateralSharePriceData]> {\n try {\n const results = await multicall(client, {\n contracts: [\n {\n address: collateralAddresses[0],\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets',\n },\n {\n address: collateralAddresses[0],\n abi: collateralTrackerV2Abi,\n functionName: 'totalSupply',\n },\n {\n address: collateralAddresses[1],\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets',\n },\n {\n address: collateralAddresses[1],\n abi: collateralTrackerV2Abi,\n functionName: 'totalSupply',\n },\n ],\n blockNumber,\n allowFailure: false,\n })\n\n const [assets0, supply0, assets1, supply1] = results\n\n return [\n { totalAssets: assets0, totalSupply: supply0 },\n { totalAssets: assets1, totalSupply: supply1 },\n ]\n } catch (e: unknown) {\n if (e instanceof ContractFunctionExecutionError) {\n return [\n { totalAssets: 0n, totalSupply: 0n },\n { totalAssets: 0n, totalSupply: 0n },\n ]\n }\n throw e\n }\n}\n","/**\n * Batch read of CollateralTracker.totalAssets() for multiple trackers.\n *\n * @module v2/reads/collateralTotalAssets\n */\n\nimport type { Address, Client } from 'viem'\nimport { getAddress, zeroAddress } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\n\n/**\n * Get totalAssets for multiple CollateralTracker contracts in a single multicall.\n *\n * @param client - viem Client\n * @param collateralTrackerAddresses - Array of CollateralTracker addresses\n * @param chainId - Chain ID (for multicall routing)\n * @param blockNumber - Optional block number for historical queries\n * @returns Array of totalAssets (bigint) in the same order as input addresses\n */\nexport async function getCollateralTotalAssetsBatch(\n client: Client,\n collateralTrackerAddresses: Address[],\n chainId: number,\n blockNumber?: bigint,\n): Promise<bigint[]> {\n if (collateralTrackerAddresses.length === 0) return []\n\n try {\n const contracts = collateralTrackerAddresses.map((address) => ({\n address: getAddress(address ?? zeroAddress),\n abi: collateralTrackerV2Abi,\n functionName: 'totalAssets' as const,\n chainId,\n }))\n\n const results = await multicall(client, {\n contracts,\n blockNumber,\n allowFailure: false,\n })\n\n return results.map((result) => BigInt(result ?? 0))\n } catch (error) {\n console.error('Error reading collateral total assets:', error)\n return collateralTrackerAddresses.map(() => 0n)\n }\n}\n","/**\n * Account buying power read function for the Panoptic v2 SDK.\n *\n * Sources gross collateral from `CollateralTracker.assetsOf` and per-position\n * required margin from `PanopticPool.getFullPositionsData.collateralRequirements[]`,\n * cross-converted to both token denominations at the current tick.\n *\n * This replaces the prior `PanopticQuery.checkCollateral` (3-arg, oracle-ticks\n * overload) implementation that netted loan tokenId debt out of the balance\n * and excluded loans from required-collateral, causing buying-power readouts\n * to be wildly wrong for any account that had borrowed.\n *\n * @module v2/reads/buyingPower\n */\n\nimport type { Address, Client } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\nimport { multicall } from 'viem/actions'\n\nimport { collateralTrackerV2Abi, panopticPoolV2Abi } from '../../../generated'\nimport { tickToSqrtPriceX96 } from '../formatters/tick'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { type MulticallBlockCall, readBlockAndAggregate, requireReturnData } from './multicallBlock'\n\nconst Q128 = 1n << 128n\n\nfunction convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\nfunction convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Parameters for getAccountBuyingPower.\n */\nexport interface GetAccountBuyingPowerParams {\n /** viem Client (PublicClient or basic Client with transport) */\n client: Client\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** TokenIds of open positions */\n tokenIds: bigint[]\n /** PanopticQuery address (kept for backwards compatibility; unused). */\n queryAddress?: Address\n /**\n * Optional pre-fetched collateral tracker addresses (saves an RPC).\n * If omitted, they are fetched from the pool.\n */\n collateralAddresses?: { collateralToken0: Address; collateralToken1: Address }\n /** Optional block number for historical queries */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata (skips block metadata fetch) */\n _meta?: BlockMeta\n}\n\n/**\n * Result of getAccountBuyingPower.\n *\n * Both per-token values are the **gross** account total cross-converted\n * into the respective single-token denomination at the current tick:\n * - `collateralBalance0` / `requiredCollateral0` are in token0 units\n * - `collateralBalance1` / `requiredCollateral1` are in token1 units\n */\nexport interface AccountBuyingPower {\n /** Gross collateral (deposits + borrowed shares), denominated in token0 */\n collateralBalance0: bigint\n /** Sum of per-position collateral requirements, denominated in token0 */\n requiredCollateral0: bigint\n /** Gross collateral (deposits + borrowed shares), denominated in token1 */\n collateralBalance1: bigint\n /** Sum of per-position collateral requirements, denominated in token1 */\n requiredCollateral1: bigint\n /** Block metadata for the Multicall3 aggregate read */\n _meta: BlockMeta\n}\n\n/**\n * Get account-level buying power.\n *\n * Uses {@link https://github.com/panoptic-xyz CollateralTracker.assetsOf} for\n * gross collateral and `PanopticPool.getFullPositionsData.collateralRequirements[]`\n * for the per-position required margin — so loan tokenIds (width=0 shorts)\n * contribute to the requirement instead of being netted out of the balance.\n *\n * Accepts a plain viem `Client` (not just `PublicClient`) so it works with wagmi's\n * `useClient()` without needing a cast.\n *\n * @param params - The parameters\n * @returns Account buying power data with optional block metadata\n */\nexport async function getAccountBuyingPower(\n params: GetAccountBuyingPowerParams,\n): Promise<AccountBuyingPower> {\n const { client, poolAddress, account, tokenIds } = params\n const blockNumber = params.blockNumber ?? params._meta?.blockNumber\n\n // Resolve collateral tracker addresses (immutable; cache-friendly).\n let collateralToken0: Address\n let collateralToken1: Address\n if (params.collateralAddresses) {\n collateralToken0 = params.collateralAddresses.collateralToken0\n collateralToken1 = params.collateralAddresses.collateralToken1\n } else {\n const addrs = await multicall(client, {\n contracts: [\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken0' },\n { address: poolAddress, abi: panopticPoolV2Abi, functionName: 'collateralToken1' },\n ],\n blockNumber,\n allowFailure: false,\n })\n collateralToken0 = addrs[0]\n collateralToken1 = addrs[1]\n }\n\n const calls: MulticallBlockCall[] = [\n {\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n }),\n },\n {\n target: collateralToken0,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n {\n target: collateralToken1,\n callData: encodeFunctionData({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n }),\n },\n ]\n\n const positionDataIndex = tokenIds.length > 0 ? calls.length : null\n if (positionDataIndex !== null) {\n calls.push({\n target: poolAddress,\n callData: encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, tokenIds],\n }),\n })\n }\n\n const { _meta, results } = await readBlockAndAggregate({ client, calls, blockNumber })\n\n const currentTickResult = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n data: requireReturnData(results, 0, 'PanopticPool.getCurrentTick'),\n })\n const assets0 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 1, 'CollateralTracker.assetsOf token0'),\n })\n const assets1 = decodeFunctionResult({\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n data: requireReturnData(results, 2, 'CollateralTracker.assetsOf token1'),\n })\n const currentTick = BigInt(currentTickResult)\n const positionDataResult =\n positionDataIndex === null\n ? null\n : (decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data: requireReturnData(results, positionDataIndex, 'PanopticPool.getFullPositionsData'),\n }) as readonly [bigint, bigint, readonly bigint[], readonly bigint[], readonly bigint[]])\n\n // Sum collateral requirements across positions, per token.\n let required0Native = 0n\n let required1Native = 0n\n if (positionDataResult) {\n const collateralRequirements = positionDataResult[3]\n for (const packed of collateralRequirements) {\n const decoded = decodeLeftRightUnsigned(packed)\n required0Native += decoded.right // token0\n required1Native += decoded.left // token1\n }\n }\n\n // Cross-convert into each single-token denomination at current tick.\n const sqrtPriceX96 = tickToSqrtPriceX96(currentTick)\n const collateralBalance0 = assets0 + convert1to0(assets1, sqrtPriceX96)\n const requiredCollateral0 = required0Native + convert1to0(required1Native, sqrtPriceX96)\n const collateralBalance1 = assets1 + convert0to1(assets0, sqrtPriceX96)\n const requiredCollateral1 = required1Native + convert0to1(required0Native, sqrtPriceX96)\n\n return {\n collateralBalance0,\n requiredCollateral0,\n collateralBalance1,\n requiredCollateral1,\n _meta,\n }\n}\n","/**\n * Shared construction for dispatches wrapped in a temporary width=0 **credit**\n * leg, used to move token flow from one collateral token to the other inside a\n * single `dispatch()`.\n *\n * A credit rather than a loan: a credit pays into the pool instead of borrowing\n * from it, so it requires zero buying power, never touches `s_assetsInAMM`, and\n * can never be capped by a collateral tracker's utilization.\n *\n * @module v2/simulations/creditWrap\n */\n\nimport type { BatchDispatchArgs } from '../batch/types'\nimport type { TickAndSpreadLimits } from '../writes/position'\n\n/**\n * Pre-encoded `dispatch()` arguments a credit wrap is applied to.\n *\n * Alias of {@link BatchDispatchArgs} — the two are the same concept.\n */\nexport type DispatchIntent = BatchDispatchArgs\n\n/**\n * Which side of the swap is exact.\n *\n * - `exact-out`: the credit **sources** a known amount of its token, paying a\n * swapped amount of the counter-token. Mint carries `swapAtMint=true`.\n * - `exact-in`: the credit **sells** a known amount of its token, receiving a\n * swapped amount of the counter-token. Burn carries `swapAtMint=true`.\n */\nexport type CreditWrapDirection = 'exact-in' | 'exact-out'\n\n/**\n * Where the two credit legs sit relative to the user's own operations.\n *\n * - `straddle`: mint first, user ops, burn last. Required for `exact-out`, where\n * the sourced token must be available while the user's ops run.\n * - `append`: both legs after the user's ops. Required for `exact-in`, where the\n * token being sold does not exist until those ops have run.\n */\nexport type CreditWrapPlacement = 'append' | 'straddle'\n\nexport interface BuildCreditWrappedDispatchParams {\n dispatch: DispatchIntent\n /** The temporary width=0 credit leg. */\n creditTokenId: bigint\n /** Size of the mint leg. The burn leg always passes `0n` (= burn all). */\n creditPositionSize: bigint\n tickLimitLow: bigint\n tickLimitHigh: bigint\n direction: CreditWrapDirection\n placement: CreditWrapPlacement\n}\n\n/**\n * Wrap a dispatch with a temporary credit leg that is opened and closed in the\n * same transaction, netting to a swap.\n *\n * `swapAtMint` is not a calldata flag — it is the ORDER of the tick-limit pair:\n * descending `[high, low]` turns the swap on, ascending `[low, high]` leaves it\n * off. Exactly one of the two legs carries it, and which one is what makes the\n * swap exact-in vs exact-out.\n */\nexport function buildCreditWrappedDispatch(\n params: BuildCreditWrappedDispatchParams,\n): DispatchIntent {\n const { dispatch, creditTokenId, creditPositionSize, direction, placement } = params\n const low =\n params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitLow : params.tickLimitHigh\n const high =\n params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitHigh : params.tickLimitLow\n\n const swapping: TickAndSpreadLimits = [high, low, 0n]\n const notSwapping: TickAndSpreadLimits = [low, high, 0n]\n const mintLimits = direction === 'exact-out' ? swapping : notSwapping\n const burnLimits = direction === 'exact-out' ? notSwapping : swapping\n\n const wrapped: DispatchIntent = {\n positionIdList:\n placement === 'straddle'\n ? [creditTokenId, ...dispatch.positionIdList, creditTokenId]\n : [...dispatch.positionIdList, creditTokenId, creditTokenId],\n finalPositionIdList: [...dispatch.finalPositionIdList],\n positionSizes:\n placement === 'straddle'\n ? [creditPositionSize, ...dispatch.positionSizes, 0n]\n : [...dispatch.positionSizes, creditPositionSize, 0n],\n tickAndSpreadLimits:\n placement === 'straddle'\n ? [mintLimits, ...dispatch.tickAndSpreadLimits, burnLimits]\n : [...dispatch.tickAndSpreadLimits, mintLimits, burnLimits],\n usePremiaAsCollateral: dispatch.usePremiaAsCollateral,\n builderCode: dispatch.builderCode,\n }\n return wrapped\n}\n","/**\n * Dispatch simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateDispatch\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { DispatchSimulation, SimulationResult, TokenFlow } from '../types'\nimport type { TickAndSpreadLimits } from '../writes/position'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating dispatch.\n */\nexport interface SimulateDispatchParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /**\n * Operation list passed to `dispatch()` — one tokenId per batch item, in\n * operation order. Mints reference NEW tokenIds the user doesn't yet own,\n * so this list is NOT safe to read against pre-dispatch storage.\n */\n positionIdList: bigint[]\n /** Final position ID list after operations */\n finalPositionIdList: bigint[]\n /**\n * The user's actual on-chain `positionIdList` BEFORE dispatch. Required to\n * populate `preMarginExcess0/1` (read via a pre-dispatch\n * `getFullPositionsData` chained in the same multicall). When omitted,\n * `preMarginExcess0/1` are returned as `null`.\n */\n existingPositionIdList?: bigint[]\n /** Position sizes for each operation */\n positionSizes: bigint[]\n /** Tick and spread limits for each operation */\n tickAndSpreadLimits: TickAndSpreadLimits[]\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Builder code */\n builderCode?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a raw dispatch operation.\n *\n * Uses PanopticPool.multicall with getAssetsOf-dispatch-getAssetsOf pattern\n * to measure exact collateral asset movements.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with dispatch data or error\n */\nexport async function simulateDispatch(\n params: SimulateDispatchParams,\n): Promise<SimulationResult<DispatchSimulation>> {\n const {\n client,\n poolAddress,\n account,\n positionIdList,\n finalPositionIdList,\n positionSizes,\n tickAndSpreadLimits,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n existingPositionIdList,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Encode dispatch call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n positionIdList,\n finalPositionIdList,\n positionSizes,\n tickAndSpreadLimits.map(\n (t) => [Number(t[0]), Number(t[1]), Number(t[2])] as readonly [number, number, number],\n ),\n usePremiaAsCollateral,\n builderCode,\n ],\n })\n\n // Encode getFullPositionsData against the pre-dispatch (caller-supplied\n // existing list) and post-dispatch (finalPositionIdList) position lists.\n // Running both in the same multicall — pre-call before dispatch, post-call\n // after — lets the simulation report margin excess (= assets - required\n // collateral) on both sides atomically. Required collateral is summed\n // across the per-position LeftRightUnsigned entries.\n //\n // The pre-call uses `existingPositionIdList` (the user's actual storage\n // list), NOT `positionIdList` (the operation list, which contains\n // not-yet-minted tokenIds and would revert with PositionNotOwned).\n const preFullPositionsCallData =\n existingPositionIdList !== undefined\n ? encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, existingPositionIdList],\n })\n : undefined\n const postFullPositionsCallData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, finalPositionIdList],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n preCallData: preFullPositionsCallData ? [preFullPositionsCallData] : undefined,\n postCallData: [postFullPositionsCallData],\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Determine which positions were created/closed by diffing the post-dispatch\n // list against the pre-dispatch on-chain snapshot. `positionIdList` is the\n // operation list (which contains not-yet-minted tokenIds and excludes\n // unaffected pre-existing ones), so it can't be used as the \"before\" set.\n const preSnapshot = existingPositionIdList ?? []\n const positionsCreated = finalPositionIdList.filter((id) => !preSnapshot.includes(id))\n const positionsClosed = preSnapshot.filter((id) => !finalPositionIdList.includes(id))\n\n // Sum collateralRequirements across all entries from one\n // getFullPositionsData multicall slot. Each entry is a LeftRightUnsigned\n // packed as right=token0, left=token1. Returns null on decode failure so\n // callers fall back gracefully (the type is bigint | null).\n const sumCollateralReq = (data: Hex | undefined): { token0: bigint; token1: bigint } | null => {\n if (!data) return null\n try {\n const decoded = decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data,\n })\n const reqs = decoded[3] // collateralRequirements\n let token0 = 0n\n let token1 = 0n\n for (const packed of reqs) {\n const r = decodeLeftRightUnsigned(packed)\n token0 += r.right\n token1 += r.left\n }\n return { token0, token1 }\n } catch {\n return null\n }\n }\n\n const preReq = sumCollateralReq(flowResult.preCallResults?.[0])\n const postReq = sumCollateralReq(flowResult.postCallResults?.[0])\n\n const _meta = await metaPromise\n\n // Build simulation result with actual token flow data\n const data: DispatchSimulation = {\n netAmount0: tokenFlow.delta0,\n netAmount1: tokenFlow.delta1,\n positionsCreated,\n positionsClosed,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n preMarginExcess0: preReq ? tokenFlow.balanceBefore0 - preReq.token0 : null,\n preMarginExcess1: preReq ? tokenFlow.balanceBefore1 - preReq.token1 : null,\n postMarginExcess0: postReq ? tokenFlow.balanceAfter0 - postReq.token0 : null,\n postMarginExcess1: postReq ? tokenFlow.balanceAfter1 - postReq.token1 : null,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","import type { Address, PublicClient } from 'viem'\n\nimport { NotEnoughTokensError, PanopticError, parsePanopticError } from '../errors'\nimport { getPool } from '../reads/pool'\nimport type { BlockMeta, DispatchSimulation, SimulationResult, TokenFlow } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport { buildUniqueCredit } from '../writes/loanUtils'\nimport { type DispatchIntent, buildCreditWrappedDispatch } from './creditWrap'\nimport { simulateDispatch } from './simulateDispatch'\n\nconst BPS_DENOMINATOR = 10_000n\nconst MAX_RECOVERY_QUOTE_ATTEMPTS = 8\n\nexport type { DispatchIntent }\n\nexport interface TokenShortfallRecoveryQuoteParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n chainId: bigint\n existingPositionIds: bigint[]\n dispatch: DispatchIntent\n error: unknown\n /**\n * Slippage tolerance for the recovery swap, in **basis points** (1% = 100).\n * Applied to `estimatedAmountIn` to produce `maximumAmountIn`.\n * Values above `10_000` (100%) are rejected as `invalid-slippage`.\n */\n slippageBps: bigint\n /**\n * Price bound for the temporary credit legs. Defaults to the full tick range —\n * the recovery swap is protected economically by `maximumAmountIn`, not by a\n * price band, and the user's own operations keep their own limits.\n */\n tickLimitLow?: bigint\n /** See {@link TokenShortfallRecoveryQuoteParams.tickLimitLow}. */\n tickLimitHigh?: bigint\n blockNumber?: bigint\n}\n\nexport interface TokenShortfallRecoveryQuote {\n tokenIn: Address\n tokenOut: Address\n /**\n * Exact amount of `tokenOut` the temporary credit sources. Covers the whole\n * dispatch, not just the first charge that reverted — a batch charges\n * commission/premia per operation, so the total needed is usually larger\n * than the `assetsRequested - assetBalance` of the first failure.\n */\n amountOut: bigint\n estimatedAmountIn: bigint\n maximumAmountIn: bigint\n slippageBps: bigint\n /**\n * Signed net change of `tokenIn` across the ENTIRE wrapped transaction —\n * the user's own operations plus the recovery swap. This is what a wallet\n * simulation shows, and it is not the same as `-estimatedAmountIn`, which\n * prices the swap leg alone.\n */\n netTokenInChange: bigint\n /** Signed net change of `tokenOut` across the entire wrapped transaction. */\n netTokenOutChange: bigint\n /** The temporary width=0 credit leg used to source the shortfall. */\n creditTokenId: bigint\n dispatch: DispatchIntent\n simulation: SimulationResult<DispatchSimulation> & { success: true }\n tokenFlow: TokenFlow\n _meta: BlockMeta\n}\n\nexport type TokenShortfallRecoveryUnavailableReason =\n | 'not-token-shortfall'\n | 'invalid-shortfall'\n | 'invalid-slippage'\n | 'unsupported-token'\n | 'invalid-tick-limits'\n | 'swap-unavailable'\n | 'recovery-unavailable'\n\nexport type TokenShortfallRecoveryResult =\n | { available: true; quote: TokenShortfallRecoveryQuote }\n | {\n available: false\n reason: TokenShortfallRecoveryUnavailableReason\n /** Human-readable description of the sub-step that failed, for diagnostics. */\n detail?: string\n error?: PanopticError\n }\n\nexport interface BuildTokenShortfallRecoveryDispatchParams {\n dispatch: DispatchIntent\n /** The temporary width=0 credit leg that sources the missing token. */\n creditTokenId: bigint\n creditPositionSize: bigint\n tickLimitLow: bigint\n tickLimitHigh: bigint\n}\n\n/**\n * Wrap a dispatch with a temporary credit leg that sources the shortfall.\n *\n * Exact-output construction: mint the credit with `swapAtMint=true` (paying a\n * swapped amount of the token the account has), run the user's operations, then\n * burn it with `swapAtMint=false` to receive exactly the missing token.\n *\n * A credit rather than a loan so the recovery is never capped by the shortfall\n * token's utilization — the case that fails today on a >94% utilized tracker.\n */\nexport function buildTokenShortfallRecoveryDispatch(\n params: BuildTokenShortfallRecoveryDispatchParams,\n): DispatchIntent {\n return buildCreditWrappedDispatch({ ...params, direction: 'exact-out', placement: 'straddle' })\n}\n\n/**\n * Extract a fully-decoded `NotEnoughTokens` revert from an arbitrary error.\n *\n * Returns `null` when the error is something else, or when only the 4-byte\n * selector could be matched (the parser's fallback path constructs the error\n * with undefined args, which is not actionable).\n */\nexport function getNotEnoughTokensError(error: unknown): NotEnoughTokensError | null {\n let candidate: NotEnoughTokensError | null = null\n if (error instanceof NotEnoughTokensError) {\n candidate = error\n } else {\n const parsed = parsePanopticError(error)\n if (parsed?.error instanceof NotEnoughTokensError) candidate = parsed.error\n }\n if (candidate === null) return null\n // Selector-only decodes yield undefined args at runtime despite the types.\n const args: Partial<\n Pick<NotEnoughTokensError, 'tokenAddress' | 'assetsRequested' | 'assetBalance'>\n > = candidate\n if (\n args.tokenAddress === undefined ||\n args.assetsRequested === undefined ||\n args.assetBalance === undefined\n ) {\n return null\n }\n return candidate\n}\n\nfunction maximumAmountIn(estimatedAmountIn: bigint, slippageBps: bigint): bigint {\n if (slippageBps < 0n) {\n throw new PanopticError('slippageBps must be non-negative')\n }\n return (\n (estimatedAmountIn * (BPS_DENOMINATOR + slippageBps) + BPS_DENOMINATOR - 1n) / BPS_DENOMINATOR\n )\n}\n\nfunction getInputAmount(tokenFlow: TokenFlow, tokenInIndex: 0n | 1n): bigint {\n const delta = tokenInIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n return delta < 0n ? -delta : delta\n}\n\nfunction getBalanceBefore(tokenFlow: TokenFlow, tokenIndex: 0n | 1n): bigint {\n return tokenIndex === 0n ? tokenFlow.balanceBefore0 : tokenFlow.balanceBefore1\n}\n\nfunction getOutputAmount(tokenFlow: TokenFlow, tokenOutIndex: 0n | 1n): bigint {\n const delta = tokenOutIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n return delta > 0n ? delta : 0n\n}\n\nexport async function quoteTokenShortfallRecovery(\n params: TokenShortfallRecoveryQuoteParams,\n): Promise<TokenShortfallRecoveryResult> {\n const shortfallError = getNotEnoughTokensError(params.error)\n if (shortfallError === null) {\n return { available: false, reason: 'not-token-shortfall' }\n }\n\n let amountOut = shortfallError.assetsRequested - shortfallError.assetBalance\n if (amountOut <= 0n) {\n return {\n available: false,\n reason: 'invalid-shortfall',\n detail: `requested=${shortfallError.assetsRequested} <= balance=${shortfallError.assetBalance}`,\n }\n }\n if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR) {\n return {\n available: false,\n reason: 'invalid-slippage',\n detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR}]`,\n }\n }\n // The credit legs default to the full tick range: the swap is bounded\n // economically by maximumAmountIn, and the user's own ops keep their limits.\n const tickLimitLow = params.tickLimitLow ?? MIN_TICK\n const tickLimitHigh = params.tickLimitHigh ?? MAX_TICK\n if (tickLimitLow >= tickLimitHigh) {\n return {\n available: false,\n reason: 'invalid-tick-limits',\n detail: `tickLimitLow=${tickLimitLow} >= tickLimitHigh=${tickLimitHigh}`,\n }\n }\n\n const targetBlockNumber = params.blockNumber ?? (await params.client.getBlockNumber())\n const pool = await getPool({\n client: params.client,\n poolAddress: params.poolAddress,\n chainId: params.chainId,\n blockNumber: targetBlockNumber,\n })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const normalizedShortfallToken = shortfallError.tokenAddress.toLowerCase()\n const isToken0Shortfall =\n normalizedShortfallToken === token0.toLowerCase() ||\n normalizedShortfallToken === pool.collateralTracker0.address.toLowerCase()\n const isToken1Shortfall =\n normalizedShortfallToken === token1.toLowerCase() ||\n normalizedShortfallToken === pool.collateralTracker1.address.toLowerCase()\n const tokenOutIndex = isToken0Shortfall ? 0n : isToken1Shortfall ? 1n : null\n if (tokenOutIndex === null) {\n return {\n available: false,\n reason: 'unsupported-token',\n detail: `${shortfallError.tokenAddress} is neither collateral token of ${params.poolAddress}`,\n }\n }\n\n const tokenInIndex = tokenOutIndex === 0n ? 1n : 0n\n const tokenOut = tokenOutIndex === 0n ? token0 : token1\n const tokenIn = tokenInIndex === 0n ? token0 : token1\n const collisionIds = Array.from(\n new Set([\n ...params.existingPositionIds,\n ...params.dispatch.positionIdList,\n ...params.dispatch.finalPositionIdList,\n ]),\n )\n for (let attempt = 0; attempt < MAX_RECOVERY_QUOTE_ATTEMPTS; attempt++) {\n // asset === tokenType === tokenOutIndex: the credit is denominated in the\n // token being sourced. Passing tokenInIndex as tokenType is the loan\n // convention and reverses the flow (pays the shortfall token instead of\n // receiving it).\n const credit = buildUniqueCredit(\n pool.poolId,\n tokenOutIndex,\n tokenOutIndex,\n pool.currentTick,\n pool.tickSpacing,\n collisionIds,\n amountOut,\n )\n const recoveredDispatch = buildTokenShortfallRecoveryDispatch({\n dispatch: params.dispatch,\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n })\n const swapDispatch = buildTokenShortfallRecoveryDispatch({\n dispatch: {\n positionIdList: [],\n finalPositionIdList: [...params.existingPositionIds],\n positionSizes: [],\n tickAndSpreadLimits: [],\n usePremiaAsCollateral: false,\n builderCode: 0n,\n },\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n })\n\n const swapSimulation = await simulateDispatch({\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n ...swapDispatch,\n blockNumber: targetBlockNumber,\n })\n if (!swapSimulation.success || swapSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: swapSimulation.success\n ? 'swap-only simulation returned no token flow'\n : `swap-only simulation reverted: ${swapSimulation.error.message}`,\n error: swapSimulation.success ? undefined : swapSimulation.error,\n }\n }\n const estimatedAmountIn = getInputAmount(swapSimulation.tokenFlow, tokenInIndex)\n const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps)\n const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex)\n const sourceBalance = getBalanceBefore(swapSimulation.tokenFlow, tokenInIndex)\n if (swapOutput < amountOut || sourceBalance < maxAmountIn) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail:\n swapOutput < amountOut\n ? `swap output ${swapOutput} < required ${amountOut}`\n : `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,\n error: new PanopticError('Insufficient source collateral for the recovery swap'),\n }\n }\n\n const recoverySimulation = await simulateDispatch({\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n ...recoveredDispatch,\n blockNumber: targetBlockNumber,\n })\n if (recoverySimulation.success) {\n if (recoverySimulation.tokenFlow !== undefined) {\n return {\n available: true,\n quote: {\n tokenIn,\n tokenOut,\n amountOut,\n estimatedAmountIn,\n maximumAmountIn: maxAmountIn,\n slippageBps: params.slippageBps,\n netTokenInChange:\n tokenInIndex === 0n\n ? recoverySimulation.tokenFlow.delta0\n : recoverySimulation.tokenFlow.delta1,\n netTokenOutChange:\n tokenOutIndex === 0n\n ? recoverySimulation.tokenFlow.delta0\n : recoverySimulation.tokenFlow.delta1,\n creditTokenId: credit.tokenId,\n dispatch: recoveredDispatch,\n simulation: {\n ...recoverySimulation,\n tokenFlow: recoverySimulation.tokenFlow,\n },\n tokenFlow: recoverySimulation.tokenFlow,\n _meta: recoverySimulation._meta,\n },\n }\n }\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: 'wrapped dispatch simulation returned no token flow',\n error: new PanopticError('Recovery simulation did not return token flow'),\n }\n }\n\n const remainingShortfall = getNotEnoughTokensError(recoverySimulation.error)\n if (\n remainingShortfall === null ||\n remainingShortfall.tokenAddress.toLowerCase() !== normalizedShortfallToken\n ) {\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: `wrapped dispatch reverted with a non-shortfall error: ${recoverySimulation.error.message}`,\n error: recoverySimulation.error,\n }\n }\n // Grow by the residual the contract just reported. If that residual is\n // non-positive (assetsRequested <= assetBalance, e.g. the shortfall moved to\n // a rounding/fee boundary the revert no longer quantifies), fall back to\n // reusing amountOut — i.e. DOUBLE the target each retry. Bounded by\n // MAX_RECOVERY_QUOTE_ATTEMPTS and by the source-balance check above, so a\n // runaway size fails as swap-unavailable rather than looping.\n const decodedShortfall = remainingShortfall.assetsRequested - remainingShortfall.assetBalance\n const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut\n amountOut += additionalAmountOut\n }\n\n return {\n available: false,\n reason: 'recovery-unavailable',\n detail: `still short after ${MAX_RECOVERY_QUOTE_ATTEMPTS} sizing attempts (last target ${amountOut})`,\n error: new PanopticError('Could not cover recovery swap costs within the quote attempt limit'),\n }\n}\n","/**\n * Open position preview — combines buying power check with open position simulation.\n *\n * @module v2/reads/openPositionPreview\n */\n\nimport type { Address, Client, PublicClient } from 'viem'\n\nimport type { NotEnoughTokensError } from '../errors'\nimport { AccountInsolventError } from '../errors'\nimport { parsePanopticError } from '../errors/parser'\nimport type { SimulateOpenPositionParams } from '../simulations/simulateOpenPosition'\nimport { simulateOpenPosition } from '../simulations/simulateOpenPosition'\nimport { getNotEnoughTokensError } from '../simulations/tokenShortfallRecovery'\nimport type { OpenPositionSimulation, SimulationResult } from '../types'\nimport type { AccountBuyingPower } from './buyingPower'\nimport { getAccountBuyingPower } from './buyingPower'\n\n/**\n * Parameters for getOpenPositionPreview.\n */\nexport interface GetOpenPositionPreviewParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Existing position IDs held by the account (before this mint) */\n existingPositionIds: bigint[]\n /** TokenId of position to open */\n tokenId: bigint\n /** Position size */\n positionSize: bigint\n /** PanopticQuery address */\n queryAddress: Address\n /** Lower tick limit */\n tickLimitLow: bigint\n /** Upper tick limit */\n tickLimitHigh: bigint\n /** Spread limit (default 0n) */\n spreadLimit?: bigint\n /** Whether to swap at mint */\n swapAtMint?: boolean\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Chain ID (for greeks calculation) */\n chainId?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Result of getOpenPositionPreview.\n */\nexport interface OpenPositionPreview {\n /** Current buying power (from checkCollateral on existing positions) */\n currentBuyingPower: AccountBuyingPower\n /** Simulation result (from dry-run dispatch) */\n simulation: SimulationResult<OpenPositionSimulation>\n /**\n * Whether the account has enough *buying power* for the position.\n *\n * False only for a genuine `AccountInsolvent` revert. A token shortfall is\n * reported separately via {@link OpenPositionPreview.tokenShortfall} — the two\n * have different remedies (lower the size vs. source the missing token), so\n * do not collapse them back into one flag.\n */\n isSolvent: boolean\n /**\n * Set when the mint reverted because one collateral tracker lacked tokens,\n * not because the account is short on margin. The account may hold plenty of\n * value in the *other* token, in which case a collateral swap resolves it.\n */\n tokenShortfall: NotEnoughTokensError | null\n /** Token 0 amount required (negative delta = deposit). Null if simulation failed. */\n amount0Required: bigint | null\n /** Token 1 amount required. Null if simulation failed. */\n amount1Required: bigint | null\n /** Collateral balance in token 0 after mint. Null if simulation failed. */\n postCollateral0: bigint | null\n /** Collateral balance in token 1 after mint. Null if simulation failed. */\n postCollateral1: bigint | null\n /** Post-mint collateral requirement in token0 (per-token, not cross-margined). Null if sim failed. */\n postMintCollateralReqToken0: bigint | null\n /** Post-mint collateral requirement in token1 (per-token, not cross-margined). Null if sim failed. */\n postMintCollateralReqToken1: bigint | null\n /**\n * Collateral requirement for the new position only (last entry of perPositionCollateralReqs).\n * Use this for \"Margin Used\" display — postMintCollateralReqToken0/1 includes existing positions too.\n * Null if simulation failed or perPositionCollateralReqs is empty.\n */\n newPositionCollateralReqToken0: bigint | null\n /** Collateral requirement for the new position only, token1. Null if sim failed. */\n newPositionCollateralReqToken1: bigint | null\n}\n\n/**\n * Get a preview of opening a position.\n *\n * Composes two calls:\n * 1. `getAccountBuyingPower` — current margin state for existing positions\n * 2. `simulateOpenPosition` — dry-run dispatch to check feasibility & token flows\n *\n * @param params - Preview parameters\n * @returns Preview with buying power, simulation result, and derived convenience fields\n */\nexport async function getOpenPositionPreview(\n params: GetOpenPositionPreviewParams,\n): Promise<OpenPositionPreview> {\n const {\n client,\n poolAddress,\n account,\n existingPositionIds,\n tokenId,\n positionSize,\n queryAddress,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit,\n swapAtMint,\n usePremiaAsCollateral,\n chainId,\n blockNumber,\n } = params\n\n // Run both calls in parallel\n const [currentBuyingPower, simulation] = await Promise.all([\n getAccountBuyingPower({\n client: client as Client,\n poolAddress,\n account,\n tokenIds: existingPositionIds,\n queryAddress,\n blockNumber,\n }),\n simulateOpenPosition({\n client,\n poolAddress,\n account,\n existingPositionIds,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit,\n swapAtMint,\n usePremiaAsCollateral,\n chainId,\n blockNumber,\n } satisfies SimulateOpenPositionParams),\n ])\n\n // Two distinct failures, kept apart because they have different remedies:\n // AccountInsolvent -> not enough buying power; the size must come down.\n // NotEnoughTokens -> one tracker is short tokens; the account may still be\n // well within its buying power, just holding the wrong\n // token, so sourcing it (swap / loan leg) resolves it.\n // Everything else (PriceBoundFail, EffectiveLiquidityAboveThreshold, …) is\n // neither, and must not read as a collateral problem.\n let isSolvent = true\n let tokenShortfall: NotEnoughTokensError | null = null\n if (!simulation.success) {\n const parsed = parsePanopticError(simulation.error)\n const err = parsed?.error ?? simulation.error\n isSolvent = !(err instanceof AccountInsolventError)\n tokenShortfall = getNotEnoughTokensError(err)\n }\n const data = simulation.success ? simulation.data : null\n\n return {\n currentBuyingPower,\n simulation,\n isSolvent,\n tokenShortfall,\n amount0Required: data?.amount0Required ?? null,\n amount1Required: data?.amount1Required ?? null,\n postCollateral0: data?.postCollateral0 ?? null,\n postCollateral1: data?.postCollateral1 ?? null,\n postMintCollateralReqToken0: data?.postMintCollateralReqToken0 ?? null,\n postMintCollateralReqToken1: data?.postMintCollateralReqToken1 ?? null,\n newPositionCollateralReqToken0:\n data?.perPositionCollateralReqs && data.perPositionCollateralReqs.length > 0\n ? (data.perPositionCollateralReqs[data.perPositionCollateralReqs.length - 1]?.token0 ??\n null)\n : null,\n newPositionCollateralReqToken1:\n data?.perPositionCollateralReqs && data.perPositionCollateralReqs.length > 0\n ? (data.perPositionCollateralReqs[data.perPositionCollateralReqs.length - 1]?.token1 ??\n null)\n : null,\n }\n}\n","/**\n * Read the native token (e.g. ETH) price in USD from a PanopticPool's on-chain tick.\n *\n * @module v2/reads/nativeTokenPrice\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { tickToPriceDecimalScaled } from '../formatters/tick'\n\nexport interface GetNativeTokenPriceParams {\n client: PublicClient\n /** Address of a PanopticPool deployed on a native/USD stablecoin underlying pool */\n panopticPoolAddress: Address\n /** Decimals of token0 in the underlying pool */\n token0Decimals: bigint\n /** Decimals of token1 in the underlying pool */\n token1Decimals: bigint\n /** Whether the native asset is token0 (true) or token1 (false) */\n nativeIsToken0: boolean\n}\n\n/**\n * Fetch the native token price in USD by reading `getCurrentTick()` from a\n * PanopticPool deployed on a native/stablecoin pair.\n *\n * @returns The price as a decimal string (e.g. \"2000.00\")\n */\nexport async function getNativeTokenPrice(params: GetNativeTokenPriceParams): Promise<string> {\n const { client, panopticPoolAddress, token0Decimals, token1Decimals, nativeIsToken0 } = params\n\n const currentTick = await client.readContract({\n address: panopticPoolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getCurrentTick',\n })\n\n // tickToPriceDecimalScaled returns token0/token1 price (price of token0 denominated in token1).\n // If nativeIsToken0: price = USD per native (what we want)\n // If !nativeIsToken0: price = native per USD → invert by swapping decimals\n if (nativeIsToken0) {\n return tickToPriceDecimalScaled(BigInt(currentTick), token0Decimals, token1Decimals, 2n)\n } else {\n // Swap decimals to get the inverse price\n return tickToPriceDecimalScaled(BigInt(currentTick), token1Decimals, token0Decimals, 2n)\n }\n}\n","/**\n * Account trade history for the Panoptic v2 SDK.\n *\n * Fetches OptionMinted and OptionBurnt events filtered by account address\n * using indexed topic filtering for RPC efficiency (2 calls total).\n *\n * @module v2/reads/history\n */\n\nimport type { Address, Hash, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport type { BlockMeta } from '../types'\nimport { decodePositionBalance } from '../writes/utils'\n\n/**\n * A single trade (mint or burn) in the account's history.\n */\nexport interface AccountTrade {\n /** Whether this was a mint or burn */\n action: 'mint' | 'burn'\n /** TokenId of the position */\n tokenId: bigint\n /** Position size */\n positionSize: bigint\n /** Block number of the trade */\n blockNumber: bigint\n /** Transaction hash */\n transactionHash: Hash\n /** Log index within the block */\n logIndex: bigint\n /** Tick at mint (only for mints) */\n tickAtMint?: bigint\n /** Timestamp at mint in Unix seconds (only for mints) */\n timestampAtMint?: bigint\n /** Whether a swap occurred at mint (only for mints) */\n swapAtMint?: boolean\n /** Pool utilization for token 0 at mint (only for mints) */\n poolUtilization0?: bigint\n /** Pool utilization for token 1 at mint (only for mints) */\n poolUtilization1?: bigint\n /** Premia settled per leg on burn (only for burns) */\n premiaByLeg?: readonly [bigint, bigint, bigint, bigint]\n}\n\n/**\n * Account history result.\n */\nexport interface AccountHistory {\n /** All trades sorted by block number ascending, then log index */\n trades: AccountTrade[]\n /** Block metadata at query time */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getAccountHistory.\n */\nexport interface GetAccountHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address to fetch history for */\n account: Address\n /** Start block (default: 0n) */\n fromBlock?: bigint\n /** End block (default: latest) */\n toBlock?: bigint\n /** Optional block number for _meta (default: toBlock or latest) */\n blockNumber?: bigint\n}\n\n/**\n * Fetch trade history for an account on a specific pool.\n *\n * Uses indexed topic filtering on the `recipient` field of OptionMinted\n * and OptionBurnt events, resulting in exactly 2 RPC calls regardless\n * of the number of trades.\n *\n * @param params - Query parameters\n * @returns Account trade history sorted chronologically\n *\n * @example\n * ```typescript\n * const history = await getAccountHistory({\n * client,\n * poolAddress,\n * account: '0x...',\n * fromBlock: 18_000_000n,\n * })\n *\n * for (const trade of history.trades) {\n * console.log(`${trade.action} tokenId=${trade.tokenId} size=${trade.positionSize}`)\n * }\n * ```\n */\nexport async function getAccountHistory(params: GetAccountHistoryParams): Promise<AccountHistory> {\n const { client, poolAddress, account, fromBlock = 0n, toBlock, blockNumber } = params\n\n const effectiveToBlock = toBlock ?? blockNumber ?? (await client.getBlockNumber())\n const metaBlockNumber = blockNumber ?? effectiveToBlock\n\n // Fetch mints and burns in parallel — 2 RPC calls total.\n // Both events have `recipient` as indexed topic[1], so the RPC node\n // filters server-side via the topic hash.\n const [mintLogs, burnLogs, _meta] = await Promise.all([\n client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: 'OptionMinted',\n args: { recipient: account },\n fromBlock,\n toBlock: effectiveToBlock,\n }),\n client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: 'OptionBurnt',\n args: { recipient: account },\n fromBlock,\n toBlock: effectiveToBlock,\n }),\n getBlockMeta({ client, blockNumber: metaBlockNumber }),\n ])\n\n const trades: AccountTrade[] = []\n\n // Parse mints\n for (const log of mintLogs) {\n const args = log.args as {\n recipient: Address\n tokenId: bigint\n balanceData: bigint\n }\n const balance = decodePositionBalance(args.balanceData)\n trades.push({\n action: 'mint',\n tokenId: args.tokenId,\n positionSize: balance.positionSize,\n blockNumber: log.blockNumber!,\n transactionHash: log.transactionHash!,\n logIndex: BigInt(log.logIndex!),\n tickAtMint: balance.tickAtMint,\n timestampAtMint: balance.timestampAtMint,\n swapAtMint: balance.swapAtMint,\n poolUtilization0: balance.poolUtilization0,\n poolUtilization1: balance.poolUtilization1,\n })\n }\n\n // Parse burns\n for (const log of burnLogs) {\n const args = log.args as {\n recipient: Address\n tokenId: bigint\n positionSize: bigint\n premiaByLeg: readonly [bigint, bigint, bigint, bigint]\n }\n trades.push({\n action: 'burn',\n tokenId: args.tokenId,\n positionSize: args.positionSize,\n blockNumber: log.blockNumber!,\n transactionHash: log.transactionHash!,\n logIndex: BigInt(log.logIndex!),\n premiaByLeg: args.premiaByLeg,\n })\n }\n\n // Sort chronologically: by block number, then log index\n trades.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n return a.logIndex < b.logIndex ? -1 : 1\n })\n\n return { trades, _meta }\n}\n","/**\n * Historical Uniswap fee reads for the Panoptic v2 SDK.\n *\n * Standalone function for fetching Uniswap fee accrual across historical blocks.\n * Works with any Uniswap V3/V4 pool — no Panoptic pool required.\n *\n * Also used internally by getStreamiaHistory for the Uniswap fee component.\n *\n * @module v2/reads/uniswapFeeHistory\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { InvalidHistoryRangeError } from '../errors/sdk'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\nimport type { StreamiaLeg } from '../types/streamia'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A single snapshot of Uniswap fee data at a particular block. */\nexport interface UniswapFeeSnapshot {\n /** Resolved block number for this snapshot. */\n blockNumber: bigint\n /** Timestamp of the resolved block in Unix seconds. */\n blockTimestamp: bigint\n /** Uniswap fee delta from the first block in the series */\n fees: { token0: bigint; token1: bigint }\n}\n\n/** Result from getUniswapFeeHistory. */\nexport interface UniswapFeeHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: UniswapFeeSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n/** Parameters for getUniswapFeeHistory. */\nexport interface GetUniswapFeeHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Decoded legs with pre-computed liquidity */\n legs: StreamiaLeg[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n// ── Public function ────────────────────────────────────────────────────\n\n/**\n * Get historical Uniswap fee accrual for a set of liquidity legs across multiple blocks.\n *\n * Works with any Uniswap V3/V4 pool — no Panoptic pool required.\n * Returns fee deltas relative to the first block in the series.\n *\n * @param params - The parameters\n * @returns Fee snapshots at each block\n */\nexport async function getUniswapFeeHistory(\n params: GetUniswapFeeHistoryParams,\n): Promise<UniswapFeeHistoryResult> {\n const { client, blockNumbers, legs, poolConfig } = params\n\n // Validate legs\n for (const leg of legs) {\n if (leg.lowerTick >= leg.upperTick) {\n throw new InvalidHistoryRangeError(\n `Leg lowerTick (${leg.lowerTick}) must be < upperTick (${leg.upperTick})`,\n )\n }\n if (leg.liquidity <= 0n) {\n throw new InvalidHistoryRangeError(`Leg liquidity must be > 0, got ${leg.liquidity}`)\n }\n }\n\n if (blockNumbers.length === 0 || legs.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n const [blockData, blockMetadata, _meta] = await Promise.all([\n fetchUniswapFeeData(client, blockNumbers, legs, poolConfig),\n Promise.all(blockNumbers.map((blockNumber) => getBlockMeta({ client, blockNumber }))),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n let initialFees0: bigint | null = null\n let initialFees1: bigint | null = null\n\n const snapshots: UniswapFeeSnapshot[] = blockData.map((bd, i) => {\n const { total0, total1 } = computeUniswapFeesForBlock(bd, legs)\n\n if (initialFees0 === null) {\n initialFees0 = total0\n initialFees1 = total1\n }\n\n return {\n blockNumber: blockMetadata[i].blockNumber,\n blockTimestamp: blockMetadata[i].blockTimestamp,\n fees: {\n token0: total0 - initialFees0,\n token1: total1 - (initialFees1 as bigint),\n },\n }\n })\n\n return { snapshots, _meta }\n}\n\n// ── Internals (also used by streamiaHistory) ─────────────────────────\n\n/** Raw Uniswap data fetched for a single block. */\nexport interface UniswapBlockData {\n currentTick: number\n feeGrowthGlobal0: bigint\n feeGrowthGlobal1: bigint\n /** Map from tick number → { feeGrowthOutside0, feeGrowthOutside1 } */\n tickData: Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>\n}\n\n/**\n * Fetch Uniswap pool data for all blocks in parallel.\n * Globals (slot0, feeGrowthGlobal) are fetched ONCE per block, not per-leg.\n * Tick data is fetched for each unique tick across all legs.\n */\nexport async function fetchUniswapFeeData(\n client: PublicClient,\n blockNumbers: (bigint | undefined)[],\n legs: StreamiaLeg[],\n poolConfig: PoolVersionConfig,\n): Promise<UniswapBlockData[]> {\n const uniqueTickSet = new Set<number>()\n for (const leg of legs) {\n uniqueTickSet.add(leg.lowerTick)\n uniqueTickSet.add(leg.upperTick)\n }\n const uniqueTicks = [...uniqueTickSet].sort((a, b) => a - b)\n\n const blockPromises = blockNumbers.map((bn) =>\n fetchUniswapBlockSnapshot(client, bn, uniqueTicks, poolConfig),\n )\n\n return Promise.all(blockPromises)\n}\n\n/**\n * Compute total Uniswap fees for all legs at a single block, using the\n * standard Uniswap V3 fee accumulation formula.\n */\nexport function computeUniswapFeesForBlock(\n blockData: UniswapBlockData,\n legs: StreamiaLeg[],\n): { total0: bigint; total1: bigint } {\n let total0 = 0n\n let total1 = 0n\n\n for (const leg of legs) {\n const lower = blockData.tickData.get(leg.lowerTick)\n const upper = blockData.tickData.get(leg.upperTick)\n if (!lower || !upper) continue\n\n const { feeGrowthGlobal0, feeGrowthGlobal1, currentTick } = blockData\n\n const feesBelow0 =\n currentTick >= leg.lowerTick\n ? lower.feeGrowthOutside0\n : feeGrowthGlobal0 - lower.feeGrowthOutside0\n const feesBelow1 =\n currentTick >= leg.lowerTick\n ? lower.feeGrowthOutside1\n : feeGrowthGlobal1 - lower.feeGrowthOutside1\n\n const feesAbove0 =\n currentTick < leg.upperTick\n ? upper.feeGrowthOutside0\n : feeGrowthGlobal0 - upper.feeGrowthOutside0\n const feesAbove1 =\n currentTick < leg.upperTick\n ? upper.feeGrowthOutside1\n : feeGrowthGlobal1 - upper.feeGrowthOutside1\n\n const fees0 = ((feeGrowthGlobal0 - feesBelow0 - feesAbove0) * leg.liquidity) / (1n << 128n)\n const fees1 = ((feeGrowthGlobal1 - feesBelow1 - feesAbove1) * leg.liquidity) / (1n << 128n)\n\n total0 += fees0\n total1 += fees1\n }\n\n return { total0, total1 }\n}\n\n// ── Block snapshot fetchers ──────────────────────────────────────────\n\nasync function fetchUniswapBlockSnapshot(\n client: PublicClient,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n poolConfig: PoolVersionConfig,\n): Promise<UniswapBlockData> {\n if (poolConfig.version === 'v3') {\n return fetchV3BlockSnapshot(client, poolConfig.poolAddress, blockNumber, uniqueTicks)\n } else {\n return fetchV4BlockSnapshot(\n client,\n poolConfig.stateViewAddress,\n poolConfig.poolId,\n blockNumber,\n uniqueTicks,\n )\n }\n}\n\nasync function fetchV3BlockSnapshot(\n client: PublicClient,\n poolAddress: Address,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n): Promise<UniswapBlockData> {\n const contracts = [\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'slot0' as const },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'feeGrowthGlobal0X128' as const },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'feeGrowthGlobal1X128' as const },\n ...uniqueTicks.map((tick) => ({\n address: poolAddress,\n abi: uniswapV3PoolAbi,\n functionName: 'ticks' as const,\n args: [tick] as const,\n })),\n ]\n\n const results = await client.multicall({ contracts, blockNumber, allowFailure: false })\n\n const slot0Result = results[0] as readonly [\n bigint,\n number,\n number,\n number,\n number,\n number,\n boolean,\n ]\n const feeGrowthGlobal0 = results[1] as bigint\n const feeGrowthGlobal1 = results[2] as bigint\n\n const tickData = new Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>()\n for (let i = 0; i < uniqueTicks.length; i++) {\n const tickResult = results[3 + i] as readonly [\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n number,\n boolean,\n ]\n tickData.set(uniqueTicks[i], {\n feeGrowthOutside0: tickResult[2],\n feeGrowthOutside1: tickResult[3],\n })\n }\n\n return { currentTick: slot0Result[1], feeGrowthGlobal0, feeGrowthGlobal1, tickData }\n}\n\nasync function fetchV4BlockSnapshot(\n client: PublicClient,\n stateViewAddress: Address,\n poolId: `0x${string}`,\n blockNumber: bigint | undefined,\n uniqueTicks: number[],\n): Promise<UniswapBlockData> {\n const contracts = [\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getSlot0' as const,\n args: [poolId] as const,\n },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getFeeGrowthGlobals' as const,\n args: [poolId] as const,\n },\n ...uniqueTicks.map((tick) => ({\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getTickInfo' as const,\n args: [poolId, tick] as const,\n })),\n ]\n\n const results = await client.multicall({ contracts, blockNumber, allowFailure: false })\n\n const slot0Result = results[0] as readonly [bigint, number, number, number]\n const feeGrowthResult = results[1] as readonly [bigint, bigint]\n\n const tickData = new Map<number, { feeGrowthOutside0: bigint; feeGrowthOutside1: bigint }>()\n for (let i = 0; i < uniqueTicks.length; i++) {\n const tickResult = results[2 + i] as readonly [bigint, bigint, bigint, bigint]\n tickData.set(uniqueTicks[i], {\n feeGrowthOutside0: tickResult[2],\n feeGrowthOutside1: tickResult[3],\n })\n }\n\n return {\n currentTick: slot0Result[1],\n feeGrowthGlobal0: feeGrowthResult[0],\n feeGrowthGlobal1: feeGrowthResult[1],\n tickData,\n }\n}\n","/**\n * Historical streamia (streaming premia) reads for the Panoptic v2 SDK.\n *\n * Fetches Panoptic premia and optionally Uniswap fee accrual across a series\n * of historical block numbers for a single position. Composes\n * getUniswapFeeHistory internally for the Uniswap fee component.\n *\n * @module v2/reads/streamiaHistory\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { InvalidHistoryRangeError } from '../errors/sdk'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\nimport type { StreamiaLeg } from '../types/streamia'\nimport { computeUniswapFeesForBlock, fetchUniswapFeeData } from './uniswapFeeHistory'\n\n// Re-export types that were originally defined here for backward compatibility\nexport type { PoolVersionConfig, V3PoolConfig, V4PoolConfig } from '../types/poolConfig'\nexport type { StreamiaLeg } from '../types/streamia'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A settled premia event, used to subtract already-settled amounts. */\nexport interface SettledEvent {\n /** Block at which settlement occurred */\n blockNumber: bigint\n /** Amount settled for token 0 */\n settled0: bigint\n /** Amount settled for token 1 */\n settled1: bigint\n}\n\n/** Parameters for getStreamiaHistory. */\nexport interface GetStreamiaHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticPool contract address */\n panopticPoolAddress: Address\n /** Account whose position to query */\n account: Address\n /** The encoded tokenId */\n tokenId: bigint\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Decoded legs with pre-computed liquidity */\n legs: StreamiaLeg[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Whether to include Uniswap fee data (default: true) */\n includeUniswapFees?: boolean\n /** Settled premia events to subtract from Panoptic premia (optional) */\n settledEvents?: SettledEvent[]\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n/** A single snapshot of streamia data at a particular block. */\nexport interface StreamiaSnapshot {\n /** Block number (undefined if queried as latest) */\n blockNumber: bigint | undefined\n /** Net Panoptic premia (short - long), after subtracting settled amounts */\n panopticPremia: { token0: bigint; token1: bigint }\n /** Uniswap fee delta from the first block in the series */\n uniswapFees: { token0: bigint; token1: bigint }\n}\n\n/** Result from getStreamiaHistory. */\nexport interface StreamiaHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: StreamiaSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n// 128-bit mask for LeftRight decoding\nconst MASK_128 = (1n << 128n) - 1n\n\n// ── Main function ──────────────────────────────────────────────────────\n\n/**\n * Get historical streamia data for a position across multiple blocks.\n *\n * @param params - The parameters\n * @returns Snapshots of Panoptic premia and Uniswap fee deltas at each block\n */\nexport async function getStreamiaHistory(\n params: GetStreamiaHistoryParams,\n): Promise<StreamiaHistoryResult> {\n const {\n client,\n panopticPoolAddress,\n account,\n tokenId,\n blockNumbers,\n legs,\n poolConfig,\n includeUniswapFees = true,\n settledEvents,\n } = params\n\n // Validate legs\n for (const leg of legs) {\n if (leg.lowerTick >= leg.upperTick) {\n throw new InvalidHistoryRangeError(\n `Leg lowerTick (${leg.lowerTick}) must be < upperTick (${leg.upperTick})`,\n )\n }\n if (leg.liquidity <= 0n) {\n throw new InvalidHistoryRangeError(`Leg liquidity must be > 0, got ${leg.liquidity}`)\n }\n }\n\n if (blockNumbers.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n // ── 1. Panoptic premia: one readContract per block ─────────────────\n const premiaRequests = blockNumbers.map((bn) =>\n client.readContract({\n address: panopticPoolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, [tokenId]],\n blockNumber: bn,\n }),\n )\n\n // ── 2. Uniswap fees (delegated to uniswapFeeHistory internals) ────\n const uniswapDataPromise =\n includeUniswapFees && legs.length > 0\n ? fetchUniswapFeeData(client, blockNumbers, legs, poolConfig)\n : undefined\n\n // ── 3. Fire all in parallel ────────────────────────────────────────\n const [premiaResults, uniswapData, _meta] = await Promise.all([\n Promise.all(premiaRequests),\n uniswapDataPromise ?? Promise.resolve(undefined),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n // ── 4. Pre-sort settled events for O(n+m) accumulation ─────────────\n const sortedSettled = settledEvents\n ? [...settledEvents].sort((a, b) => (a.blockNumber < b.blockNumber ? -1 : 1))\n : []\n\n // ── 5. Build snapshots ─────────────────────────────────────────────\n let settledIdx = 0\n let accSettled0 = 0n\n let accSettled1 = 0n\n\n let initialUniswapFees0: bigint | null = null\n let initialUniswapFees1: bigint | null = null\n\n const snapshots: StreamiaSnapshot[] = premiaResults.map((result, i) => {\n const bn = blockNumbers[i]\n\n const shortPacked = result[0]\n const longPacked = result[1]\n\n const short0 = shortPacked & MASK_128\n const short1 = shortPacked >> 128n\n const long0 = longPacked & MASK_128\n const long1 = longPacked >> 128n\n\n // Advance settled accumulator\n const effectiveBn = bn ?? BigInt(Number.MAX_SAFE_INTEGER)\n while (\n settledIdx < sortedSettled.length &&\n sortedSettled[settledIdx].blockNumber <= effectiveBn\n ) {\n accSettled0 += sortedSettled[settledIdx].settled0\n accSettled1 += sortedSettled[settledIdx].settled1\n settledIdx++\n }\n\n const premia0 = short0 - long0 - accSettled0\n const premia1 = short1 - long1 - accSettled1\n\n let uniswapFees0 = 0n\n let uniswapFees1 = 0n\n\n if (uniswapData) {\n const blockData = uniswapData[i]\n const { total0, total1 } = computeUniswapFeesForBlock(blockData, legs)\n\n if (initialUniswapFees0 === null) {\n initialUniswapFees0 = total0\n initialUniswapFees1 = total1\n }\n uniswapFees0 = total0 - initialUniswapFees0\n uniswapFees1 = total1 - (initialUniswapFees1 as bigint)\n }\n\n return {\n blockNumber: bn,\n panopticPremia: { token0: premia0, token1: premia1 },\n uniswapFees: { token0: uniswapFees0, token1: uniswapFees1 },\n }\n })\n\n return { snapshots, _meta }\n}\n","/**\n * Direct Uniswap V3 pool read — no Panoptic deployment required.\n *\n * @module v2/reads/uniswapPool\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { encodeAbiParameters, keccak256, zeroAddress } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticValidationError } from '../errors'\nimport type { BlockMeta } from '../types'\n\nconst erc20MetaAbi = [\n {\n type: 'function',\n name: 'symbol',\n inputs: [],\n outputs: [{ type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'name',\n inputs: [],\n outputs: [{ type: 'string' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'decimals',\n inputs: [],\n outputs: [{ type: 'uint8' }],\n stateMutability: 'view',\n },\n] as const\n\nexport interface UniswapV3PoolToken {\n address: Address\n symbol: string\n name: string\n decimals: number\n}\n\nexport interface UniswapV3PoolInfo {\n poolAddress: Address\n token0: UniswapV3PoolToken\n token1: UniswapV3PoolToken\n /** Fee tier in hundredths of a bip (e.g. 500 = 0.05%) */\n fee: number\n tickSpacing: number\n currentTick: number\n sqrtPriceX96: bigint\n liquidity: bigint\n /**\n * Packed protocol fee from slot0: `feeProtocol1 << 4 | feeProtocol0`. Each\n * nibble `n` denotes a protocol fee of `1/n` of the swap fee (`0` = off).\n */\n feeProtocol: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV3PoolInfoParams {\n client: PublicClient\n poolAddress: Address\n}\n\n/**\n * Fetch core data for a Uniswap V3 pool directly from chain.\n *\n * Does NOT require a Panoptic deployment — works for any V3 pool address.\n */\nexport async function getUniswapV3PoolInfo(\n params: GetUniswapV3PoolInfoParams,\n): Promise<UniswapV3PoolInfo> {\n const { client, poolAddress } = params\n\n // Pin every read to the same block so pool state + token metadata are\n // self-consistent. Pool reads run first because token0/token1 are needed to\n // address the ERC20 metadata calls; the second multicall is pinned to the\n // same block as the first.\n const _meta = await getBlockMeta({ client })\n\n const [slot0, fee, tickSpacing, token0Addr, token1Addr, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'slot0' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'fee' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'tickSpacing' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'token0' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'token1' },\n { address: poolAddress, abi: uniswapV3PoolAbi, functionName: 'liquidity' },\n ],\n })\n\n const [t0Symbol, t0Name, t0Decimals, t1Symbol, t1Name, t1Decimals] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'symbol' },\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'name' },\n { address: token0Addr, abi: erc20MetaAbi, functionName: 'decimals' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'symbol' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'name' },\n { address: token1Addr, abi: erc20MetaAbi, functionName: 'decimals' },\n ],\n })\n\n return {\n poolAddress,\n token0: {\n address: token0Addr,\n symbol: t0Symbol,\n name: t0Name,\n decimals: Number(t0Decimals),\n },\n token1: {\n address: token1Addr,\n symbol: t1Symbol,\n name: t1Name,\n decimals: Number(t1Decimals),\n },\n fee: Number(fee),\n tickSpacing: Number(tickSpacing),\n currentTick: Number(slot0[1]),\n sqrtPriceX96: slot0[0],\n liquidity,\n feeProtocol: BigInt(slot0[5]),\n _meta,\n }\n}\n\nexport interface UniswapV3Liquidities {\n ticks: bigint[]\n liquidityNets: bigint[]\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV3PoolLiquiditiesParams {\n client: PublicClient\n /** Uniswap V3 pool address */\n poolAddress: Address\n /** PanopticQuery address — must expose the public `getTickNetsV3` overload */\n queryAddress: Address\n /** Center tick of the range to scan */\n startTick: number\n /** Number of ticks on each side of startTick to scan */\n nTicks: bigint\n}\n\n/** Absolute Uniswap V3/V4 tick bounds. */\nconst TICK_MIN = -887272\nconst TICK_MAX = 887272\n\n/**\n * Clamp `nTicks` so the scan range\n * [scaled(startTick) − nTicks·tickSpacing, scaled(startTick) + nTicks·tickSpacing]\n * stays within [TICK_MIN, TICK_MAX]. Required because PanopticQuery's\n * getTickNetsV3/V4 revert with \"Tick out of bounds\" otherwise.\n */\nfunction clampNTicks(startTick: number, tickSpacing: number, nTicks: bigint): bigint {\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new PanopticValidationError(\n `clampNTicks: tickSpacing must be a positive integer, got ${tickSpacing}`,\n )\n }\n const scaled = Math.trunc(startTick / tickSpacing) * tickSpacing\n const maxUp = Math.floor((TICK_MAX - scaled) / tickSpacing)\n const maxDown = Math.floor((scaled - TICK_MIN) / tickSpacing)\n const safe = BigInt(Math.max(0, Math.min(maxUp, maxDown)))\n return nTicks < safe ? nTicks : safe\n}\n\n/**\n * Fetch cumulative liquidity distribution for a Uniswap V3 pool via\n * `PanopticQuery.getTickNetsV3`. Does NOT require a Panoptic market to exist\n * for the pool — only a deployed PanopticQuery on the chain.\n */\nexport async function getUniswapV3PoolLiquidities(\n params: GetUniswapV3PoolLiquiditiesParams,\n): Promise<UniswapV3Liquidities> {\n const { client, poolAddress, queryAddress, startTick, nTicks } = params\n\n // We don't know tickSpacing here; PanopticQuery reads it from the pool.\n // For safety, clamp against the worst case (tickSpacing = 1).\n const safeN = clampNTicks(startTick, 1, nTicks)\n\n // Pin the read to a specific block so the returned ticks/liquidityNets\n // are consistent with the _meta we hand back.\n const _meta = await getBlockMeta({ client })\n const [ticks, liquidityNets] = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNetsV3',\n args: [poolAddress, startTick, safeN],\n blockNumber: _meta.blockNumber,\n })\n\n return {\n ticks: [...ticks],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n\n// ============================================================================\n// V4\n// ============================================================================\n\nexport interface UniswapV4PoolKey {\n currency0: Address\n currency1: Address\n /** Fee in hundredths of a bip (e.g. 500 = 0.05%) */\n fee: number\n tickSpacing: number\n hooks: Address\n}\n\nconst POOL_KEY_ABI_PARAMS = [\n {\n type: 'tuple',\n components: [\n { name: 'currency0', type: 'address' },\n { name: 'currency1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickSpacing', type: 'int24' },\n { name: 'hooks', type: 'address' },\n ],\n },\n] as const\n\n/** Compute the v4 poolId from a PoolKey: `keccak256(abi.encode(poolKey))`. */\nexport function computeV4PoolId(poolKey: UniswapV4PoolKey): Hex {\n return keccak256(\n encodeAbiParameters(POOL_KEY_ABI_PARAMS, [\n {\n currency0: poolKey.currency0,\n currency1: poolKey.currency1,\n fee: poolKey.fee,\n tickSpacing: poolKey.tickSpacing,\n hooks: poolKey.hooks,\n },\n ]),\n )\n}\n\nexport interface ResolveUniswapV4PoolKeyParams {\n client: PublicClient\n /** Uniswap V4 PoolManager address */\n poolManager: Address\n /** The bytes32 poolId hash */\n poolId: Hex\n /** Lower bound block for the scan (defaults to 0n) */\n fromBlock?: bigint\n /**\n * Per-request block range. Many RPCs cap getLogs at 10k/50k blocks;\n * defaults to 9_500 to stay under common limits.\n */\n chunkSize?: bigint\n /**\n * Number of chunked getLogs requests fired in parallel per batch.\n * Higher = faster but more likely to trip RPC rate limits. Default 8.\n */\n concurrency?: number\n}\n\n/**\n * Resolve a V4 PoolKey from its poolId by scanning `Initialize` event logs\n * on the PoolManager, filtered on the indexed `id` topic.\n *\n * Walks backwards from the latest block in `chunkSize` increments to\n * accommodate RPCs that cap getLogs ranges. Chunks are fired in parallel\n * batches of `concurrency` to keep wall-clock time low; returns as soon as\n * any batch produces a match. Throws if no event is found or if the\n * recomputed poolId does not match the queried one.\n */\nexport async function resolveUniswapV4PoolKey(\n _params: ResolveUniswapV4PoolKeyParams,\n): Promise<UniswapV4PoolKey> {\n // Disabled to save on RPC costs — the Initialize-event scan over the full\n // PoolManager history can issue dozens of eth_getLogs requests per\n // first-load resolution. Re-enable by uncommenting the body below.\n throw new PanopticValidationError(\n 'resolveUniswapV4PoolKey is disabled. ' +\n 'Resolve the V4 PoolKey via your indexer (e.g. Ponder) and pass it to getUniswapV4PoolInfo directly.',\n )\n\n /*\n const {\n client,\n poolManager,\n poolId,\n fromBlock = 0n,\n chunkSize = 9_500n,\n concurrency = 8,\n } = _params\n\n const latest = await client.getBlockNumber()\n\n // Pre-compute all chunk ranges, walking backwards.\n const ranges: Array<{ from: bigint; to: bigint }> = []\n let to = latest\n while (to >= fromBlock) {\n const from = to - chunkSize + 1n > fromBlock ? to - chunkSize + 1n : fromBlock\n ranges.push({ from, to })\n if (from === fromBlock) break\n to = from - 1n\n }\n\n let foundLogs: Awaited<ReturnType<PublicClient['getLogs']>> = []\n\n for (let i = 0; i < ranges.length; i += concurrency) {\n const batch = ranges.slice(i, i + concurrency)\n const results = await Promise.all(\n batch.map((r) =>\n client.getLogs({\n address: poolManager,\n event: uniswapV4PoolManagerAbi[0],\n args: { id: poolId },\n fromBlock: r.from,\n toBlock: r.to,\n }),\n ),\n )\n const hit = results.find((logs) => logs.length > 0)\n if (hit) {\n foundLogs = hit\n break\n }\n }\n\n if (foundLogs.length === 0) {\n throw new Error(`No Initialize event found for poolId ${poolId} on PoolManager ${poolManager}`)\n }\n\n const args = (foundLogs[0] as { args: Record<string, unknown> }).args as {\n id: Hex\n currency0: Address\n currency1: Address\n fee: number\n tickSpacing: number\n hooks: Address\n }\n\n const key: UniswapV4PoolKey = {\n currency0: args.currency0,\n currency1: args.currency1,\n fee: Number(args.fee),\n tickSpacing: Number(args.tickSpacing),\n hooks: args.hooks,\n }\n\n const recomputed = computeV4PoolId(key)\n if (recomputed.toLowerCase() !== poolId.toLowerCase()) {\n throw new Error(\n `Recomputed poolId ${recomputed} does not match queried ${poolId} — PoolKey encoding mismatch`,\n )\n }\n\n return key\n */\n}\n\n/**\n * Slot0 + liquidity for a V4 pool by poolId — does NOT require the PoolKey.\n * Used to render basic info (currentTick, sqrtPriceX96, liquidity) when the\n * PoolKey is unknown.\n */\nexport interface UniswapV4PoolBasicState {\n poolId: Hex\n sqrtPriceX96: bigint\n currentTick: number\n /** Packed directional protocol fee: `oneForZero << 12 | zeroForOne`, in pips. */\n protocolFee: bigint\n /** Dynamic LP fee from slot0 (NOT necessarily the static PoolKey.fee). */\n lpFee: number\n liquidity: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV4PoolBasicStateParams {\n client: Pick<PublicClient, 'getBlock' | 'multicall'>\n stateViewAddress: Address\n poolId: Hex\n}\n\nexport async function getUniswapV4PoolBasicState(\n params: GetUniswapV4PoolBasicStateParams,\n): Promise<UniswapV4PoolBasicState> {\n const { client, stateViewAddress, poolId } = params\n // Pin slot0 + liquidity to the same block as the returned _meta.\n const _meta = await getBlockMeta({ client })\n const [slot0, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: stateViewAddress, abi: stateViewAbi, functionName: 'getSlot0', args: [poolId] },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getLiquidity',\n args: [poolId],\n },\n ],\n })\n return {\n poolId,\n sqrtPriceX96: slot0[0],\n currentTick: Number(slot0[1]),\n protocolFee: BigInt(slot0[2]),\n lpFee: Number(slot0[3]),\n liquidity,\n _meta,\n }\n}\n\nexport interface UniswapV4PoolInfo {\n poolId: Hex\n poolKey: UniswapV4PoolKey\n token0: UniswapV3PoolToken\n token1: UniswapV3PoolToken\n fee: number\n tickSpacing: number\n hooks: Address\n currentTick: number\n sqrtPriceX96: bigint\n /** Packed directional protocol fee: `oneForZero << 12 | zeroForOne`, in pips. */\n protocolFee: bigint\n liquidity: bigint\n _meta: BlockMeta\n}\n\nexport interface GetUniswapV4PoolInfoParams {\n client: Pick<PublicClient, 'getBlock' | 'multicall'>\n stateViewAddress: Address\n poolKey: UniswapV4PoolKey\n}\n\n/** Synthetic token metadata for native ETH (currency address `0x0`). */\nconst NATIVE_ETH_META = { symbol: 'ETH', name: 'Ether', decimals: 18 } as const\n\nasync function readErc20Meta(\n client: Pick<PublicClient, 'multicall'>,\n address: Address,\n blockNumber?: bigint,\n): Promise<{ symbol: string; name: string; decimals: number }> {\n const [symbol, name, decimals] = await client.multicall({\n allowFailure: false,\n blockNumber,\n contracts: [\n { address, abi: erc20MetaAbi, functionName: 'symbol' },\n { address, abi: erc20MetaAbi, functionName: 'name' },\n { address, abi: erc20MetaAbi, functionName: 'decimals' },\n ],\n })\n return { symbol, name, decimals: Number(decimals) }\n}\n\n/**\n * Fetch core data for a Uniswap V4 pool directly from chain.\n *\n * Does NOT require a Panoptic deployment — only StateView + (for non-native\n * currencies) ERC20s. Caller must supply a resolved PoolKey (see\n * `resolveUniswapV4PoolKey`).\n */\nexport async function getUniswapV4PoolInfo(\n params: GetUniswapV4PoolInfoParams,\n): Promise<UniswapV4PoolInfo> {\n const { client, stateViewAddress, poolKey } = params\n const poolId = computeV4PoolId(poolKey)\n\n // Skip ERC20 metadata reads for native ETH (currency `0x0`) so the\n // multicall doesn't revert, and substitute synthetic metadata.\n const c0IsNative = poolKey.currency0 === zeroAddress\n const c1IsNative = poolKey.currency1 === zeroAddress\n\n const _meta = await getBlockMeta({ client })\n\n // State reads (slot0 + liquidity) batched in one multicall.\n const [slot0, liquidity] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n { address: stateViewAddress, abi: stateViewAbi, functionName: 'getSlot0', args: [poolId] },\n {\n address: stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getLiquidity',\n args: [poolId],\n },\n ],\n })\n\n // ERC20 metadata (skipped for native ETH) batched in a second multicall,\n // pinned to the same block as the state reads above for consistency.\n const token0Meta = c0IsNative\n ? { ...NATIVE_ETH_META }\n : await readErc20Meta(client, poolKey.currency0, _meta.blockNumber)\n const token1Meta = c1IsNative\n ? { ...NATIVE_ETH_META }\n : await readErc20Meta(client, poolKey.currency1, _meta.blockNumber)\n\n return {\n poolId,\n poolKey,\n token0: { address: poolKey.currency0, ...token0Meta },\n token1: { address: poolKey.currency1, ...token1Meta },\n fee: poolKey.fee,\n tickSpacing: poolKey.tickSpacing,\n hooks: poolKey.hooks,\n currentTick: Number(slot0[1]),\n sqrtPriceX96: slot0[0],\n protocolFee: BigInt(slot0[2]),\n liquidity,\n _meta,\n }\n}\n\nexport interface GetUniswapV4PoolLiquiditiesParams {\n client: PublicClient\n queryAddress: Address\n poolManager: Address\n poolId: Hex\n tickSpacing: number\n startTick: number\n nTicks: bigint\n}\n\n/**\n * Fetch cumulative liquidity distribution for a Uniswap V4 pool via\n * `PanopticQuery.getTickNetsV4`. Does NOT require a Panoptic market for the pool.\n */\nexport async function getUniswapV4PoolLiquidities(\n params: GetUniswapV4PoolLiquiditiesParams,\n): Promise<UniswapV3Liquidities> {\n const { client, queryAddress, poolManager, poolId, tickSpacing, startTick, nTicks } = params\n\n const safeN = clampNTicks(startTick, tickSpacing, nTicks)\n\n // Pin to a specific block so the returned ticks/liquidityNets match _meta.\n const _meta = await getBlockMeta({ client })\n const [ticks, liquidityNets] = await client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getTickNetsV4',\n args: [poolManager, poolId, tickSpacing, startTick, safeN],\n blockNumber: _meta.blockNumber,\n })\n\n return {\n ticks: [...ticks],\n liquidityNets: [...liquidityNets],\n _meta,\n }\n}\n","/**\n * Direct Uniswap V3/V4 LP position reads — no Panoptic deployment required.\n *\n * Fetches a position's liquidity, tick range and uncollected fees:\n * - V3: `NonfungiblePositionManager.positions` + a `collect` simulation\n * (exact fees, including tokensOwed and unaccrued feeGrowth).\n * - V4: `StateView.getPositionInfo` + `getFeeGrowthInside` and the\n * feeGrowthInside delta math from v4-core's `Position.calculatePositionFeesAccrued`.\n *\n * @module v2/reads/uniswapLpPosition\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { BaseError, ContractFunctionRevertedError, ExecutionRevertedError, toHex } from 'viem'\n\nimport { StateViewAbi } from '../../../abis/StateView'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\n\n// The root NonFungiblePositionManagerAbi flattens collect's CollectParams\n// struct into scalar inputs, which yields a different function selector than\n// the deployed contract's `collect((uint256,address,uint128,uint128))` — so a\n// correct minimal ABI is defined here.\nconst nfpmAbi = [\n {\n type: 'function',\n name: 'positions',\n inputs: [{ name: 'tokenId', type: 'uint256' }],\n outputs: [\n { name: 'nonce', type: 'uint96' },\n { name: 'operator', type: 'address' },\n { name: 'token0', type: 'address' },\n { name: 'token1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickLower', type: 'int24' },\n { name: 'tickUpper', type: 'int24' },\n { name: 'liquidity', type: 'uint128' },\n { name: 'feeGrowthInside0LastX128', type: 'uint256' },\n { name: 'feeGrowthInside1LastX128', type: 'uint256' },\n { name: 'tokensOwed0', type: 'uint128' },\n { name: 'tokensOwed1', type: 'uint128' },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'collect',\n inputs: [\n {\n name: 'params',\n type: 'tuple',\n components: [\n { name: 'tokenId', type: 'uint256' },\n { name: 'recipient', type: 'address' },\n { name: 'amount0Max', type: 'uint128' },\n { name: 'amount1Max', type: 'uint128' },\n ],\n },\n ],\n outputs: [\n { name: 'amount0', type: 'uint256' },\n { name: 'amount1', type: 'uint256' },\n ],\n stateMutability: 'payable',\n },\n] as const\n\nconst MAX_UINT128 = 2n ** 128n - 1n\nconst MAX_UINT256 = 2n ** 256n - 1n\nconst Q128 = 2n ** 128n\n\n/** Liquidity, range and uncollected fees for a single LP position. */\nexport interface UniswapLpPositionState {\n liquidity: bigint\n tickLower: number\n tickUpper: number\n /** Uncollected fees in token0, inclusive of tokensOwed (V3). */\n fees0: bigint\n /** Uncollected fees in token1, inclusive of tokensOwed (V3). */\n fees1: bigint\n /** Block metadata the reads were pinned to. */\n _meta: BlockMeta\n}\n\n/**\n * Whether an error thrown by a viem contract call is an on-chain revert (as\n * opposed to a transport/RPC failure such as a timeout or rate limit).\n */\nfunction isContractRevert(error: unknown): boolean {\n return (\n error instanceof BaseError &&\n error.walk(\n (err) =>\n err instanceof ContractFunctionRevertedError || err instanceof ExecutionRevertedError,\n ) != null\n )\n}\n\nexport interface UniswapV3LpPositionState extends UniswapLpPositionState {\n token0: Address\n token1: Address\n /** Fee tier in hundredths of a bip (e.g. 500 = 0.05%). */\n fee: number\n}\n\nexport interface GetUniswapV3LpPositionStateParams {\n client: PublicClient\n /** NonfungiblePositionManager address. */\n nfpmAddress: Address\n /** ERC721 tokenId of the position. */\n tokenId: bigint\n /** Current owner of the position NFT (used as `account` for the collect simulation). */\n owner: Address\n /** Optional historical block to pin the position read to. */\n blockNumber?: bigint\n}\n\n/**\n * Fetch a Uniswap V3 LP position's state and uncollected fees.\n *\n * Fees come from simulating `collect` with max amounts as the owner — one\n * eth_call returning the exact claimable amounts (tokensOwed + fee growth\n * since the last poke). The simulation is best-effort: if it reverts (e.g.\n * an empty position), fees fall back to 0.\n */\nexport async function getUniswapV3LpPositionState(\n params: GetUniswapV3LpPositionStateParams,\n): Promise<UniswapV3LpPositionState> {\n const { client, nfpmAddress, tokenId, owner, blockNumber } = params\n\n // Pin both reads to the same block so position state and fees are\n // self-consistent with the returned _meta. The collect simulation cannot be\n // folded into a Multicall3 batch: it must run with msg.sender = owner.\n const _meta = await getBlockMeta({ client, blockNumber })\n\n const position = await client.readContract({\n address: nfpmAddress,\n abi: nfpmAbi,\n functionName: 'positions',\n args: [tokenId],\n blockNumber: _meta.blockNumber,\n })\n const [, , token0, token1, fee, tickLower, tickUpper, liquidity] = position\n\n let fees0 = 0n\n let fees1 = 0n\n try {\n const { result } = await client.simulateContract({\n address: nfpmAddress,\n abi: nfpmAbi,\n functionName: 'collect',\n args: [{ tokenId, recipient: owner, amount0Max: MAX_UINT128, amount1Max: MAX_UINT128 }],\n account: owner,\n blockNumber: _meta.blockNumber,\n })\n ;[fees0, fees1] = result\n } catch (error) {\n // collect reverts for some empty positions — report zero fees. Transport\n // and RPC failures propagate so callers don't mistake them for no fees.\n if (!isContractRevert(error)) throw error\n }\n\n return {\n token0,\n token1,\n fee: Number(fee),\n tickLower: Number(tickLower),\n tickUpper: Number(tickUpper),\n liquidity,\n fees0,\n fees1,\n _meta,\n }\n}\n\n/**\n * Uncollected fees from a feeGrowthInside delta, mirroring v4-core's\n * `Position.calculatePositionFeesAccrued`: the subtraction wraps around\n * uint256 (feeGrowthInside can legitimately underflow in-protocol).\n */\nexport function feesFromFeeGrowthDelta(\n feeGrowthInsideCurrentX128: bigint,\n feeGrowthInsideLastX128: bigint,\n liquidity: bigint,\n): bigint {\n const delta = (feeGrowthInsideCurrentX128 - feeGrowthInsideLastX128) & MAX_UINT256\n return (delta * liquidity) / Q128\n}\n\nexport interface GetUniswapV4LpPositionStateParams {\n client: PublicClient\n /** StateView address. */\n stateViewAddress: Address\n /** Uniswap v4 PositionManager (posm) address — the position owner inside PoolManager. */\n positionManagerAddress: Address\n /** The bytes32 poolId hash. */\n poolId: Hex\n /** ERC721 tokenId of the position (posm salt = bytes32(tokenId)). */\n tokenId: bigint\n tickLower: number\n tickUpper: number\n /** Optional historical block to pin the position read to. */\n blockNumber?: bigint\n}\n\n/**\n * Fetch a Uniswap V4 LP position's state and uncollected fees via StateView.\n *\n * The position inside PoolManager is keyed by (positionManager, tickLower,\n * tickUpper, salt) where posm uses `bytes32(tokenId)` as the salt. Fees on\n * pools with fee-taking hooks may be approximate.\n */\nexport async function getUniswapV4LpPositionState(\n params: GetUniswapV4LpPositionStateParams,\n): Promise<UniswapLpPositionState> {\n const {\n client,\n stateViewAddress,\n positionManagerAddress,\n poolId,\n tokenId,\n tickLower,\n tickUpper,\n blockNumber,\n } = params\n\n const salt = toHex(tokenId, { size: 32 })\n\n // Pin both StateView reads to the same block as the returned _meta.\n const _meta = await getBlockMeta({ client, blockNumber })\n\n const [positionInfo, feeGrowthInside] = await client.multicall({\n allowFailure: false,\n blockNumber: _meta.blockNumber,\n contracts: [\n {\n address: stateViewAddress,\n abi: StateViewAbi,\n functionName: 'getPositionInfo',\n args: [poolId, positionManagerAddress, tickLower, tickUpper, salt],\n },\n {\n address: stateViewAddress,\n abi: StateViewAbi,\n functionName: 'getFeeGrowthInside',\n args: [poolId, tickLower, tickUpper],\n },\n ],\n })\n\n const [liquidity, feeGrowthInside0LastX128, feeGrowthInside1LastX128] = positionInfo\n const [feeGrowthInside0X128, feeGrowthInside1X128] = feeGrowthInside\n\n return {\n liquidity,\n tickLower,\n tickUpper,\n fees0: feesFromFeeGrowthDelta(feeGrowthInside0X128, feeGrowthInside0LastX128, liquidity),\n fees1: feesFromFeeGrowthDelta(feeGrowthInside1X128, feeGrowthInside1LastX128, liquidity),\n _meta,\n }\n}\n","/**\n * Historical price reads for the Panoptic v2 SDK.\n *\n * Fetches slot0 (tick + sqrtPriceX96) across a series of historical blocks\n * for price-over-time charting. All block reads are parallelized via\n * Promise.all (viem auto-batches into multicall).\n *\n * @module v2/reads/priceHistory\n */\n\nimport type { PublicClient } from 'viem'\n\nimport { stateViewAbi } from '../abis/stateView'\nimport { uniswapV3PoolAbi } from '../abis/uniswapV3Pool'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport type { BlockMeta } from '../types'\nimport type { PoolVersionConfig } from '../types/poolConfig'\n\n// ── Types ──────────────────────────────────────────────────────────────\n\n/** A single price snapshot at a particular block. */\nexport interface PriceSnapshot {\n /** Block number (undefined if queried as latest) */\n blockNumber: bigint | undefined\n /** Current tick of the pool at this block */\n tick: number\n /** sqrtPriceX96 at this block */\n sqrtPriceX96: bigint\n}\n\n/** Result from getPriceHistory. */\nexport interface PriceHistoryResult {\n /** Snapshots in the same order as input blockNumbers */\n snapshots: PriceSnapshot[]\n /** Block metadata for the latest block used */\n _meta: BlockMeta\n}\n\n/** Parameters for getPriceHistory. */\nexport interface GetPriceHistoryParams {\n /** viem PublicClient */\n client: PublicClient\n /** Block numbers to query; undefined entries resolve to latest */\n blockNumbers: (bigint | undefined)[]\n /** Pool version config (carries pool address / StateView + poolId) */\n poolConfig: PoolVersionConfig\n /** Pre-fetched block metadata (skips an extra eth_getBlockByNumber if provided) */\n _meta?: BlockMeta\n}\n\n// ── Main function ──────────────────────────────────────────────────────\n\n/**\n * Get historical price data (tick + sqrtPriceX96) for a pool across multiple blocks.\n *\n * @param params - The parameters\n * @returns Price snapshots at each block\n *\n * @example\n * ```typescript\n * const { snapshots } = await getPriceHistory({\n * client,\n * blockNumbers: [18000000n, 18000100n, 18000200n],\n * poolConfig: { version: 'v3', poolAddress: '0x...' },\n * })\n *\n * for (const snap of snapshots) {\n * console.log(`Block ${snap.blockNumber}: tick=${snap.tick}`)\n * }\n * ```\n */\nexport async function getPriceHistory(params: GetPriceHistoryParams): Promise<PriceHistoryResult> {\n const { client, blockNumbers, poolConfig } = params\n\n if (blockNumbers.length === 0) {\n const _meta = params._meta ?? (await getBlockMeta({ client }))\n return { snapshots: [], _meta }\n }\n\n // Fire one slot0 read per block. Calls at different historical blocks cannot\n // be coalesced into one multicall, so callers should not poll this path.\n const slot0Requests = blockNumbers.map((bn) => fetchSlot0(client, bn, poolConfig))\n\n const [slot0Results, _meta] = await Promise.all([\n Promise.all(slot0Requests),\n params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client }),\n ])\n\n const snapshots: PriceSnapshot[] = slot0Results.map((result, i) => ({\n blockNumber: blockNumbers[i],\n tick: result.tick,\n sqrtPriceX96: result.sqrtPriceX96,\n }))\n\n return { snapshots, _meta }\n}\n\n// ── Internals ──────────────────────────────────────────────────────────\n\ninterface Slot0Data {\n tick: number\n sqrtPriceX96: bigint\n}\n\nasync function fetchSlot0(\n client: PublicClient,\n blockNumber: bigint | undefined,\n poolConfig: PoolVersionConfig,\n): Promise<Slot0Data> {\n if (poolConfig.version === 'v3') {\n const result = await client.readContract({\n address: poolConfig.poolAddress,\n abi: uniswapV3PoolAbi,\n functionName: 'slot0',\n blockNumber,\n })\n return {\n sqrtPriceX96: result[0],\n tick: result[1],\n }\n } else {\n const result = await client.readContract({\n address: poolConfig.stateViewAddress,\n abi: stateViewAbi,\n functionName: 'getSlot0',\n args: [poolConfig.poolId],\n blockNumber,\n })\n return {\n sqrtPriceX96: result[0],\n tick: result[1],\n }\n }\n}\n","/**\n * Position enrichment data for UI display.\n *\n * Batches all contract reads needed to enrich subgraph position data with\n * on-chain premia, portfolio values, and collateral requirements.\n *\n * @module v2/reads/enrichment\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticPoolV2Abi, panopticQueryAbi } from '../../../generated'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { PanopticError } from '../errors'\nimport type { BlockMeta } from '../types'\nimport { decodeLeftRightUnsigned } from '../writes/utils'\n\n/**\n * Error thrown when an enrichment contract call fails for a specific position.\n */\nexport class EnrichmentCallError extends PanopticError {\n /** The tokenId of the position that failed */\n readonly tokenId: bigint\n /** The name of the failing call */\n readonly callName: string\n\n constructor(tokenId: bigint, callName: string, cause?: unknown) {\n super(\n `Enrichment call \"${callName}\" failed for tokenId ${tokenId}`,\n cause instanceof Error ? cause : undefined,\n )\n this.tokenId = tokenId\n this.callName = callName\n }\n}\n\n/**\n * Input describing a position for enrichment.\n */\nexport interface PositionInput {\n /** The tokenId (256-bit identifier) */\n tokenId: bigint\n /** Whether the position is currently open */\n isOpen: boolean\n /** Tick at time of mint */\n tickAtMint: number\n /** Account address that owns the position */\n account: Address\n /** Pool address the position belongs to */\n poolAddress: Address\n /** Tick at burn (closed positions only) */\n tickAtBurn?: number\n /** Block number of the burn tx (closed positions only) */\n burnBlockNumber?: bigint\n /** Premium in token0 from subgraph (closed positions only) */\n burnPremium0?: bigint\n /** Premium in token1 from subgraph (closed positions only) */\n burnPremium1?: bigint\n}\n\n/**\n * Enrichment result for a single position.\n *\n * Values are in raw token units (token0 and token1), not asset/quote.\n * The UI maps these to asset/quote based on isAssetToken0.\n */\nexport interface PositionEnrichmentResult {\n /** Net premia owed: shortPremium - longPremium for token0 (open); burnPremium0 for closed */\n premiaOwed0: bigint\n /** Net premia owed: shortPremium - longPremium for token1 (open); burnPremium1 for closed */\n premiaOwed1: bigint\n /** Portfolio value in token0 at current tick (open) or burn tick (closed) */\n portfolioValue0: bigint\n /** Portfolio value in token1 at current tick (open) or burn tick (closed) */\n portfolioValue1: bigint\n /** Portfolio value in token0 at mint tick */\n portfolioValueAtMint0: bigint\n /** Portfolio value in token1 at mint tick */\n portfolioValueAtMint1: bigint\n /**\n * Per-token collateral requirement from `getFullPositionsData.collateralRequirements[]`.\n * These are NOT cross-margined — each is in its own token denomination.\n * For closed positions these are 0n (collateral is moot).\n */\n collateralReqToken0: bigint\n collateralReqToken1: bigint\n}\n\n/**\n * Parameters for getPositionEnrichmentData.\n */\nexport interface GetPositionEnrichmentDataParams {\n /** viem PublicClient */\n client: PublicClient\n /** PanopticQuery helper contract address */\n queryAddress: Address\n /** Positions to enrich */\n positions: PositionInput[]\n /** Current pool tick (used for open position portfolio values) */\n currentTick: number\n /** Optional block number for open position reads */\n blockNumber?: bigint\n /** Optional pre-fetched block metadata */\n _meta?: BlockMeta\n}\n\n/**\n * Result from getPositionEnrichmentData.\n */\nexport interface GetPositionEnrichmentDataResult {\n /** Enrichment data keyed by tokenId string */\n byTokenId: Map<string, PositionEnrichmentResult>\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Fetch enrichment data (premia, portfolio values, collateral requirements) for a set of positions.\n *\n * Batches all needed contract reads into efficient multicalls:\n * - **Open positions**: 3 calls per position in a single multicall at current block:\n * 1. `getFullPositionsData` → premia + collateral requirements\n * 2. `getPortfolioValue` at currentTick → current portfolio value\n * 3. `getPortfolioValue` at mintTick → portfolio value at mint\n * - **Closed positions**: 2 calls per position at `burnBlockNumber - 1`:\n * 1. `getPortfolioValue` at burnTick → portfolio value at close\n * 2. `getPortfolioValue` at mintTick → portfolio value at mint\n * (premia come from subgraph `burnPremium0/1`)\n *\n * ## Same-Block Guarantee\n * Open position data is fetched at a single block number.\n * Closed position data is fetched at `burnBlockNumber - 1` (per position).\n *\n * @param params - The parameters\n * @returns Map of tokenId → enrichment data, with block metadata\n */\nexport async function getPositionEnrichmentData(\n params: GetPositionEnrichmentDataParams,\n): Promise<GetPositionEnrichmentDataResult> {\n const { client, queryAddress, positions, currentTick, blockNumber } = params\n\n // Fetch a single block metadata for the entire enrichment result\n const _meta = params._meta ?? (await getBlockMeta({ client, blockNumber }))\n\n if (positions.length === 0) {\n return { byTokenId: new Map(), _meta }\n }\n\n const openPositions = positions.filter((p) => p.isOpen)\n const closedPositions = positions.filter((p) => !p.isOpen)\n\n const byTokenId = new Map<string, PositionEnrichmentResult>()\n\n // Process open and closed positions in parallel\n await Promise.all([\n processOpenPositions(client, queryAddress, openPositions, currentTick, blockNumber, _meta),\n processClosedPositions(client, queryAddress, closedPositions),\n ]).then(([openResults, closedResults]) => {\n // Merge results into byTokenId map\n for (const [key, value] of openResults.entries) {\n byTokenId.set(key, value)\n }\n for (const [key, value] of closedResults) {\n byTokenId.set(key, value)\n }\n })\n\n return { byTokenId, _meta }\n}\n\n/** Number of multicall contracts per open position */\nconst OPEN_CALLS_PER_POSITION = 3\n/** Number of multicall contracts per closed position */\nconst CLOSED_CALLS_PER_POSITION = 2\n\n/**\n * Process open positions: single multicall with 5 calls per position.\n */\nasync function processOpenPositions(\n client: PublicClient,\n queryAddress: Address,\n positions: PositionInput[],\n currentTick: number,\n blockNumber: bigint | undefined,\n _meta: BlockMeta,\n): Promise<{ entries: [string, PositionEnrichmentResult][] }> {\n if (positions.length === 0) {\n return { entries: [] }\n }\n\n const targetBlockNumber = blockNumber ?? _meta.blockNumber\n\n // Build multicall contracts: 3 calls per position\n const contracts = positions.flatMap((p) => [\n // 1. getFullPositionsData → premia + collateral requirements\n {\n address: p.poolAddress,\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData' as const,\n args: [p.account, true, [p.tokenId]] as const,\n },\n // 2. getPortfolioValue at currentTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, currentTick, [p.tokenId]] as const,\n },\n // 3. getPortfolioValue at mintTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtMint, [p.tokenId]] as const,\n },\n ])\n\n const multicallResults = await client.multicall({\n contracts,\n blockNumber: targetBlockNumber,\n allowFailure: true,\n })\n\n const entries: [string, PositionEnrichmentResult][] = []\n\n for (let i = 0; i < positions.length; i++) {\n const position = positions[i]\n const baseIdx = i * OPEN_CALLS_PER_POSITION\n\n const premiaResult = multicallResults[baseIdx]\n const portfolioResult = multicallResults[baseIdx + 1]\n const portfolioAtMintResult = multicallResults[baseIdx + 2]\n\n if (premiaResult.status !== 'success') {\n throw new EnrichmentCallError(position.tokenId, 'getFullPositionsData', premiaResult.error)\n }\n if (portfolioResult.status !== 'success') {\n throw new EnrichmentCallError(\n position.tokenId,\n 'getPortfolioValue (currentTick)',\n portfolioResult.error,\n )\n }\n if (portfolioAtMintResult.status !== 'success') {\n throw new EnrichmentCallError(\n position.tokenId,\n 'getPortfolioValue (mintTick)',\n portfolioAtMintResult.error,\n )\n }\n\n // Decode getFullPositionsData: [shortPremium, longPremium, balances[], collateralReqs[], netPremia[]]\n const [shortPremiumPacked, longPremiumPacked, , collateralReqsPacked] = premiaResult.result as [\n bigint,\n bigint,\n bigint[],\n bigint[],\n bigint[],\n ]\n const shortPremium = decodeLeftRightUnsigned(shortPremiumPacked)\n const longPremium = decodeLeftRightUnsigned(longPremiumPacked)\n\n const premiaOwed0 = shortPremium.right - longPremium.right // token0\n const premiaOwed1 = shortPremium.left - longPremium.left // token1\n\n // Decode per-token collateral requirements from collateralReqs[0] (LeftRightUnsigned)\n const collateralReq = decodeLeftRightUnsigned(collateralReqsPacked[0] ?? 0n)\n\n // Decode portfolio values\n const [portfolioValue0, portfolioValue1] = portfolioResult.result as [bigint, bigint]\n const [portfolioValueAtMint0, portfolioValueAtMint1] = portfolioAtMintResult.result as [\n bigint,\n bigint,\n ]\n\n entries.push([\n position.tokenId.toString(),\n {\n premiaOwed0,\n premiaOwed1,\n portfolioValue0,\n portfolioValue1,\n portfolioValueAtMint0,\n portfolioValueAtMint1,\n collateralReqToken0: collateralReq.right,\n collateralReqToken1: collateralReq.left,\n },\n ])\n }\n\n return { entries }\n}\n\n/**\n * Process closed positions: per-position calls at burnBlockNumber - 1.\n *\n * Returns entries array (not a map) to merge into the final result.\n */\nasync function processClosedPositions(\n client: PublicClient,\n queryAddress: Address,\n positions: PositionInput[],\n): Promise<[string, PositionEnrichmentResult][]> {\n if (positions.length === 0) return []\n\n // Group positions by burnBlockNumber for batch efficiency\n const byBlock = new Map<bigint, PositionInput[]>()\n for (const p of positions) {\n if (p.burnBlockNumber == null) continue\n const readBlock = p.burnBlockNumber - 1n\n const group = byBlock.get(readBlock) ?? []\n group.push(p)\n byBlock.set(readBlock, group)\n }\n\n const entries: [string, PositionEnrichmentResult][] = []\n\n // Process each block group\n await Promise.all(\n Array.from(byBlock.entries()).map(async ([readBlock, blockPositions]) => {\n // Build multicall contracts: 2 calls per position\n const contracts = blockPositions.flatMap((p) => [\n // 1. getPortfolioValue at burnTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtBurn ?? 0, [p.tokenId]] as const,\n },\n // 2. getPortfolioValue at mintTick\n {\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getPortfolioValue' as const,\n args: [p.poolAddress, p.account, p.tickAtMint, [p.tokenId]] as const,\n },\n ])\n\n const multicallResults = await client.multicall({\n contracts,\n blockNumber: readBlock,\n allowFailure: true,\n })\n\n for (let i = 0; i < blockPositions.length; i++) {\n const position = blockPositions[i]\n const baseIdx = i * CLOSED_CALLS_PER_POSITION\n\n const portfolioAtBurnResult = multicallResults[baseIdx]\n const portfolioAtMintResult = multicallResults[baseIdx + 1]\n\n // Closed position reads can fail legitimately (e.g. position minted and burned\n // in the same block — at burnBlock-1 it doesn't exist yet). Fall back to zeros.\n const [portfolioValue0, portfolioValue1] =\n portfolioAtBurnResult.status === 'success'\n ? (portfolioAtBurnResult.result as [bigint, bigint])\n : [0n, 0n]\n const [portfolioValueAtMint0, portfolioValueAtMint1] =\n portfolioAtMintResult.status === 'success'\n ? (portfolioAtMintResult.result as [bigint, bigint])\n : [0n, 0n]\n\n entries.push([\n position.tokenId.toString(),\n {\n premiaOwed0: position.burnPremium0 ?? 0n,\n premiaOwed1: position.burnPremium1 ?? 0n,\n portfolioValue0,\n portfolioValue1,\n portfolioValueAtMint0,\n portfolioValueAtMint1,\n collateralReqToken0: 0n,\n collateralReqToken1: 0n,\n },\n ])\n }\n }),\n )\n\n return entries\n}\n","/**\n * Get synchronization status for an account.\n * @module v2/sync/getSyncStatus\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { loadCheckpoint } from './reorgHandling'\n\n/**\n * Parameters for getSyncStatus.\n */\nexport interface GetSyncStatusParams {\n /** viem public client */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to check */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Sync status result.\n */\nexport interface SyncStatusResult {\n /** Last synced block number (0n if never synced) */\n lastSyncedBlock: bigint\n /** Whether the account is fully synced to current block */\n isSynced: boolean\n /** Number of blocks behind (0n if synced) */\n blocksBehind: bigint\n /** Number of positions tracked */\n positionCount: bigint\n /** Whether a checkpoint exists */\n hasCheckpoint: boolean\n}\n\n/**\n * Get the synchronization status for an account.\n *\n * This function checks the stored checkpoint and compares against\n * the current chain head to determine sync status.\n *\n * @param params - Status parameters\n * @returns Sync status information\n */\nexport async function getSyncStatus(params: GetSyncStatusParams): Promise<SyncStatusResult> {\n const { client, chainId, poolAddress, account, storage } = params\n\n // Get current block\n const currentBlock = await client.getBlockNumber()\n\n // Load checkpoint\n const checkpoint = await loadCheckpoint(storage, chainId, poolAddress, account)\n\n if (!checkpoint) {\n return {\n lastSyncedBlock: 0n,\n isSynced: false,\n blocksBehind: currentBlock,\n positionCount: 0n,\n hasCheckpoint: false,\n }\n }\n\n const blocksBehind = currentBlock - checkpoint.lastBlock\n const isSynced = blocksBehind <= 0n\n\n return {\n lastSyncedBlock: checkpoint.lastBlock,\n isSynced,\n blocksBehind: blocksBehind > 0n ? blocksBehind : 0n,\n positionCount: BigInt(checkpoint.positionIds.length),\n hasCheckpoint: true,\n }\n}\n","/**\n * Trade history tracking for closed positions.\n * @module v2/sync/tradeHistory\n */\n\nimport type { Address } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { getClosedPositionsKey, jsonSerializer } from '../storage'\nimport type { ClosedPosition, RealizedPnL } from '../types'\n\n/**\n * Parameters for saving a closed position.\n */\nexport interface SaveClosedPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account that owned the position */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** The closed position data */\n closedPosition: ClosedPosition\n}\n\n/**\n * Save a closed position to trade history.\n *\n * @param params - Save parameters\n */\nexport async function saveClosedPosition(params: SaveClosedPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, closedPosition } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n let history: ClosedPosition[]\n if (existingData) {\n try {\n history = jsonSerializer.parse(existingData) as ClosedPosition[]\n } catch {\n history = []\n }\n } else {\n history = []\n }\n\n // Add new closed position\n history.push(closedPosition)\n\n // Sort by close block (most recent first)\n history.sort((a, b) => Number(b.closeBlock - a.closeBlock))\n\n await storage.set(key, jsonSerializer.stringify(history))\n}\n\n/**\n * Parameters for getting trade history.\n */\nexport interface GetTradeHistoryParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to get history for */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Maximum number of positions to return (default: 100) */\n limit?: bigint\n /** Offset for pagination */\n offset?: bigint\n /** Filter by closure reason */\n closureReason?: 'closed' | 'liquidated' | 'force_exercised'\n /** Filter by block range (from) */\n fromBlock?: bigint\n /** Filter by block range (to) */\n toBlock?: bigint\n}\n\n/**\n * Get trade history (closed positions) for an account.\n *\n * This function reads from local storage, no RPC calls.\n * Positions are returned in reverse chronological order (most recent first).\n *\n * @param params - Query parameters\n * @returns Array of closed positions\n */\nexport async function getTradeHistory(params: GetTradeHistoryParams): Promise<ClosedPosition[]> {\n const {\n chainId,\n poolAddress,\n account,\n storage,\n limit = 100n,\n offset = 0n,\n closureReason,\n fromBlock,\n toBlock,\n } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n let history: ClosedPosition[]\n try {\n history = jsonSerializer.parse(data) as ClosedPosition[]\n } catch {\n return []\n }\n\n // Apply filters\n if (closureReason) {\n history = history.filter((p) => p.closureReason === closureReason)\n }\n\n if (fromBlock !== undefined) {\n history = history.filter((p) => p.closeBlock >= fromBlock)\n }\n\n if (toBlock !== undefined) {\n history = history.filter((p) => p.closeBlock <= toBlock)\n }\n\n // Apply pagination\n const start = Number(offset)\n const end = start + Number(limit)\n return history.slice(start, end)\n}\n\n/**\n * Get closed positions (alias for getTradeHistory with specific closure reason).\n *\n * @param params - Query parameters\n * @returns Array of closed positions\n */\nexport async function getClosedPositions(params: GetTradeHistoryParams): Promise<ClosedPosition[]> {\n return getTradeHistory(params)\n}\n\n/**\n * Parameters for getting realized PnL.\n */\nexport interface GetRealizedPnLParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account to get PnL for */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Filter by block range (from) */\n fromBlock?: bigint\n /** Filter by block range (to) */\n toBlock?: bigint\n}\n\n/**\n * Get realized PnL summary for an account.\n *\n * Calculates totals from all closed positions in storage.\n *\n * @param params - Query parameters\n * @returns Realized PnL summary\n */\nexport async function getRealizedPnL(params: GetRealizedPnLParams): Promise<RealizedPnL> {\n const { chainId, poolAddress, account, storage, fromBlock, toBlock } = params\n\n const history = await getTradeHistory({\n chainId,\n poolAddress,\n account,\n storage,\n limit: BigInt(Number.MAX_SAFE_INTEGER), // Get all\n fromBlock,\n toBlock,\n })\n\n let total0 = 0n\n let total1 = 0n\n let winCount = 0n\n let lossCount = 0n\n\n for (const position of history) {\n total0 += position.realizedPnL0\n total1 += position.realizedPnL1\n\n // Consider it a win if either token had positive PnL\n // (in practice, one will usually dominate)\n const isWin = position.realizedPnL0 > 0n || position.realizedPnL1 > 0n\n const isLoss = position.realizedPnL0 < 0n || position.realizedPnL1 < 0n\n\n if (isWin && !isLoss) {\n winCount++\n } else if (isLoss && !isWin) {\n lossCount++\n }\n // Mixed results (win on one, loss on other) don't count as either\n }\n\n return {\n total0,\n total1,\n positionCount: BigInt(history.length),\n winCount,\n lossCount,\n }\n}\n\n/**\n * Clear all trade history for an account.\n *\n * @param params - Query parameters\n */\nexport async function clearTradeHistory(\n params: Omit<\n GetTradeHistoryParams,\n 'limit' | 'offset' | 'closureReason' | 'fromBlock' | 'toBlock'\n >,\n): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getClosedPositionsKey(chainId, poolAddress, account)\n await storage.delete(key)\n}\n","/**\n * Chunk spread tracking for volatility surface data.\n * @module v2/sync/chunkTracking\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { panopticQueryAbi } from '../abis/panopticQuery'\nimport { getBlockMeta } from '../clients/blockMeta'\nimport { ChunkLimitError } from '../errors'\nimport type { StorageAdapter } from '../storage'\nimport { getTrackedChunksKey, jsonSerializer } from '../storage'\nimport { DEFAULT_VEGOID } from '../tokenId/constants'\nimport type { BlockMeta } from '../types'\nimport { MAX_TRACKED_CHUNKS, WAD } from '../utils/constants'\n\n/**\n * Key for identifying a liquidity chunk.\n * A chunk is a unique combination of (tokenType, tickLower, tickUpper).\n */\nexport interface LiquidityChunkKey {\n /** Token type: 0n = token0 (put), 1n = token1 (call) */\n tokenType: 0n | 1n\n /** Lower tick bound */\n tickLower: bigint\n /** Upper tick bound */\n tickUpper: bigint\n}\n\n/**\n * Full chunk data with spread calculation.\n */\nexport interface LiquidityChunkSpread extends LiquidityChunkKey {\n /** Liquidity currently deployed in Uniswap */\n netLiquidity: bigint\n /** Liquidity borrowed by option buyers */\n removedLiquidity: bigint\n /** Computed spread: (1 + (1/VEGOID) * removed/net) * 1e18 */\n spreadWad: bigint\n}\n\n/**\n * Parameters for adding tracked chunks.\n */\nexport interface AddTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Chunks to add */\n chunks: LiquidityChunkKey[]\n}\n\n/**\n * Serialize a chunk key to a string for storage/comparison.\n */\nfunction serializeChunkKey(chunk: LiquidityChunkKey): string {\n return `${chunk.tokenType}:${chunk.tickLower}:${chunk.tickUpper}`\n}\n\n/**\n * Deserialize a chunk key from a string.\n */\nfunction deserializeChunkKey(key: string): LiquidityChunkKey {\n const [tokenType, tickLower, tickUpper] = key.split(':')\n return {\n tokenType: BigInt(tokenType) as 0n | 1n,\n tickLower: BigInt(tickLower),\n tickUpper: BigInt(tickUpper),\n }\n}\n\n/**\n * Add chunks to tracking.\n *\n * @param params - Parameters\n * @throws ChunkLimitError if adding would exceed 1000 chunks\n */\nexport async function addTrackedChunks(params: AddTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage, chunks } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const existingData = await storage.get(key)\n\n let trackedKeys: Set<string>\n if (existingData) {\n try {\n const keys = jsonSerializer.parse(existingData) as string[]\n trackedKeys = new Set(keys)\n } catch {\n trackedKeys = new Set()\n }\n } else {\n trackedKeys = new Set()\n }\n\n // Add new chunks\n for (const chunk of chunks) {\n const serialized = serializeChunkKey(chunk)\n trackedKeys.add(serialized)\n }\n\n // Check limit\n if (trackedKeys.size > MAX_TRACKED_CHUNKS) {\n const attemptedAdd = BigInt(chunks.length)\n throw new ChunkLimitError(BigInt(trackedKeys.size - chunks.length), attemptedAdd)\n }\n\n await storage.set(key, jsonSerializer.stringify([...trackedKeys]))\n}\n\n/**\n * Parameters for removing tracked chunks.\n */\nexport interface RemoveTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Chunks to remove */\n chunks: LiquidityChunkKey[]\n}\n\n/**\n * Remove chunks from tracking.\n *\n * @param params - Parameters\n */\nexport async function removeTrackedChunks(params: RemoveTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage, chunks } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let trackedKeys: Set<string>\n try {\n const keys = jsonSerializer.parse(existingData) as string[]\n trackedKeys = new Set(keys)\n } catch {\n return\n }\n\n // Remove chunks\n for (const chunk of chunks) {\n const serialized = serializeChunkKey(chunk)\n trackedKeys.delete(serialized)\n }\n\n if (trackedKeys.size === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify([...trackedKeys]))\n }\n}\n\n/**\n * Parameters for getting tracked chunks.\n */\nexport interface GetTrackedChunksParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Get all tracked chunk keys.\n *\n * @param params - Parameters\n * @returns Array of tracked chunk keys\n */\nexport async function getTrackedChunks(\n params: GetTrackedChunksParams,\n): Promise<LiquidityChunkKey[]> {\n const { chainId, poolAddress, storage } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n try {\n const keys = jsonSerializer.parse(data) as string[]\n return keys.map(deserializeChunkKey)\n } catch {\n return []\n }\n}\n\n/**\n * Parameters for getting chunk spreads (legacy manual tracking).\n * @deprecated Use scanChunks() for automatic chunk discovery\n */\nexport interface GetChunkSpreadsParams {\n /** viem public client */\n client: PublicClient\n /** Chain ID */\n chainId: bigint\n /** Pool address (PanopticPool) */\n poolAddress: Address\n /** SFPM address */\n sfpmAddress: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Optional filter by token type */\n tokenType?: 0n | 1n\n /** VEGOID constant (default: 4n) */\n vegoid?: bigint\n}\n\n/**\n * Get spread data for all tracked chunks (legacy).\n *\n * @deprecated Use scanChunks() for automatic chunk discovery with on-chain data.\n * This function only returns manually tracked chunks.\n *\n * @param params - Parameters\n * @returns Array of chunk spreads with liquidity data\n */\nexport async function getChunkSpreads(\n params: GetChunkSpreadsParams,\n): Promise<LiquidityChunkSpread[]> {\n const { chainId, poolAddress, storage, tokenType } = params\n\n // Get tracked chunks\n let chunks = await getTrackedChunks({ chainId, poolAddress, storage })\n\n // Apply filter\n if (tokenType !== undefined) {\n chunks = chunks.filter((c) => c.tokenType === tokenType)\n }\n\n if (chunks.length === 0) {\n return []\n }\n\n // Return tracked chunks without liquidity data\n // Use scanChunks() for on-chain liquidity data\n return chunks.map((chunk) => ({\n ...chunk,\n netLiquidity: 0n,\n removedLiquidity: 0n,\n spreadWad: WAD,\n }))\n}\n\n/**\n * Calculate spread from liquidity values.\n *\n * spread = 1 + (1/VEGOID) * removedLiquidity / netLiquidity\n *\n * @param netLiquidity - Liquidity in Uniswap\n * @param removedLiquidity - Liquidity borrowed by buyers\n * @param vegoid - VEGOID constant (default: 4n)\n * @returns Spread in WAD (1e18 = 1.0x)\n */\nexport function calculateSpreadWad(\n netLiquidity: bigint,\n removedLiquidity: bigint,\n vegoid: bigint = DEFAULT_VEGOID,\n): bigint {\n if (netLiquidity === 0n) {\n return WAD // 1.0x spread if no liquidity\n }\n\n // spread = WAD + (WAD / vegoid) * removedLiquidity / netLiquidity\n // = WAD + (WAD * removedLiquidity) / (vegoid * netLiquidity)\n const bonus = (WAD * removedLiquidity) / (vegoid * netLiquidity)\n return WAD + bonus\n}\n\n/**\n * Clear all tracked chunks for a pool.\n *\n * @param params - Parameters\n */\nexport async function clearTrackedChunks(params: GetTrackedChunksParams): Promise<void> {\n const { chainId, poolAddress, storage } = params\n\n const key = getTrackedChunksKey(chainId, poolAddress)\n await storage.delete(key)\n}\n\n// ============================================================================\n// PanopticQuery-based chunk functions (recommended)\n// ============================================================================\n\n/**\n * Scanned chunk with liquidity data from PanopticQuery.scanChunks().\n */\nexport interface ScannedChunk {\n /** Strike tick (center of the chunk) */\n strike: bigint\n /** Token type 0 net liquidity */\n netLiquidity0: bigint\n /** Token type 1 net liquidity */\n netLiquidity1: bigint\n /** Token type 0 removed liquidity */\n removedLiquidity0: bigint\n /** Token type 1 removed liquidity */\n removedLiquidity1: bigint\n /** Computed spread for token type 0 */\n spreadWad0: bigint\n /** Computed spread for token type 1 */\n spreadWad1: bigint\n /** Token type 0 settled tokens (LeftRightUnsigned: left=token1, right=token0) */\n settledTokens0: bigint\n /** Token type 1 settled tokens (LeftRightUnsigned: left=token1, right=token0) */\n settledTokens1: bigint\n}\n\n/**\n * Result of scanning chunks in a tick range.\n */\nexport interface ScanChunksResult {\n /** Array of scanned chunks with liquidity data */\n chunks: ScannedChunk[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for scanChunks().\n */\nexport interface ScanChunksParams {\n /** viem public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery contract address */\n queryAddress: Address\n /** Lower tick bound of range to scan */\n tickLower: bigint\n /** Upper tick bound of range to scan */\n tickUpper: bigint\n /** Width of chunks to scan (tickUpper - tickLower for each chunk) */\n width: bigint\n /** VEGOID constant for spread calculation (default: 4n) */\n vegoid?: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Scan for non-empty liquidity chunks in a tick range.\n *\n * Uses PanopticQuery.scanChunks() to discover chunks with liquidity.\n * Returns only non-empty chunks, making it efficient for large ranges.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - Parameters\n * @returns Scanned chunks with liquidity data and block metadata\n *\n * @example\n * ```typescript\n * const result = await scanChunks({\n * client,\n * poolAddress: '0x...',\n * queryAddress: '0x...',\n * tickLower: -1000n,\n * tickUpper: 1000n,\n * width: 100n, // 100 tick wide chunks\n * })\n *\n * for (const chunk of result.chunks) {\n * console.log(`Strike ${chunk.strike}: spread0=${chunk.spreadWad0}, spread1=${chunk.spreadWad1}`)\n * }\n * ```\n */\nexport async function scanChunks(params: ScanChunksParams): Promise<ScanChunksResult> {\n const {\n client,\n poolAddress,\n queryAddress,\n tickLower,\n tickUpper,\n width,\n vegoid = 4n,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [result, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'scanChunks',\n args: [poolAddress, Number(tickLower), Number(tickUpper), Number(width)],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n const [strikes, netLiquidities, removedLiquidities, settledTokens] = result\n\n const chunks: ScannedChunk[] = strikes.map((strike, i) => {\n const net0 = netLiquidities[i][0]\n const net1 = netLiquidities[i][1]\n const removed0 = removedLiquidities[i][0]\n const removed1 = removedLiquidities[i][1]\n\n return {\n strike: BigInt(strike),\n netLiquidity0: net0,\n netLiquidity1: net1,\n removedLiquidity0: removed0,\n removedLiquidity1: removed1,\n spreadWad0: calculateSpreadWad(net0, removed0, vegoid),\n spreadWad1: calculateSpreadWad(net1, removed1, vegoid),\n settledTokens0: settledTokens[i][0],\n settledTokens1: settledTokens[i][1],\n }\n })\n\n return { chunks, _meta }\n}\n\n/**\n * Chunk data for a single leg of a position.\n */\nexport interface LegChunkData {\n /** Leg index (0-3) */\n legIndex: number\n /** Net liquidity (liquidity in Uniswap) */\n netLiquidity: bigint\n /** Removed liquidity (borrowed by option buyers) */\n removedLiquidity: bigint\n /** Computed spread */\n spreadWad: bigint\n}\n\n/**\n * Chunk data for a position (all legs).\n */\nexport interface PositionChunkData {\n /** TokenId of the position */\n tokenId: bigint\n /** Chunk data for each leg */\n legs: LegChunkData[]\n}\n\n/**\n * Result of getting position chunk data.\n */\nexport interface GetPositionChunkDataResult {\n /** Array of position chunk data */\n positions: PositionChunkData[]\n /** Block metadata */\n _meta: BlockMeta\n}\n\n/**\n * Parameters for getPositionChunkData().\n */\nexport interface GetPositionChunkDataParams {\n /** viem public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** PanopticQuery contract address */\n queryAddress: Address\n /** Array of tokenIds to query */\n tokenIds: bigint[]\n /** VEGOID constant for spread calculation (default: 4n) */\n vegoid?: bigint\n /** Optional block number for historical queries */\n blockNumber?: bigint\n}\n\n/**\n * Get chunk data (liquidity) for specific positions.\n *\n * Uses PanopticQuery.getChunkData() to fetch net and removed liquidity\n * for each leg of the given positions.\n *\n * ## Same-Block Guarantee\n * All data is fetched at a single block.\n *\n * @param params - Parameters\n * @returns Position chunk data with liquidity for each leg\n *\n * @example\n * ```typescript\n * const result = await getPositionChunkData({\n * client,\n * poolAddress: '0x...',\n * queryAddress: '0x...',\n * tokenIds: [tokenId1, tokenId2],\n * })\n *\n * for (const pos of result.positions) {\n * console.log(`Position ${pos.tokenId}:`)\n * for (const leg of pos.legs) {\n * console.log(` Leg ${leg.legIndex}: net=${leg.netLiquidity}, removed=${leg.removedLiquidity}`)\n * }\n * }\n * ```\n */\nexport async function getPositionChunkData(\n params: GetPositionChunkDataParams,\n): Promise<GetPositionChunkDataResult> {\n const {\n client,\n poolAddress,\n queryAddress,\n tokenIds,\n vegoid = DEFAULT_VEGOID,\n blockNumber,\n } = params\n\n if (tokenIds.length === 0) {\n const _meta = await getBlockMeta({ client, blockNumber })\n return { positions: [], _meta }\n }\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n\n const [chunkData, _meta] = await Promise.all([\n client.readContract({\n address: queryAddress,\n abi: panopticQueryAbi,\n functionName: 'getChunkData',\n args: [poolAddress, tokenIds],\n blockNumber: targetBlockNumber,\n }),\n getBlockMeta({ client, blockNumber: targetBlockNumber }),\n ])\n\n // chunkData is uint256[2][4][] - [positionIndex][legIndex][0=net, 1=removed]\n const positions: PositionChunkData[] = tokenIds.map((tokenId, posIndex) => {\n const positionData = chunkData[posIndex]\n const legs: LegChunkData[] = []\n\n // Each position has up to 4 legs\n for (let legIndex = 0; legIndex < 4; legIndex++) {\n const legData = positionData[legIndex]\n const netLiquidity = legData[0]\n const removedLiquidity = legData[1]\n\n // Only include legs with data (non-zero liquidity indicates active leg)\n if (netLiquidity > 0n || removedLiquidity > 0n) {\n legs.push({\n legIndex,\n netLiquidity,\n removedLiquidity,\n spreadWad: calculateSpreadWad(netLiquidity, removedLiquidity, vegoid),\n })\n }\n }\n\n return { tokenId, legs }\n })\n\n return { positions, _meta }\n}\n","/**\n * Pending position tracking for optimistic updates.\n * @module v2/sync/pendingPositions\n */\n\nimport type { Address, Hash } from 'viem'\n\nimport type { StorageAdapter } from '../storage'\nimport { getPendingPositionsKey, jsonSerializer } from '../storage'\nimport type { TokenIdLeg } from '../types'\n\n/**\n * A pending position that has been submitted but not yet confirmed.\n */\nexport interface PendingPosition {\n /** The TokenId */\n tokenId: bigint\n /** Owner address */\n owner: Address\n /** Pool address */\n poolAddress: Address\n /** Position size (from simulation) */\n positionSize: bigint\n /** Decoded legs */\n legs: TokenIdLeg[]\n /** Transaction hash */\n txHash: Hash\n /** Block number when submitted */\n submittedAtBlock: bigint\n /** Timestamp when submitted */\n submittedAt: bigint\n /** Status */\n status: 'pending' | 'confirmed' | 'failed'\n}\n\n/**\n * Parameters for adding a pending position.\n */\nexport interface AddPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Pending position data */\n position: PendingPosition\n}\n\n/**\n * Add a pending position for optimistic updates.\n *\n * Called when openPosition() submits a transaction.\n *\n * @param params - Parameters\n */\nexport async function addPendingPosition(params: AddPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, position } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n let pending: PendingPosition[]\n if (existingData) {\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n pending = []\n }\n } else {\n pending = []\n }\n\n // Add new pending position\n pending.push(position)\n\n await storage.set(key, jsonSerializer.stringify(pending))\n}\n\n/**\n * Parameters for getting pending positions.\n */\nexport interface GetPendingPositionsParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n}\n\n/**\n * Get all pending positions for an account.\n *\n * @param params - Parameters\n * @returns Array of pending positions\n */\nexport async function getPendingPositions(\n params: GetPendingPositionsParams,\n): Promise<PendingPosition[]> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const data = await storage.get(key)\n\n if (!data) {\n return []\n }\n\n try {\n const pending = jsonSerializer.parse(data) as PendingPosition[]\n // Only return pending status\n return pending.filter((p) => p.status === 'pending')\n } catch {\n return []\n }\n}\n\n/**\n * Parameters for confirming a pending position.\n */\nexport interface ConfirmPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Token ID to confirm */\n tokenId: bigint\n}\n\n/**\n * Mark a pending position as confirmed.\n *\n * Called when syncPositions() finds the OptionMinted event.\n *\n * @param params - Parameters\n */\nexport async function confirmPendingPosition(params: ConfirmPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, tokenId } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Find and update the position\n const updated = pending.map((p) =>\n p.tokenId === tokenId ? { ...p, status: 'confirmed' as const } : p,\n )\n\n // Remove confirmed positions (they're now in the main position list)\n const remaining = updated.filter((p) => p.status === 'pending')\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n\n/**\n * Parameters for failing a pending position.\n */\nexport interface FailPendingPositionParams {\n /** Chain ID */\n chainId: bigint\n /** Pool address */\n poolAddress: Address\n /** Account (owner) */\n account: Address\n /** Storage adapter */\n storage: StorageAdapter\n /** Transaction hash that failed */\n txHash: Hash\n}\n\n/**\n * Mark a pending position as failed (transaction reverted).\n *\n * @param params - Parameters\n */\nexport async function failPendingPosition(params: FailPendingPositionParams): Promise<void> {\n const { chainId, poolAddress, account, storage, txHash } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Remove the failed position\n const remaining = pending.filter((p) => p.txHash !== txHash)\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n\n/**\n * Clear all pending positions for an account.\n *\n * @param params - Parameters\n */\nexport async function clearPendingPositions(params: GetPendingPositionsParams): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n await storage.delete(key)\n}\n\n/**\n * Clean up stale pending positions.\n *\n * Removes pending positions older than the specified block threshold.\n * This handles cases where transactions were dropped from the mempool.\n *\n * @param params - Parameters\n * @param maxAgeBlocks - Maximum age in blocks (default: 100)\n * @param currentBlock - Current block number\n */\nexport async function cleanupStalePendingPositions(\n params: GetPendingPositionsParams,\n currentBlock: bigint,\n maxAgeBlocks: bigint = 100n,\n): Promise<void> {\n const { chainId, poolAddress, account, storage } = params\n\n const key = getPendingPositionsKey(chainId, poolAddress, account)\n const existingData = await storage.get(key)\n\n if (!existingData) {\n return\n }\n\n let pending: PendingPosition[]\n try {\n pending = jsonSerializer.parse(existingData) as PendingPosition[]\n } catch {\n return\n }\n\n // Filter out stale positions\n const threshold = currentBlock - maxAgeBlocks\n const remaining = pending.filter((p) => p.status === 'pending' && p.submittedAtBlock > threshold)\n\n if (remaining.length === 0) {\n await storage.delete(key)\n } else if (remaining.length !== pending.length) {\n await storage.set(key, jsonSerializer.stringify(remaining))\n }\n}\n","/**\n * Event reconstruction for full position history scan.\n * @module v2/sync/eventReconstruction\n */\n\nimport type { Address, Hash, PublicClient } from 'viem'\n\nimport type { SyncEvent } from '../types'\n\n/**\n * Parameters for event reconstruction.\n */\nexport interface EventReconstructionParams {\n /** viem public client */\n client: PublicClient\n /** Pool address */\n poolAddress: Address\n /** Account to reconstruct positions for */\n account: Address\n /** Starting block for event scan */\n fromBlock: bigint\n /** Ending block for event scan */\n toBlock: bigint\n /** Batch size for log queries (default: 10000) */\n batchSize?: bigint\n /** Progress callback */\n onProgress?: (event: SyncEvent) => void\n}\n\n/**\n * Event reconstruction result.\n */\nexport interface EventReconstructionResult {\n /** Position IDs that are currently open */\n openPositions: bigint[]\n /** Position IDs that have been closed */\n closedPositions: bigint[]\n /** Number of blocks scanned */\n blocksScanned: bigint\n /** Last scanned block number */\n lastBlock: bigint\n /** Last scanned block hash */\n lastBlockHash: Hash\n}\n\n/**\n * Mint event from reconstruction.\n */\ninterface MintEvent {\n tokenId: bigint\n positionSize: bigint\n blockNumber: bigint\n blockHash: Hash\n transactionHash: Hash\n logIndex: number\n}\n\n/**\n * Burn event from reconstruction.\n */\ninterface BurnEvent {\n tokenId: bigint\n positionSize: bigint\n blockNumber: bigint\n blockHash: Hash\n transactionHash: Hash\n logIndex: number\n}\n\n/**\n * Reconstruct position history from events.\n * This is the fallback method when snapshot recovery fails.\n * It scans all OptionMinted and OptionBurnt events to build the position set.\n *\n * @param params - Reconstruction parameters\n * @returns Reconstruction result with open and closed positions\n */\nexport async function reconstructFromEvents(\n params: EventReconstructionParams,\n): Promise<EventReconstructionResult> {\n const {\n client,\n poolAddress,\n account,\n fromBlock,\n toBlock,\n batchSize = 10000n,\n onProgress,\n } = params\n\n const mintEvents: MintEvent[] = []\n const burnEvents: BurnEvent[] = []\n\n let currentBlock = fromBlock\n const totalBlocks = toBlock - fromBlock\n\n // Scan in batches\n while (currentBlock <= toBlock) {\n const endBlock =\n currentBlock + batchSize - 1n > toBlock ? toBlock : currentBlock + batchSize - 1n\n\n // Fetch mint events for this batch\n const [mints, burns] = await Promise.all([\n client.getLogs({\n address: poolAddress,\n event: {\n type: 'event',\n name: 'OptionMinted',\n inputs: [\n { type: 'address', name: 'recipient', indexed: true },\n { type: 'uint256', name: 'tokenId', indexed: true },\n { type: 'uint256', name: 'balanceData', indexed: false },\n ],\n },\n args: {\n recipient: account,\n },\n fromBlock: currentBlock,\n toBlock: endBlock,\n }),\n client.getLogs({\n address: poolAddress,\n event: {\n type: 'event',\n name: 'OptionBurnt',\n inputs: [\n { type: 'address', name: 'recipient', indexed: true },\n { type: 'uint256', name: 'tokenId', indexed: true },\n { type: 'uint256', name: 'positionSize', indexed: false },\n { type: 'int256[4]', name: 'premiaByLeg', indexed: false },\n ],\n },\n args: {\n recipient: account,\n },\n fromBlock: currentBlock,\n toBlock: endBlock,\n }),\n ])\n\n // Process mint events\n for (const mint of mints) {\n // Decode position size from balanceData (first 128 bits)\n const balanceData = mint.args.balanceData as bigint\n const positionSize = balanceData & ((1n << 128n) - 1n)\n\n mintEvents.push({\n tokenId: mint.args.tokenId as bigint,\n positionSize,\n blockNumber: mint.blockNumber,\n blockHash: mint.blockHash,\n transactionHash: mint.transactionHash,\n logIndex: mint.logIndex,\n })\n }\n\n // Process burn events\n for (const burn of burns) {\n burnEvents.push({\n tokenId: burn.args.tokenId as bigint,\n positionSize: burn.args.positionSize as bigint,\n blockNumber: burn.blockNumber,\n blockHash: burn.blockHash,\n transactionHash: burn.transactionHash,\n logIndex: burn.logIndex,\n })\n }\n\n // Report progress\n if (onProgress) {\n const blocksProcessed = endBlock - fromBlock + 1n\n const progress = totalBlocks > 0n ? (blocksProcessed * 100n) / totalBlocks : 100n\n\n onProgress({\n currentBlock: endBlock,\n targetBlock: toBlock,\n positionsFound: BigInt(mintEvents.length),\n progress,\n })\n }\n\n currentBlock = endBlock + 1n\n }\n\n // Build position map: tokenId -> net position size\n const positionMap = new Map<bigint, bigint>()\n\n // Sort all events by block and log index\n const allEvents = [\n ...mintEvents.map((e) => ({ ...e, type: 'mint' as const })),\n ...burnEvents.map((e) => ({ ...e, type: 'burn' as const })),\n ].sort((a, b) => {\n const blockDiff = Number(a.blockNumber - b.blockNumber)\n if (blockDiff !== 0) return blockDiff\n return a.logIndex - b.logIndex\n })\n\n // Process events in order\n for (const event of allEvents) {\n const current = positionMap.get(event.tokenId) ?? 0n\n\n if (event.type === 'mint') {\n positionMap.set(event.tokenId, current + event.positionSize)\n } else {\n positionMap.set(event.tokenId, current - event.positionSize)\n }\n }\n\n // Separate open and closed positions\n const openPositions: bigint[] = []\n const closedPositions: bigint[] = []\n\n for (const [tokenId, size] of positionMap) {\n if (size > 0n) {\n openPositions.push(tokenId)\n } else {\n closedPositions.push(tokenId)\n }\n }\n\n // Get the last block hash\n const lastBlock = await client.getBlock({ blockNumber: toBlock })\n\n return {\n openPositions,\n closedPositions,\n blocksScanned: toBlock - fromBlock + 1n,\n lastBlock: toBlock,\n lastBlockHash: lastBlock.hash,\n }\n}\n\n/**\n * Get the deployment block for a pool.\n * This searches for the first PoolInitialized event.\n *\n * @param client - viem public client\n * @param poolAddress - Pool address\n * @returns Deployment block number or null if not found\n */\nexport async function getPoolDeploymentBlock(\n client: PublicClient,\n poolAddress: Address,\n): Promise<bigint | null> {\n // Search for the first event from this pool\n // We use a binary search approach to find the deployment block\n\n const currentBlock = await client.getBlockNumber()\n let low = 0n\n let high = currentBlock\n let foundBlock: bigint | null = null\n\n // Binary search with scan windows to find the deployment block.\n // Each iteration checks [mid, mid + scanRange] for logs.\n const scanRange = 10000n\n\n while (low <= high) {\n const mid = (low + high) / 2n\n const rangeEnd = mid + scanRange > high ? high : mid + scanRange\n\n try {\n const logs = await client.getLogs({\n address: poolAddress,\n fromBlock: mid,\n toBlock: rangeEnd,\n })\n\n if (logs.length > 0) {\n // Found logs — record earliest and search before it\n const earliest = logs[0].blockNumber\n if (foundBlock === null || earliest < foundBlock) {\n foundBlock = earliest\n }\n high = earliest - 1n\n } else {\n // No logs in [mid, rangeEnd] — skip the entire checked range\n low = rangeEnd + 1n\n }\n } catch {\n // Range too large for RPC — halve the search space\n high = mid + (rangeEnd - mid) / 2n\n }\n }\n\n return foundBlock\n}\n","/**\n * Item-based wrapper around simulateDispatch for batched mint/burn ops.\n * @module v2/simulations/simulateBatchDispatch\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { buildBatchDispatchArgs } from '../batch/build'\nimport type { BatchDiagnostic, BatchOp } from '../batch/types'\nimport { getBlockMeta } from '../clients'\nimport type { BlockMeta, DispatchSimulation, SimulationResult } from '../types'\nimport { simulateDispatch } from './simulateDispatch'\n\n/**\n * Parameters for `simulateBatchDispatch`.\n *\n * - `client`: viem PublicClient used for read calls.\n * - `poolAddress`: PanopticPool address the batch targets.\n * - `account`: account whose collateral and positions are simulated against.\n * - `items`: ordered batch ops (mints + burns) — order matters because dispatch\n * applies them sequentially.\n * - `existingPositionIds`: account's current on-chain `positionIdList`. Must\n * reflect FRESH on-chain state (not a cached/optimistic snapshot) — stale\n * data here yields incorrect pre-dispatch margin excess and false\n * burn-not-found diagnostics.\n * - `usePremiaAsCollateral`: applied across the whole dispatch. Defaults to\n * `false`.\n * - `builderCode`: applied across the whole dispatch. Defaults to `0n`.\n * - `blockNumber`: optional pinned block; defaults to the client's latest.\n */\nexport interface SimulateBatchDispatchParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n /** Batch ops in operation order. */\n items: BatchOp[]\n /** Current on-chain positionIdList for the account (fresh). */\n existingPositionIds: bigint[]\n /** Apply across the whole dispatch. Defaults to false. */\n usePremiaAsCollateral?: boolean\n /** Apply across the whole dispatch. Defaults to 0n. */\n builderCode?: bigint\n /** Optional pinned block. */\n blockNumber?: bigint\n}\n\n/**\n * Result returned by `simulateBatchDispatch`.\n *\n * Either delegates to `simulateDispatch` (and therefore matches its\n * `SimulationResult<DispatchSimulation>` shape), or short-circuits with\n * batch-level diagnostics when the items fail validation. In either case the\n * shape includes a `diagnostics` field so callers can render conflicts before\n * deciding what to do — UIs typically gray out the Execute button when\n * `diagnostics.length > 0`.\n */\nexport type SimulateBatchDispatchResult =\n | (SimulationResult<DispatchSimulation> & { diagnostics: BatchDiagnostic[] })\n | { success: false; diagnostics: BatchDiagnostic[]; _meta: BlockMeta }\n\n/**\n * Simulate a batch dispatch built from `items` + the current on-chain\n * positionIdList. Returns batch diagnostics OR a real simulation result.\n */\nexport async function simulateBatchDispatch(\n params: SimulateBatchDispatchParams,\n): Promise<SimulateBatchDispatchResult> {\n const {\n client,\n poolAddress,\n account,\n items,\n existingPositionIds,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n } = params\n\n const { args, diagnostics } = buildBatchDispatchArgs({\n items,\n existingPositionIds,\n usePremiaAsCollateral,\n builderCode,\n })\n\n if (args === null) {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const meta = await getBlockMeta({ client, blockNumber: targetBlockNumber })\n return { success: false, diagnostics, _meta: meta }\n }\n\n const sim = await simulateDispatch({\n client,\n poolAddress,\n account,\n positionIdList: args.positionIdList,\n finalPositionIdList: args.finalPositionIdList,\n existingPositionIdList: existingPositionIds,\n positionSizes: args.positionSizes,\n tickAndSpreadLimits: args.tickAndSpreadLimits,\n usePremiaAsCollateral: args.usePremiaAsCollateral,\n builderCode: args.builderCode,\n blockNumber,\n })\n\n return { ...sim, diagnostics: [] }\n}\n","/**\n * Close position simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateClosePosition\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { ClosePositionSimulation, SimulationResult } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating position closing.\n */\nexport interface SimulateClosePositionParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Current position ID list */\n positionIdList: bigint[]\n /** TokenId of position to close */\n tokenId: bigint\n /** Position size to close */\n positionSize: bigint\n /**\n * Lower tick limit (always <= tickLimitHigh).\n * Use MIN_TICK (-887272n) to allow any downward price movement.\n */\n tickLimitLow: bigint\n /**\n * Upper tick limit (always >= tickLimitLow).\n * Use MAX_TICK (887272n) to allow any upward price movement.\n */\n tickLimitHigh: bigint\n /** Spread limit tick (use 0n for no spread limit) */\n spreadLimit?: bigint\n /**\n * Whether to swap tokens at burn to achieve single-sided exposure.\n * When true, tickLimits are passed to dispatch in descending order (high, low).\n * When false (default), tickLimits are passed in ascending order (low, high).\n */\n swapAtMint?: boolean\n /** Whether to use premia as collateral */\n usePremiaAsCollateral?: boolean\n /** Builder code */\n builderCode?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate closing a position.\n *\n * Uses PanopticPool.multicall with getAssetsOf-dispatch-getAssetsOf pattern\n * to measure exact collateral asset movements from the burn.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with close data or error\n */\nexport async function simulateClosePosition(\n params: SimulateClosePositionParams,\n): Promise<SimulationResult<ClosePositionSimulation>> {\n const {\n client,\n poolAddress,\n account,\n positionIdList,\n tokenId,\n tickLimitLow,\n tickLimitHigh,\n spreadLimit = 0n,\n swapAtMint = false,\n usePremiaAsCollateral = false,\n builderCode = 0n,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Build tick limits based on swapAtMint flag:\n // - swapAtMint=true: descending order (high, low) triggers SFPM swap\n // - swapAtMint=false: ascending order (low, high) no swap\n const tickLimits: readonly [number, number, number] = swapAtMint\n ? [Number(tickLimitHigh), Number(tickLimitLow), Number(spreadLimit)]\n : [Number(tickLimitLow), Number(tickLimitHigh), Number(spreadLimit)]\n\n try {\n // Prepare final position list (without the closed position)\n const finalPositionIdList = positionIdList.filter((id) => id !== tokenId)\n\n // Encode dispatch call data for burn (positionSize = 0 signals close)\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [tokenId],\n finalPositionIdList,\n [0n],\n [tickLimits],\n usePremiaAsCollateral,\n builderCode,\n ],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow = flowResult.tokenFlow\n const _meta = await metaPromise\n\n // Map token flow to simulation fields:\n // Positive delta = user receives collateral back\n const data: ClosePositionSimulation = {\n amount0Received: tokenFlow.delta0,\n amount1Received: tokenFlow.delta1,\n premiaCollected0: null, // Requires pre-close premia snapshot\n premiaCollected1: null,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n realizedPnL0: null, // Requires open position cost basis\n realizedPnL1: null,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","/**\n * Force exercise simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateForceExercise\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { ForceExerciseSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating force exercise.\n */\nexport interface SimulateForceExerciseParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Exercisor account address */\n account: Address\n /** Account whose position is being exercised */\n user: Address\n /** Position IDs from the exercisor's account */\n positionIdListFrom: bigint[]\n /** Position IDs of the target user */\n positionIdListTo: bigint[]\n /** Final position ID list for the user after exercise */\n positionIdListToFinal: bigint[]\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a force exercise operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with exercise data or error\n */\nexport async function simulateForceExercise(\n params: SimulateForceExerciseParams,\n): Promise<SimulationResult<ForceExerciseSimulation>> {\n const {\n client,\n poolAddress,\n account,\n user,\n positionIdListFrom,\n positionIdListTo,\n positionIdListToFinal,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Default token flow for failure cases\n const emptyTokenFlow: TokenFlow = {\n delta0: 0n,\n delta1: 0n,\n balanceBefore0: 0n,\n balanceBefore1: 0n,\n balanceAfter0: 0n,\n balanceAfter1: 0n,\n tickBefore: null,\n tickAfter: null,\n }\n\n try {\n // Encode dispatchFrom call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatchFrom',\n args: [positionIdListFrom, user, positionIdListTo, positionIdListToFinal, 0n],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account, // Measure exercisor's collateral change\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n // Check for specific exercise-related errors\n const errorMessage = flowResult.error || 'Simulation failed'\n const isNotExercisable =\n errorMessage.includes('NoLegsExercisable') || errorMessage.includes('NotALongLeg')\n\n if (isNotExercisable) {\n const _meta = await metaPromise\n const data: ForceExerciseSimulation = {\n exerciseFee0: 0n,\n exerciseFee1: 0n,\n canExercise: false,\n reason: errorMessage.includes('NoLegsExercisable')\n ? 'No legs are exercisable (not ITM)'\n : 'Position does not have a long leg',\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n throw new PanopticError(errorMessage)\n }\n\n const _meta = await metaPromise\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Build simulation result with actual token flow data\n // Exercise fee is what the exercisor receives (positive delta)\n const data: ForceExerciseSimulation = {\n exerciseFee0: tokenFlow.delta0,\n exerciseFee1: tokenFlow.delta1,\n canExercise: true,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n // If simulation fails, check the reason\n const errorMessage = error instanceof Error ? error.message : 'Simulation failed'\n\n // Check for specific exercise-related errors\n const isNotExercisable =\n errorMessage.includes('NoLegsExercisable') || errorMessage.includes('NotALongLeg')\n\n if (isNotExercisable) {\n const data: ForceExerciseSimulation = {\n exerciseFee0: 0n,\n exerciseFee1: 0n,\n canExercise: false,\n reason: errorMessage.includes('NoLegsExercisable')\n ? 'No legs are exercisable (not ITM)'\n : 'Position does not have a long leg',\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(errorMessage, error instanceof Error ? error : undefined),\n _meta,\n }\n }\n}\n","/**\n * Liquidation simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateLiquidate\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { LiquidateSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Parameters for simulating liquidation.\n */\nexport interface SimulateLiquidateParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Liquidator account address */\n account: Address\n /** Account being liquidated */\n liquidatee: Address\n /** Position IDs from the liquidator's account */\n positionIdListFrom: bigint[]\n /** Position IDs of the liquidatee */\n positionIdListTo: bigint[]\n /** Final position ID list for the liquidatee after liquidation */\n positionIdListToFinal: bigint[]\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a liquidation operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with liquidation data or error\n */\nexport async function simulateLiquidate(\n params: SimulateLiquidateParams,\n): Promise<SimulationResult<LiquidateSimulation>> {\n const {\n client,\n poolAddress,\n account,\n liquidatee,\n positionIdListFrom,\n positionIdListTo,\n positionIdListToFinal,\n blockNumber,\n } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n // Default token flow for failure cases\n const emptyTokenFlow: TokenFlow = {\n delta0: 0n,\n delta1: 0n,\n balanceBefore0: 0n,\n balanceBefore1: 0n,\n balanceAfter0: 0n,\n balanceAfter1: 0n,\n tickBefore: null,\n tickAfter: null,\n }\n\n try {\n // Encode dispatchFrom call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatchFrom',\n args: [positionIdListFrom, liquidatee, positionIdListTo, positionIdListToFinal, 0n],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account, // Measure liquidator's collateral change\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n // Check if it's a specific error indicating not liquidatable\n const errorMessage = flowResult.error || 'Simulation failed'\n const isNotLiquidatable =\n errorMessage.includes('NotMarginCalled') || errorMessage.includes('AccountInsolvent')\n\n if (isNotLiquidatable) {\n const _meta = await metaPromise\n const data: LiquidateSimulation = {\n bonus0: 0n,\n bonus1: 0n,\n positionsClosed: [],\n isLiquidatable: false,\n shortfall0: 0n,\n shortfall1: 0n,\n }\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n throw new PanopticError(errorMessage)\n }\n\n const _meta = await metaPromise\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Positions that would be closed\n const positionsClosed = positionIdListTo.filter((id) => !positionIdListToFinal.includes(id))\n\n // Build simulation result with actual token flow data\n // Positive delta = liquidator receives bonus\n const data: LiquidateSimulation = {\n bonus0: tokenFlow.delta0 > 0n ? tokenFlow.delta0 : 0n,\n bonus1: tokenFlow.delta1 > 0n ? tokenFlow.delta1 : 0n,\n positionsClosed,\n isLiquidatable: true,\n shortfall0: 0n, // Would need additional calculation\n shortfall1: 0n,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n // If simulation fails, the account might not be liquidatable\n const errorMessage = error instanceof Error ? error.message : 'Simulation failed'\n const isNotLiquidatable =\n errorMessage.includes('NotMarginCalled') || errorMessage.includes('AccountInsolvent')\n\n if (isNotLiquidatable) {\n const data: LiquidateSimulation = {\n bonus0: 0n,\n bonus1: 0n,\n positionsClosed: [],\n isLiquidatable: false,\n shortfall0: 0n,\n shortfall1: 0n,\n }\n return {\n success: true,\n data,\n gasEstimate: 0n,\n tokenFlow: emptyTokenFlow,\n _meta,\n }\n }\n\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(errorMessage, error instanceof Error ? error : undefined),\n _meta,\n }\n }\n}\n","/**\n * Settle simulation for the Panoptic v2 SDK.\n * @module v2/simulations/simulateSettle\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { decodeFunctionResult, encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { SettleSimulation, SimulationResult, TokenFlow } from '../types'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/** BIT_MASK_128 = (1n << 128n) - 1n */\nconst BIT_MASK_128 = (1n << 128n) - 1n\n\n/**\n * PanopticPool multicall ABI (inherited from Uniswap).\n */\nconst multicallAbi = [\n {\n type: 'function',\n name: 'multicall',\n inputs: [{ name: 'data', type: 'bytes[]' }],\n outputs: [{ name: 'results', type: 'bytes[]' }],\n stateMutability: 'nonpayable',\n },\n] as const\n\n/**\n * Parameters for simulating premium settlement.\n */\nexport interface SimulateSettleParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Current position ID list */\n positionIdList: bigint[]\n /** Optional tokenId to compute forfeit amounts for */\n tokenId?: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate premium settlement.\n *\n * When `tokenId` is provided, the simulation also computes forfeit amounts\n * by chaining the dispatch with `getFullPositionsData` reads\n * in a single multicall.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with settlement data or error\n */\nexport async function simulateSettle(\n params: SimulateSettleParams,\n): Promise<SimulationResult<SettleSimulation>> {\n const { client, poolAddress, account, positionIdList, tokenId, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // For settlement, we call dispatch with unchanged position lists\n const positionSizes = positionIdList.map(() => 0n)\n const tickAndSpreadLimits = positionIdList.map(() => [-887272n, 887272n, 0n] as const)\n\n // Encode dispatch call data\n const callData = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n positionIdList,\n positionIdList,\n positionSizes.map((s) => BigInt(s) as unknown as bigint & { readonly __uint128: true }),\n tickAndSpreadLimits.map(\n (t) => [Number(t[0]), Number(t[1]), Number(t[2])] as readonly [number, number, number],\n ),\n false,\n 0n,\n ],\n })\n\n // Simulate with token flow measurement using PanopticPool.multicall + getAssetsOf\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw (\n flowResult.rawError ?? new PanopticError(flowResult.error || 'Token flow simulation failed')\n )\n }\n\n const tokenFlow: TokenFlow = flowResult.tokenFlow\n\n // Compute forfeit amounts if tokenId is provided\n let forfeitAmounts: [bigint, bigint] | undefined\n if (tokenId !== undefined) {\n forfeitAmounts = await computeForfeitAmounts({\n client,\n poolAddress,\n account,\n positionIdList,\n tokenId,\n dispatchCallData: callData,\n blockNumber: targetBlockNumber,\n })\n }\n\n const _meta = await metaPromise\n\n // Build simulation result with actual token flow data\n // Positive delta = premia received\n const data: SettleSimulation = {\n premiaReceived0: tokenFlow.delta0 > 0n ? tokenFlow.delta0 : 0n,\n premiaReceived1: tokenFlow.delta1 > 0n ? tokenFlow.delta1 : 0n,\n postCollateral0: tokenFlow.balanceAfter0,\n postCollateral1: tokenFlow.balanceAfter1,\n forfeitAmounts,\n }\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n\n/**\n * Compute forfeit amounts by chaining dispatch + getFullPositionsData\n * in a single PanopticPool.multicall.\n */\nasync function computeForfeitAmounts(params: {\n client: PublicClient\n poolAddress: Address\n account: Address\n positionIdList: bigint[]\n tokenId: bigint\n dispatchCallData: Hex\n blockNumber: bigint\n}): Promise<[bigint, bigint]> {\n const { client, poolAddress, account, tokenId, dispatchCallData, blockNumber } = params\n\n // Encode getFullPositionsData calls (available = false, total = true)\n const feesCallAvailable = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, false, [tokenId]],\n })\n const feesCallTotal = encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n args: [account, true, [tokenId]],\n })\n\n try {\n // Chain: dispatch (settle) + fees(available) + fees(total) in one multicall\n const { result } = await client.simulateContract({\n address: poolAddress,\n abi: multicallAbi,\n functionName: 'multicall',\n args: [[dispatchCallData, feesCallAvailable, feesCallTotal]],\n account,\n blockNumber,\n })\n\n // Decode the two fee reads (result[0] is dispatch, result[1] and result[2] are fees)\n const decodeFeesResult = (data: Hex): bigint => {\n return decodeFunctionResult({\n abi: panopticPoolV2Abi,\n functionName: 'getFullPositionsData',\n data,\n })[0]\n }\n\n const availablePremium = decodeFeesResult(result[1])\n const totalPremium = decodeFeesResult(result[2])\n\n const available0 = availablePremium & BIT_MASK_128\n const available1 = availablePremium >> 128n\n const total0 = totalPremium & BIT_MASK_128\n const total1 = totalPremium >> 128n\n\n return [total0 - available0, total1 - available1]\n } catch (error) {\n throw new PanopticError(\n 'Forfeit amount computation failed',\n error instanceof Error ? error : undefined,\n )\n }\n}\n","/**\n * Vault simulation functions for the Panoptic v2 SDK.\n * @module v2/simulations/simulateVault\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { collateralTrackerV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport type { DepositSimulation, SimulationResult, WithdrawSimulation } from '../types'\n\n/**\n * Parameters for simulating deposit.\n */\nexport interface SimulateDepositParams {\n /** Public client */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Assets to deposit */\n assets: bigint\n /** Whether the collateral tracker wraps native ETH (requires sending msg.value) */\n isNativeETH?: boolean\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a deposit operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with deposit data or error\n */\nexport async function simulateDeposit(\n params: SimulateDepositParams,\n): Promise<SimulationResult<DepositSimulation>> {\n const { client, collateralTrackerAddress, account, assets, isNativeETH, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Run multicall (historical block), gas estimate (latest), and block meta in parallel\n const [[currentShares, currentAssets, previewedShares], gasEstimate, _meta] = await Promise.all(\n [\n client.multicall({\n contracts: [\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'balanceOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewDeposit',\n args: [assets],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n }),\n client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'deposit',\n args: [assets, account],\n account,\n ...(isNativeETH && { value: assets }),\n blockNumber: targetBlockNumber,\n }),\n metaPromise,\n ],\n )\n\n const data: DepositSimulation = {\n sharesMinted: previewedShares,\n postAssets: currentAssets + assets,\n postShares: currentShares + previewedShares,\n }\n\n return {\n success: true,\n data,\n gasEstimate,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n\n/**\n * Parameters for simulating withdrawal.\n */\nexport interface SimulateWithdrawParams {\n /** Public client */\n client: PublicClient\n /** CollateralTracker address */\n collateralTrackerAddress: Address\n /** Account address */\n account: Address\n /** Assets to withdraw */\n assets: bigint\n /** Optional block number for simulation */\n blockNumber?: bigint\n}\n\n/**\n * Simulate a withdrawal operation.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with withdrawal data or error\n */\nexport async function simulateWithdraw(\n params: SimulateWithdrawParams,\n): Promise<SimulationResult<WithdrawSimulation>> {\n const { client, collateralTrackerAddress, account, assets, blockNumber } = params\n\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n try {\n // Get current state\n const [currentShares, currentAssets, maxWithdrawable, previewedShares] = await client.multicall(\n {\n contracts: [\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'balanceOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'assetsOf',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'maxWithdraw',\n args: [account],\n },\n {\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'previewWithdraw',\n args: [assets],\n },\n ],\n blockNumber: targetBlockNumber,\n allowFailure: false,\n },\n )\n\n // Check if withdrawal is possible\n const canWithdraw = assets <= maxWithdrawable\n\n const _meta = await metaPromise\n\n if (!canWithdraw) {\n const data: WithdrawSimulation = {\n sharesBurned: 0n,\n assetsReceived: 0n,\n postAssets: currentAssets,\n postShares: currentShares,\n canWithdraw: false,\n reason: `Requested ${assets}, but max withdrawable is ${maxWithdrawable}`,\n }\n\n return {\n success: true,\n data,\n gasEstimate: 0n,\n _meta,\n }\n }\n\n const gasEstimate = await client.estimateContractGas({\n address: collateralTrackerAddress,\n abi: collateralTrackerV2Abi,\n functionName: 'withdraw',\n args: [assets, account, account],\n account,\n blockNumber: targetBlockNumber,\n })\n\n const data: WithdrawSimulation = {\n sharesBurned: previewedShares,\n assetsReceived: assets,\n postAssets: currentAssets - assets,\n postShares: currentShares - previewedShares,\n canWithdraw: true,\n }\n\n return {\n success: true,\n data,\n gasEstimate,\n _meta,\n }\n } catch (error) {\n const _meta = await metaPromise\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta,\n }\n }\n}\n","/**\n * SFPM simulation functions for the Panoptic v2 SDK.\n *\n * These simulate `mintTokenizedPosition` and `burnTokenizedPosition` on the\n * SemiFungiblePositionManager, called with `account: poolAddress` (the pool\n * is the caller in the actual protocol flow).\n *\n * @module v2/simulations/sfpm\n */\n\nimport type { Address, Hex, PublicClient } from 'viem'\nimport { encodeAbiParameters } from 'viem'\n\nimport { semiFungiblePositionManagerV4Abi } from '../../../generated'\nimport type { PoolKey } from '../types'\n\n/**\n * Encode a V4 PoolKey struct as bytes for the SFPM.\n */\nexport function encodePoolKeyBytes(poolKey: PoolKey): Hex {\n return encodeAbiParameters(\n [\n {\n type: 'tuple',\n components: [\n { name: 'currency0', type: 'address' },\n { name: 'currency1', type: 'address' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickSpacing', type: 'int24' },\n { name: 'hooks', type: 'address' },\n ],\n },\n ],\n [\n {\n currency0: poolKey.currency0,\n currency1: poolKey.currency1,\n fee: Number(poolKey.fee),\n tickSpacing: Number(poolKey.tickSpacing),\n hooks: poolKey.hooks,\n },\n ],\n )\n}\n\n/**\n * Encode a V3 pool address as poolKey bytes for the V3 SFPM.\n * V3 SFPM expects `abi.encode(uniswapV3PoolAddress)`.\n */\nexport function encodeV3PoolKeyBytes(v3PoolAddress: Address): Hex {\n return encodeAbiParameters([{ type: 'address' }], [v3PoolAddress])\n}\n\n/**\n * Parameters for simulating an SFPM mint or burn.\n */\nexport interface SimulateSFPMParams {\n /** Public client */\n client: PublicClient\n /** SemiFungiblePositionManager address */\n sfpmAddress: Address\n /** PanopticPool address (used as `account` — the pool is the caller) */\n poolAddress: Address\n /** Encoded pool key (bytes) */\n poolKey: Hex\n /** TokenId to mint/burn */\n tokenId: bigint\n /** Position size (uint128) */\n positionSize: bigint\n /** Lower tick limit */\n tickLimitLow: number\n /** Upper tick limit */\n tickLimitHigh: number\n}\n\n/** Return type from SFPM mintTokenizedPosition / burnTokenizedPosition */\nexport type SFPMSimulationResult = readonly [\n readonly [bigint, bigint, bigint, bigint],\n bigint,\n number,\n]\n\n/**\n * Simulate an SFPM mintTokenizedPosition call.\n *\n * @param params - Simulation parameters\n * @returns The result tuple: [collectedAmounts[4], totalSwapped, newTick]\n */\nexport async function simulateSFPMMint(params: SimulateSFPMParams): Promise<SFPMSimulationResult> {\n const {\n client,\n sfpmAddress,\n poolAddress,\n poolKey,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n } = params\n\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'mintTokenizedPosition',\n args: [\n poolKey,\n tokenId,\n BigInt(positionSize) as bigint & { readonly __uint128: true },\n tickLimitLow,\n tickLimitHigh,\n ],\n account: poolAddress,\n })\n\n return result\n}\n\n/**\n * Simulate an SFPM burnTokenizedPosition call.\n *\n * @param params - Simulation parameters\n * @returns The result tuple: [collectedAmounts[4], totalSwapped, newTick]\n */\nexport async function simulateSFPMBurn(params: SimulateSFPMParams): Promise<SFPMSimulationResult> {\n const {\n client,\n sfpmAddress,\n poolAddress,\n poolKey,\n tokenId,\n positionSize,\n tickLimitLow,\n tickLimitHigh,\n } = params\n\n const { result } = await client.simulateContract({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n functionName: 'burnTokenizedPosition',\n args: [\n poolKey,\n tokenId,\n BigInt(positionSize) as bigint & { readonly __uint128: true },\n tickLimitLow,\n tickLimitHigh,\n ],\n account: poolAddress,\n })\n\n return result\n}\n","/**\n * Swap simulation for the Panoptic v2 SDK.\n *\n * Mirrors `writes/swap.ts`, which swaps via width=0 **credit** legs rather than\n * loans so the swap can never be capped by a collateral tracker's utilization.\n *\n * @module v2/simulations/simulateSwap\n */\n\nimport type { Address, PublicClient } from 'viem'\nimport { encodeFunctionData } from 'viem'\n\nimport { panopticPoolV2Abi } from '../../../generated'\nimport { getBlockMeta } from '../clients'\nimport { PanopticError } from '../errors'\nimport { tickLimits } from '../formatters/tick'\nimport { getPool } from '../reads/pool'\nimport type { SimulationResult, TokenFlow } from '../types'\nimport { buildUniqueCredit, resolveTokenIndex } from '../writes/loanUtils'\nimport { simulateWithTokenFlow } from './tokenFlow'\n\n/**\n * Swap simulation data.\n */\nexport interface SwapSimulation {\n /** Amount of tokenIn spent (positive) */\n amountIn: bigint\n /** Amount of tokenOut received (positive) */\n amountOut: bigint\n /** Raw token flow from the simulation */\n tokenFlow: TokenFlow\n}\n\n/**\n * Parameters for simulateSwapExactOut.\n */\nexport interface SimulateSwapExactOutParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Chain ID */\n chainId: bigint\n /** Token address to receive */\n tokenOut: Address\n /** Exact amount of tokenOut */\n amountOut: bigint\n /** Slippage tolerance in bps */\n slippageBps: bigint\n /** Existing position IDs */\n existingPositionIds: bigint[]\n /** Builder code for referral fee attribution. Defaults to `0n`. */\n builderCode?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Parameters for simulateSwapExactIn.\n */\nexport interface SimulateSwapExactInParams {\n /** Public client */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** Account address */\n account: Address\n /** Chain ID */\n chainId: bigint\n /** Token address to sell */\n tokenIn: Address\n /** Exact amount of tokenIn */\n amountIn: bigint\n /** Slippage tolerance in bps */\n slippageBps: bigint\n /** Existing position IDs */\n existingPositionIds: bigint[]\n /** Builder code for referral fee attribution. Defaults to `0n`. */\n builderCode?: bigint\n /** Optional block number */\n blockNumber?: bigint\n}\n\n/**\n * Build dispatch calldata for swap simulation.\n */\nfunction buildSwapCallData(\n creditTokenId: bigint,\n existingPositionIds: bigint[],\n amount: bigint,\n mintTickLimits: readonly [number, number, number],\n burnTickLimits: readonly [number, number, number],\n builderCode: bigint,\n): `0x${string}` {\n return encodeFunctionData({\n abi: panopticPoolV2Abi,\n functionName: 'dispatch',\n args: [\n [creditTokenId, creditTokenId],\n [...existingPositionIds],\n [amount, 0n],\n [mintTickLimits, burnTickLimits],\n false,\n builderCode,\n ],\n })\n}\n\n/**\n * Build SwapSimulation from token flow, given which token index is \"out\".\n */\nfunction buildSwapResult(tokenFlow: TokenFlow, tokenOutIndex: bigint): SwapSimulation {\n // delta is negative when user deposits, positive when user receives\n // For a swap: one delta should be negative (spent) and one positive (received)\n const delta0 = tokenFlow.delta0\n const delta1 = tokenFlow.delta1\n\n if (tokenOutIndex === 0n) {\n return {\n amountOut: delta0 > 0n ? delta0 : -delta0,\n amountIn: delta1 < 0n ? -delta1 : delta1,\n tokenFlow,\n }\n } else {\n return {\n amountOut: delta1 > 0n ? delta1 : -delta1,\n amountIn: delta0 < 0n ? -delta0 : delta0,\n tokenFlow,\n }\n }\n}\n\n/**\n * Simulate an exact-output swap.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with swap data or error\n */\nexport async function simulateSwapExactOut(\n params: SimulateSwapExactOutParams,\n): Promise<SimulationResult<SwapSimulation>> {\n const {\n client,\n poolAddress,\n account,\n chainId,\n tokenOut,\n amountOut,\n slippageBps,\n existingPositionIds,\n builderCode = 0n,\n blockNumber,\n } = params\n\n try {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n const pool = await getPool({ client, poolAddress, chainId, blockNumber: targetBlockNumber })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const tokenOutIndex = resolveTokenIndex(tokenOut, token0, token1)\n // Credit is denominated in the exact token (tokenOut); asset === tokenType.\n // Using the counter-token here is the loan convention and inverts the swap.\n const tokenType = tokenOutIndex\n\n const { low: tickLimitLow, high: tickLimitHigh } = tickLimits(pool.currentTick, slippageBps)\n\n const { tokenId: creditTokenId, adjustedSize } = buildUniqueCredit(\n pool.poolId,\n tokenOutIndex,\n tokenType,\n pool.currentTick,\n pool.tickSpacing,\n existingPositionIds,\n amountOut,\n )\n\n // Mint: swapAtMint=true (descending), Burn: swapAtMint=false (ascending)\n const mintTickLimits: readonly [number, number, number] = [\n Number(tickLimitHigh),\n Number(tickLimitLow),\n 0,\n ]\n const burnTickLimits: readonly [number, number, number] = [\n Number(tickLimitLow),\n Number(tickLimitHigh),\n 0,\n ]\n\n const callData = buildSwapCallData(\n creditTokenId,\n existingPositionIds,\n adjustedSize,\n mintTickLimits,\n burnTickLimits,\n builderCode,\n )\n\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw flowResult.rawError ?? new PanopticError(flowResult.error || 'Swap simulation failed')\n }\n\n const _meta = await metaPromise\n const data = buildSwapResult(flowResult.tokenFlow, tokenOutIndex)\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow: flowResult.tokenFlow,\n _meta,\n }\n } catch (error) {\n // Build a fallback _meta if getBlockMeta also failed\n const fallbackMeta = { blockNumber: 0n, blockTimestamp: 0n, blockHash: '0x0' as `0x${string}` }\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta: fallbackMeta,\n }\n }\n}\n\n/**\n * Simulate an exact-input swap.\n *\n * @param params - Simulation parameters\n * @returns Simulation result with swap data or error\n */\nexport async function simulateSwapExactIn(\n params: SimulateSwapExactInParams,\n): Promise<SimulationResult<SwapSimulation>> {\n const {\n client,\n poolAddress,\n account,\n chainId,\n tokenIn,\n amountIn,\n slippageBps,\n existingPositionIds,\n builderCode = 0n,\n blockNumber,\n } = params\n\n try {\n const targetBlockNumber = blockNumber ?? (await client.getBlockNumber())\n const metaPromise = getBlockMeta({ client, blockNumber: targetBlockNumber })\n\n const pool = await getPool({ client, poolAddress, chainId, blockNumber: targetBlockNumber })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const tokenInIndex = resolveTokenIndex(tokenIn, token0, token1)\n const tokenType = tokenInIndex\n\n const { low: tickLimitLow, high: tickLimitHigh } = tickLimits(pool.currentTick, slippageBps)\n\n const { tokenId: creditTokenId, adjustedSize } = buildUniqueCredit(\n pool.poolId,\n tokenInIndex,\n tokenType,\n pool.currentTick,\n pool.tickSpacing,\n existingPositionIds,\n amountIn,\n )\n\n // Mint: swapAtMint=false (ascending), Burn: swapAtMint=true (descending)\n const mintTickLimits: readonly [number, number, number] = [\n Number(tickLimitLow),\n Number(tickLimitHigh),\n 0,\n ]\n const burnTickLimits: readonly [number, number, number] = [\n Number(tickLimitHigh),\n Number(tickLimitLow),\n 0,\n ]\n\n // tokenOut is the OTHER token\n const tokenOutIndex = tokenInIndex === 0n ? 1n : 0n\n\n const callData = buildSwapCallData(\n creditTokenId,\n existingPositionIds,\n adjustedSize,\n mintTickLimits,\n burnTickLimits,\n builderCode,\n )\n\n const flowResult = await simulateWithTokenFlow({\n client,\n poolAddress,\n user: account,\n callData,\n blockNumber: targetBlockNumber,\n })\n\n if (!flowResult.success || !flowResult.tokenFlow) {\n throw flowResult.rawError ?? new PanopticError(flowResult.error || 'Swap simulation failed')\n }\n\n const _meta = await metaPromise\n const data = buildSwapResult(flowResult.tokenFlow, tokenOutIndex)\n\n return {\n success: true,\n data,\n gasEstimate: flowResult.gasEstimate,\n tokenFlow: flowResult.tokenFlow,\n _meta,\n }\n } catch (error) {\n const fallbackMeta = { blockNumber: 0n, blockTimestamp: 0n, blockHash: '0x0' as `0x${string}` }\n return {\n success: false,\n error:\n error instanceof PanopticError\n ? error\n : new PanopticError(\n error instanceof Error ? error.message : 'Simulation failed',\n error instanceof Error ? error : undefined,\n ),\n _meta: fallbackMeta,\n }\n }\n}\n","/**\n * Price conversion between the two pool tokens at a given sqrtPriceX96.\n *\n * Mirrors the on-chain `PanopticMath.convert0to1` / `convert1to0` truncation,\n * with an overflow-safe branch for when `sqrtPriceX96^2` would not fit in a\n * uint256.\n *\n * @module v2/utils/priceConvert\n */\n\nimport { PanopticError } from '../errors'\n\nconst Q128 = 1n << 128n\n\n/**\n * A non-positive price has no meaningful conversion, and `convert1to0` would\n * divide by zero — surface that as a typed SDK error rather than a RangeError\n * thrown from inside the arithmetic.\n */\nfunction assertPositivePrice(sqrtPriceX96: bigint): void {\n if (sqrtPriceX96 <= 0n) {\n throw new PanopticError(`sqrtPriceX96 must be positive, got ${sqrtPriceX96}`)\n }\n}\n\n/** Convert a token0 amount to its token1-equivalent at the given sqrtPriceX96. */\nexport function convert0to1(amount: bigint, sqrtPriceX96: bigint): bigint {\n assertPositivePrice(sqrtPriceX96)\n if (sqrtPriceX96 < Q128) {\n return (amount * sqrtPriceX96 * sqrtPriceX96) >> 192n\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * sp2Hi) >> 128n\n}\n\n/** Convert a token1 amount to its token0-equivalent at the given sqrtPriceX96. */\nexport function convert1to0(amount: bigint, sqrtPriceX96: bigint): bigint {\n assertPositivePrice(sqrtPriceX96)\n if (sqrtPriceX96 < Q128) {\n const denom = sqrtPriceX96 * sqrtPriceX96\n return (amount * (1n << 192n)) / denom\n }\n const sp2Hi = (sqrtPriceX96 * sqrtPriceX96) >> 64n\n return (amount * (1n << 128n)) / sp2Hi\n}\n\n/**\n * Convert an amount denominated in `fromTokenIndex` into the other token's\n * terms, so the two sides of a pool flow can be compared on one scale.\n */\nexport function convertToTokenIndex(\n amount: bigint,\n fromTokenIndex: bigint,\n toTokenIndex: bigint,\n sqrtPriceX96: bigint,\n): bigint {\n if (fromTokenIndex === toTokenIndex) return amount\n return fromTokenIndex === 0n\n ? convert0to1(amount, sqrtPriceX96)\n : convert1to0(amount, sqrtPriceX96)\n}\n","/**\n * \"One token out\": force the net token flow of an arbitrary dispatch into a\n * single collateral token.\n *\n * Closing a multi-leg position normally settles in BOTH collateral tokens — a\n * straddle with one ITM leg pays out in one and charges in the other. This\n * module wraps the user's dispatch with a temporary width=0 credit leg that\n * cancels the non-target side, so the account's net change is (up to dust) in\n * one token only.\n *\n * Generalises {@link quoteTokenShortfallRecovery}, which handles the same\n * mechanism but only in the \"user is short a token\" direction and only when the\n * pool has already reverted with `NotEnoughTokens`.\n *\n * @module v2/simulations/oneTokenFlow\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport { PanopticError } from '../errors'\nimport { getPool } from '../reads/pool'\nimport type { BlockMeta, TokenFlow } from '../types'\nimport { MAX_TICK, MIN_TICK } from '../utils/constants'\nimport { convertToTokenIndex } from '../utils/priceConvert'\nimport { buildUniqueCredit } from '../writes/loanUtils'\nimport {\n type CreditWrapDirection,\n type DispatchIntent,\n buildCreditWrappedDispatch,\n} from './creditWrap'\nimport { simulateDispatch } from './simulateDispatch'\nimport { getNotEnoughTokensError } from './tokenShortfallRecovery'\n\nconst BPS_DENOMINATOR = 10_000n\n\n/**\n * Default {@link OneTokenFlowQuoteParams.minSwapRatioBps}: 0.5%.\n *\n * A swap pays a pool fee of roughly 5-30 bps plus slippage, so a non-target\n * flow below this fraction of the target flow cannot pay for itself — while\n * still leaving any residual small enough not to surprise someone who asked to\n * settle in one token.\n */\nexport const DEFAULT_MIN_SWAP_RATIO_BPS = 50n\n\nexport interface OneTokenFlowQuoteParams {\n client: PublicClient\n poolAddress: Address\n account: Address\n chainId: bigint\n /** The user's actual on-chain position list BEFORE the dispatch. */\n existingPositionIds: bigint[]\n /** The dispatch the user is about to send, unwrapped. */\n dispatch: DispatchIntent\n /** Index of the token the whole net flow should land in: `0n` or `1n`. */\n targetTokenIndex: bigint\n /**\n * Slippage tolerance for the credit swap, in **basis points** (1% = 100).\n * Applied to the estimated target-token cost of an exact-out swap to produce\n * `maximumAmountIn`. Values above `10_000` (100%) are rejected.\n */\n slippageBps: bigint\n /**\n * Minimum size of the non-target flow, in **basis points** of the target\n * token's own flow, for the swap to be worth doing. Below this the residual\n * is dust and the swap would cost more in pool fee and slippage than it\n * settles, so the quote reports `below-threshold` and the caller falls back\n * to the native two-token flow. Defaults to\n * {@link DEFAULT_MIN_SWAP_RATIO_BPS}. Pass `0n` to always swap.\n *\n * Only applied when the unwrapped dispatch simulates successfully. When it\n * reverts on a shortfall, the swap is what makes the transaction possible at\n * all, so no threshold is applied.\n */\n minSwapRatioBps?: bigint\n /**\n * Price bound for the temporary credit legs. Defaults to the full tick range —\n * the swap is protected economically by the balance check, not by a price\n * band, and the user's own operations keep their own limits.\n */\n tickLimitLow?: bigint\n /** See {@link OneTokenFlowQuoteParams.tickLimitLow}. */\n tickLimitHigh?: bigint\n blockNumber?: bigint\n}\n\nexport interface OneTokenFlowQuote {\n targetToken: Address\n otherToken: Address\n targetTokenIndex: bigint\n otherTokenIndex: bigint\n direction: CreditWrapDirection\n /**\n * Amount of `otherToken` the credit sources (`exact-out`) or sells\n * (`exact-in`) — i.e. the non-target flow being cancelled.\n */\n swapAmount: bigint\n /**\n * Target-token side of the swap leg alone, priced by a swap-only simulation:\n * spent for `exact-out`, received for `exact-in`. NOT the same as\n * `netTargetChange`, which also includes the user's own operations.\n */\n estimatedCounterAmount: bigint\n /** `estimatedCounterAmount` padded by `slippageBps`. `exact-out` only. */\n maximumAmountIn: bigint\n slippageBps: bigint\n /** Signed net change of the target token across the ENTIRE wrapped tx. */\n netTargetChange: bigint\n /**\n * Signed net change of the other token across the entire wrapped tx — the\n * residual dust left by sizing the credit from a single simulation. Disclose\n * this to the user rather than claiming an exact zero.\n */\n residualOtherChange: bigint\n /** The temporary width=0 credit leg used to move the flow. */\n creditTokenId: bigint\n dispatch: DispatchIntent\n tokenFlow: TokenFlow\n _meta: BlockMeta\n}\n\nexport type OneTokenFlowUnavailableReason =\n | 'already-single-token'\n | 'below-threshold'\n | 'base-simulation-failed'\n | 'invalid-slippage'\n | 'invalid-target-token'\n | 'invalid-tick-limits'\n | 'swap-unavailable'\n | 'wrap-unavailable'\n\nexport type OneTokenFlowResult =\n | { available: true; quote: OneTokenFlowQuote }\n | {\n available: false\n reason: OneTokenFlowUnavailableReason\n /** Human-readable description of the sub-step that failed, for diagnostics. */\n detail?: string\n error?: PanopticError\n }\n\nfunction deltaAt(tokenFlow: TokenFlow, index: bigint): bigint {\n return index === 0n ? tokenFlow.delta0 : tokenFlow.delta1\n}\n\nfunction balanceBeforeAt(tokenFlow: TokenFlow, index: bigint): bigint {\n return index === 0n ? tokenFlow.balanceBefore0 : tokenFlow.balanceBefore1\n}\n\nfunction abs(value: bigint): bigint {\n return value < 0n ? -value : value\n}\n\nfunction padForSlippage(amount: bigint, slippageBps: bigint): bigint {\n return (amount * (BPS_DENOMINATOR + slippageBps) + BPS_DENOMINATOR - 1n) / BPS_DENOMINATOR\n}\n\n/**\n * Quote a dispatch wrapped so its net flow lands in `targetTokenIndex` only.\n *\n * Three simulations, all pinned to one block and with no convergence loop:\n *\n * 1. the user's dispatch as-is, to measure the non-target flow to cancel;\n * 2. the credit legs alone, to price the swap and check the source balance;\n * 3. the wrapped dispatch, whose token flow is what the user is shown and what\n * the residual dust is read from.\n */\nexport async function quoteOneTokenFlow(\n params: OneTokenFlowQuoteParams,\n): Promise<OneTokenFlowResult> {\n const { targetTokenIndex } = params\n const minSwapRatioBps = params.minSwapRatioBps ?? DEFAULT_MIN_SWAP_RATIO_BPS\n if (targetTokenIndex !== 0n && targetTokenIndex !== 1n) {\n return {\n available: false,\n reason: 'invalid-target-token',\n detail: `targetTokenIndex=${targetTokenIndex} is neither 0 nor 1`,\n }\n }\n if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR) {\n return {\n available: false,\n reason: 'invalid-slippage',\n detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR}]`,\n }\n }\n const tickLimitLow = params.tickLimitLow ?? MIN_TICK\n const tickLimitHigh = params.tickLimitHigh ?? MAX_TICK\n if (tickLimitLow >= tickLimitHigh) {\n return {\n available: false,\n reason: 'invalid-tick-limits',\n detail: `tickLimitLow=${tickLimitLow} >= tickLimitHigh=${tickLimitHigh}`,\n }\n }\n\n const otherTokenIndex = targetTokenIndex === 0n ? 1n : 0n\n const targetBlockNumber = params.blockNumber ?? (await params.client.getBlockNumber())\n const simulateArgs = {\n client: params.client,\n poolAddress: params.poolAddress,\n account: params.account,\n existingPositionIdList: params.existingPositionIds,\n blockNumber: targetBlockNumber,\n }\n\n // Read ahead of the simulation: the shortfall branch below has to know which\n // collateral a NotEnoughTokens revert refers to before it can size a credit.\n const pool = await getPool({\n client: params.client,\n poolAddress: params.poolAddress,\n chainId: params.chainId,\n blockNumber: targetBlockNumber,\n })\n const token0 = pool.collateralTracker0.token\n const token1 = pool.collateralTracker1.token\n const targetToken = targetTokenIndex === 0n ? token0 : token1\n const otherToken = otherTokenIndex === 0n ? token0 : token1\n // NotEnoughTokens is raised by the CollateralTracker and carries ITS address,\n // not the underlying token's.\n const otherTracker =\n otherTokenIndex === 0n ? pool.collateralTracker0.address : pool.collateralTracker1.address\n\n // 1. The user's dispatch as-is. When it reverts because the account is short\n // the non-target token, the revert itself quantifies the flow to cancel —\n // so one-token-out subsumes the plain shortfall-recovery case.\n const baseSimulation = await simulateDispatch({ ...simulateArgs, ...params.dispatch })\n let swapAmount: bigint\n let direction: CreditWrapDirection\n // The target-token flow of the user's ops alone. Null when the base dispatch\n // reverted, which only happens on the exact-out path.\n let baseTargetDelta: bigint | null = null\n if (baseSimulation.success && baseSimulation.tokenFlow !== undefined) {\n baseTargetDelta = deltaAt(baseSimulation.tokenFlow, targetTokenIndex)\n const otherDelta = deltaAt(baseSimulation.tokenFlow, otherTokenIndex)\n if (otherDelta === 0n) {\n return {\n available: false,\n reason: 'already-single-token',\n detail: 'the dispatch does not move the non-target token',\n }\n }\n // delta < 0: the account PAYS the other token — source it (exact-out).\n // delta > 0: the account RECEIVES it — sell it into the target (exact-in).\n direction = otherDelta < 0n ? 'exact-out' : 'exact-in'\n swapAmount = abs(otherDelta)\n } else {\n const shortfall = baseSimulation.success ? null : getNotEnoughTokensError(baseSimulation.error)\n if (shortfall === null) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: baseSimulation.success\n ? 'base simulation returned no token flow'\n : `base simulation reverted: ${baseSimulation.error.message}`,\n error: baseSimulation.success ? undefined : baseSimulation.error,\n }\n }\n // Only a shortfall in the NON-target collateral can be sized as a credit in\n // otherTokenIndex. A shortfall in the target token (or in neither) means the\n // account cannot fund the position at all, and sourcing the other token\n // would quote a swap that does not address it.\n if (shortfall.tokenAddress.toLowerCase() !== otherTracker.toLowerCase()) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: `shortfall is in ${shortfall.tokenAddress}, not the non-target collateral ${otherTracker}`,\n error: baseSimulation.success ? undefined : baseSimulation.error,\n }\n }\n const pending = shortfall.assetsRequested - shortfall.assetBalance\n if (pending <= 0n) {\n return {\n available: false,\n reason: 'base-simulation-failed',\n detail: `requested=${shortfall.assetsRequested} <= balance=${shortfall.assetBalance}`,\n }\n }\n direction = 'exact-out'\n swapAmount = pending\n }\n\n // Dust gate. The non-target flow is only worth swapping if it is material\n // next to the flow being settled; below that the swap burns a pool fee and\n // slippage to move an amount the user cannot see. Skipped when the base\n // dispatch reverted (baseTargetDelta === null), because there the swap is\n // what makes the transaction possible rather than a convenience.\n //\n // Compared in the target token's terms so the two sides share a scale. Note\n // this is deliberately NOT a fraction of notional: Neutralize ITM drives the\n // net flow toward zero while notional stays large, which would suppress the\n // swap on nearly every neutralized position.\n if (baseTargetDelta !== null && minSwapRatioBps > 0n) {\n const swapInTargetTerms = convertToTokenIndex(\n swapAmount,\n otherTokenIndex,\n targetTokenIndex,\n pool.sqrtPriceX96,\n )\n if (swapInTargetTerms * BPS_DENOMINATOR < minSwapRatioBps * abs(baseTargetDelta)) {\n return {\n available: false,\n reason: 'below-threshold',\n detail:\n `non-target flow ${swapInTargetTerms} (in target token terms) is below ` +\n `${minSwapRatioBps}bps of the target flow ${abs(baseTargetDelta)}`,\n }\n }\n }\n\n // asset === tokenType === otherTokenIndex: the credit is denominated in the\n // token whose flow is being cancelled. Passing the counter-token as tokenType\n // is the LOAN convention and silently inverts the swap.\n const collisionIds = Array.from(\n new Set([\n ...params.existingPositionIds,\n ...params.dispatch.positionIdList,\n ...params.dispatch.finalPositionIdList,\n ]),\n )\n const credit = buildUniqueCredit(\n pool.poolId,\n otherTokenIndex,\n otherTokenIndex,\n pool.currentTick,\n pool.tickSpacing,\n collisionIds,\n swapAmount,\n )\n\n // exact-out must straddle the user's ops so the sourced token is available\n // while they run; exact-in can only follow them, since the token being sold\n // does not exist until they have run.\n const placement = direction === 'exact-out' ? 'straddle' : 'append'\n const creditWrapArgs = {\n creditTokenId: credit.tokenId,\n creditPositionSize: credit.adjustedSize,\n tickLimitLow,\n tickLimitHigh,\n direction,\n placement,\n } as const\n\n // 2. For exact-out ONLY, the credit legs alone: prices the swap and proves the\n // account can cover it out of the target token before it is committed to.\n //\n // Deliberately skipped for exact-in. There, the token being sold does not\n // exist until the user's ops have run, so a swap-only simulation reverts\n // for an account holding none of it — refusing a wrap that would in fact\n // have worked. Its price is recovered from the wrapped run instead, and no\n // balance guard is needed since the ops themselves fund the sale.\n let estimatedCounterAmount = 0n\n let maximumAmountIn = 0n\n if (direction === 'exact-out') {\n const swapOnlyDispatch = buildCreditWrappedDispatch({\n ...creditWrapArgs,\n dispatch: {\n positionIdList: [],\n finalPositionIdList: [...params.existingPositionIds],\n positionSizes: [],\n tickAndSpreadLimits: [],\n usePremiaAsCollateral: false,\n builderCode: 0n,\n },\n })\n const swapSimulation = await simulateDispatch({ ...simulateArgs, ...swapOnlyDispatch })\n if (!swapSimulation.success || swapSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: swapSimulation.success\n ? 'swap-only simulation returned no token flow'\n : `swap-only simulation reverted: ${swapSimulation.error.message}`,\n error: swapSimulation.success ? undefined : swapSimulation.error,\n }\n }\n estimatedCounterAmount = abs(deltaAt(swapSimulation.tokenFlow, targetTokenIndex))\n maximumAmountIn = padForSlippage(estimatedCounterAmount, params.slippageBps)\n const sourceBalance = balanceBeforeAt(swapSimulation.tokenFlow, targetTokenIndex)\n if (sourceBalance < maximumAmountIn) {\n return {\n available: false,\n reason: 'swap-unavailable',\n detail: `source balance ${sourceBalance} < maximumAmountIn ${maximumAmountIn} (estimated ${estimatedCounterAmount}, slippageBps ${params.slippageBps})`,\n error: new PanopticError('Insufficient collateral to fund the one-token-out swap'),\n }\n }\n }\n\n // 3. The wrapped dispatch. Single pass — the swap itself shifts fees and\n // commission slightly, so the non-target side lands near, not exactly at,\n // zero. That remainder is surfaced as `residualOtherChange`.\n const wrappedDispatch = buildCreditWrappedDispatch({\n ...creditWrapArgs,\n dispatch: params.dispatch,\n })\n const wrappedSimulation = await simulateDispatch({ ...simulateArgs, ...wrappedDispatch })\n if (!wrappedSimulation.success || wrappedSimulation.tokenFlow === undefined) {\n return {\n available: false,\n reason: 'wrap-unavailable',\n detail: wrappedSimulation.success\n ? 'wrapped dispatch simulation returned no token flow'\n : `wrapped dispatch reverted: ${wrappedSimulation.error.message}`,\n error: wrappedSimulation.success ? undefined : wrappedSimulation.error,\n }\n }\n\n // exact-in never priced the swap on its own (see above): recover it as the\n // extra target-token the wrap produced over the plain dispatch.\n if (direction === 'exact-in' && baseTargetDelta !== null) {\n estimatedCounterAmount = abs(\n deltaAt(wrappedSimulation.tokenFlow, targetTokenIndex) - baseTargetDelta,\n )\n }\n\n return {\n available: true,\n quote: {\n targetToken,\n otherToken,\n targetTokenIndex,\n otherTokenIndex,\n direction,\n swapAmount,\n estimatedCounterAmount,\n maximumAmountIn,\n slippageBps: params.slippageBps,\n netTargetChange: deltaAt(wrappedSimulation.tokenFlow, targetTokenIndex),\n residualOtherChange: deltaAt(wrappedSimulation.tokenFlow, otherTokenIndex),\n creditTokenId: credit.tokenId,\n dispatch: wrappedDispatch,\n tokenFlow: wrappedSimulation.tokenFlow,\n _meta: wrappedSimulation._meta,\n },\n }\n}\n","/**\n * Uniswap v4 PoolManager event ABI (subset for event watching).\n * @module abis/poolManager\n */\n\nexport const poolManagerAbi = [\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'tickLower', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'tickUpper', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'liquidityDelta', internalType: 'int256', type: 'int256', indexed: false },\n { name: 'salt', internalType: 'bytes32', type: 'bytes32', indexed: false },\n ],\n name: 'ModifyLiquidity',\n },\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'amount0', internalType: 'int128', type: 'int128', indexed: false },\n { name: 'amount1', internalType: 'int128', type: 'int128', indexed: false },\n { name: 'sqrtPriceX96', internalType: 'uint160', type: 'uint160', indexed: false },\n { name: 'liquidity', internalType: 'uint128', type: 'uint128', indexed: false },\n { name: 'tick', internalType: 'int24', type: 'int24', indexed: false },\n { name: 'fee', internalType: 'uint24', type: 'uint24', indexed: false },\n ],\n name: 'Swap',\n },\n {\n type: 'event',\n anonymous: false,\n inputs: [\n { name: 'id', internalType: 'PoolId', type: 'bytes32', indexed: true },\n { name: 'sender', internalType: 'address', type: 'address', indexed: true },\n { name: 'amount0', internalType: 'uint256', type: 'uint256', indexed: false },\n { name: 'amount1', internalType: 'uint256', type: 'uint256', indexed: false },\n ],\n name: 'Donate',\n },\n] as const\n","/**\n * Simple WebSocket event watching for the Panoptic v2 SDK.\n * @module v2/events/watchEvents\n */\n\nimport type { Address, Hash, Log, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { PanopticEvent, PanopticEventType } from '../types'\nimport { decodeLeftRightSigned, decodePositionBalance } from '../writes/utils'\n\n/**\n * A decoded contract event log that includes both base Log fields and typed args.\n * viem's getContractEvents/watchContractEvent return logs with `.args`,\n * but the generic `Log` type doesn't include it. We use `unknown` for args\n * and narrow to specific types in each parse function's switch cases.\n */\ntype DecodedLog = Log & { args: unknown }\n\n/**\n * Parameters for watching events.\n */\nexport interface WatchEventsParams {\n /** Public client (must have WebSocket transport for real-time watching) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors */\n onError?: (error: Error) => void\n}\n\n/**\n * Event name to ABI event mapping for PanopticPool.\n */\nconst POOL_EVENT_NAMES: Record<string, PanopticEventType> = {\n OptionMinted: 'OptionMinted',\n OptionBurnt: 'OptionBurnt',\n AccountLiquidated: 'AccountLiquidated',\n ForcedExercised: 'ForcedExercised',\n PremiumSettled: 'PremiumSettled',\n}\n\n/**\n * Event name to ABI event mapping for CollateralTracker.\n */\nconst COLLATERAL_EVENT_NAMES: Record<string, PanopticEventType> = {\n Deposit: 'Deposit',\n Withdraw: 'Withdraw',\n ProtocolLossRealized: 'ProtocolLossRealized',\n}\n\n/**\n * Event name to ABI event mapping for RiskEngine.\n */\nconst RISK_ENGINE_EVENT_NAMES: Record<string, PanopticEventType> = {\n BorrowRateUpdated: 'BorrowRateUpdated',\n}\n\n/**\n * Event name to ABI event mapping for SFPM.\n */\nconst SFPM_EVENT_NAMES: Record<string, PanopticEventType> = {\n LiquidityChunkUpdated: 'LiquidityChunkUpdated',\n}\n\n/**\n * Event name to ABI event mapping for v4 PoolManager.\n */\nconst POOL_MANAGER_EVENT_NAMES: Record<string, PanopticEventType> = {\n ModifyLiquidity: 'ModifyLiquidity',\n Swap: 'Swap',\n Donate: 'Donate',\n}\n\n/**\n * Parse a decoded log into a typed PanopticEvent.\n */\nfunction parsePoolLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n // Type narrowing based on event name\n switch (eventName) {\n case 'OptionMinted': {\n const args = log.args as { recipient: Address; tokenId: bigint; balanceData: bigint }\n const balanceData = decodePositionBalance(args.balanceData)\n return {\n type: 'OptionMinted',\n ...baseEvent,\n recipient: args.recipient,\n tokenId: args.tokenId,\n positionSize: balanceData.positionSize,\n poolUtilization0: balanceData.poolUtilization0,\n poolUtilization1: balanceData.poolUtilization1,\n tickAtMint: balanceData.tickAtMint,\n timestampAtMint: balanceData.timestampAtMint,\n blockAtMint: balanceData.blockAtMint,\n swapAtMint: balanceData.swapAtMint,\n }\n }\n\n case 'OptionBurnt': {\n const args = log.args as {\n recipient: Address\n positionSize: bigint\n tokenId: bigint\n premiaByLeg: readonly [bigint, bigint, bigint, bigint]\n }\n return {\n type: 'OptionBurnt',\n ...baseEvent,\n recipient: args.recipient,\n tokenId: args.tokenId,\n positionSize: args.positionSize,\n premiaByLeg: args.premiaByLeg,\n }\n }\n\n case 'AccountLiquidated': {\n const args = log.args as { liquidator: Address; liquidatee: Address; bonusAmounts: bigint }\n const bonus = decodeLeftRightSigned(args.bonusAmounts)\n return {\n type: 'AccountLiquidated',\n ...baseEvent,\n liquidator: args.liquidator,\n liquidatee: args.liquidatee,\n bonusAmount0: bonus.right,\n bonusAmount1: bonus.left,\n }\n }\n\n case 'ForcedExercised': {\n const args = log.args as {\n exercisor: Address\n user: Address\n tokenId: bigint\n exerciseFee: bigint\n }\n const fee = decodeLeftRightSigned(args.exerciseFee)\n return {\n type: 'ForcedExercised',\n ...baseEvent,\n exercisor: args.exercisor,\n user: args.user,\n tokenId: args.tokenId,\n exerciseFee0: fee.right,\n exerciseFee1: fee.left,\n }\n }\n\n case 'PremiumSettled': {\n const args = log.args as {\n user: Address\n tokenId: bigint\n legIndex: bigint\n settledAmounts: bigint\n }\n const settled = decodeLeftRightSigned(args.settledAmounts)\n return {\n type: 'PremiumSettled',\n ...baseEvent,\n user: args.user,\n tokenId: args.tokenId,\n legIndex: args.legIndex,\n settledAmount0: settled.right,\n settledAmount1: settled.left,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a CollateralTracker log into a typed PanopticEvent.\n */\nfunction parseCollateralLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'Deposit': {\n const args = log.args as { sender: Address; owner: Address; assets: bigint; shares: bigint }\n return {\n type: 'Deposit',\n ...baseEvent,\n sender: args.sender,\n owner: args.owner,\n assets: args.assets,\n shares: args.shares,\n }\n }\n\n case 'Withdraw': {\n const args = log.args as {\n sender: Address\n receiver: Address\n owner: Address\n assets: bigint\n shares: bigint\n }\n return {\n type: 'Withdraw',\n ...baseEvent,\n sender: args.sender,\n receiver: args.receiver,\n owner: args.owner,\n assets: args.assets,\n shares: args.shares,\n }\n }\n\n case 'ProtocolLossRealized': {\n const args = log.args as {\n liquidatee: Address\n liquidator: Address\n protocolLossAssets: bigint\n protocolLossShares: bigint\n }\n return {\n type: 'ProtocolLossRealized',\n ...baseEvent,\n liquidatee: args.liquidatee,\n liquidator: args.liquidator,\n protocolLossAssets: args.protocolLossAssets,\n protocolLossShares: args.protocolLossShares,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a RiskEngine log into a typed PanopticEvent.\n */\nfunction parseRiskEngineLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'BorrowRateUpdated': {\n const args = log.args as {\n collateralToken: Address\n avgBorrowRate: bigint\n rateAtTarget: bigint\n }\n return {\n type: 'BorrowRateUpdated',\n ...baseEvent,\n collateralToken: args.collateralToken,\n avgBorrowRate: args.avgBorrowRate,\n rateAtTarget: args.rateAtTarget,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse an SFPM log into a typed PanopticEvent.\n */\nfunction parseSfpmLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'LiquidityChunkUpdated': {\n const args = log.args as {\n poolId: Hash\n owner: Address\n tokenType: bigint\n tickLower: number\n tickUpper: number\n liquidityDelta: bigint\n }\n return {\n type: 'LiquidityChunkUpdated',\n ...baseEvent,\n poolId: args.poolId,\n owner: args.owner,\n tokenType: args.tokenType,\n tickLower: args.tickLower,\n tickUpper: args.tickUpper,\n liquidityDelta: args.liquidityDelta,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Parse a v4 PoolManager log into a typed PanopticEvent.\n */\nfunction parsePoolManagerLog(log: DecodedLog, eventName: string): PanopticEvent | null {\n const baseEvent = {\n transactionHash: log.transactionHash!,\n blockNumber: log.blockNumber!,\n blockHash: log.blockHash!,\n logIndex: BigInt(log.logIndex!),\n }\n\n switch (eventName) {\n case 'ModifyLiquidity': {\n const args = log.args as {\n id: Hash\n sender: Address\n tickLower: number\n tickUpper: number\n liquidityDelta: bigint\n salt: Hash\n }\n return {\n type: 'ModifyLiquidity',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n tickLower: args.tickLower,\n tickUpper: args.tickUpper,\n liquidityDelta: args.liquidityDelta,\n salt: args.salt,\n }\n }\n\n case 'Swap': {\n const args = log.args as {\n id: Hash\n sender: Address\n amount0: bigint\n amount1: bigint\n sqrtPriceX96: bigint\n liquidity: bigint\n tick: number\n fee: number\n }\n return {\n type: 'Swap',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n amount0: args.amount0,\n amount1: args.amount1,\n sqrtPriceX96: args.sqrtPriceX96,\n liquidity: args.liquidity,\n tick: args.tick,\n fee: args.fee,\n }\n }\n\n case 'Donate': {\n const args = log.args as { id: Hash; sender: Address; amount0: bigint; amount1: bigint }\n return {\n type: 'Donate',\n ...baseEvent,\n id: args.id,\n sender: args.sender,\n amount0: args.amount0,\n amount1: args.amount1,\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Watch for Panoptic events in real-time using WebSocket.\n *\n * This is a one-shot watcher - if the WebSocket disconnects, it stops.\n * For production bots that need automatic reconnection, use `createEventSubscription()`.\n *\n * @param params - Watch parameters\n * @returns Unwatch function to stop watching\n *\n * @example\n * ```typescript\n * const unwatch = watchEvents({\n * client,\n * poolAddress,\n * eventTypes: ['OptionMinted', 'OptionBurnt'],\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error(error),\n * })\n *\n * // Later: stop watching\n * unwatch()\n * ```\n */\nexport function watchEvents(params: WatchEventsParams): () => void {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n } = params\n\n const unwatchFns: (() => void)[] = []\n\n // Determine which pool events to watch\n const poolEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in POOL_EVENT_NAMES)\n : (Object.keys(POOL_EVENT_NAMES) as PanopticEventType[])\n\n // Watch PanopticPool events\n for (const eventType of poolEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n // Determine which collateral events to watch\n const collateralEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in COLLATERAL_EVENT_NAMES)\n : (Object.keys(COLLATERAL_EVENT_NAMES) as PanopticEventType[])\n\n // Watch CollateralTracker events (if addresses provided)\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch RiskEngine events (if address provided)\n if (riskEngineAddress) {\n const riskEngineEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in RISK_ENGINE_EVENT_NAMES)\n : (Object.keys(RISK_ENGINE_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of riskEngineEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch SFPM events (if address provided)\n if (sfpmAddress) {\n const sfpmEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in SFPM_EVENT_NAMES)\n : (Object.keys(SFPM_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of sfpmEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Watch PoolManager events (if address provided)\n if (poolManagerAddress) {\n const poolManagerEventTypesToWatch = eventTypes\n ? eventTypes.filter((t) => t in POOL_MANAGER_EVENT_NAMES)\n : (Object.keys(POOL_MANAGER_EVENT_NAMES) as PanopticEventType[])\n\n for (const eventType of poolManagerEventTypesToWatch) {\n try {\n const unwatch = client.watchContractEvent({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n onLogs: (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n onLogs(events)\n }\n },\n onError: onError,\n })\n unwatchFns.push(unwatch)\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n }\n }\n }\n\n // Return combined unwatch function\n return () => {\n for (const unwatch of unwatchFns) {\n unwatch()\n }\n }\n}\n\nexport type { DecodedLog }\nexport { parseCollateralLog, parsePoolLog, parsePoolManagerLog, parseRiskEngineLog, parseSfpmLog }\n","/**\n * Resilient event subscription with auto-reconnect for the Panoptic v2 SDK.\n * @module v2/events/subscription\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { EventSubscription, PanopticEvent, PanopticEventType } from '../types'\nimport type { DecodedLog } from './watchEvents'\nimport {\n parseCollateralLog,\n parsePoolLog,\n parsePoolManagerLog,\n parseRiskEngineLog,\n parseSfpmLog,\n} from './watchEvents'\n\n/**\n * Reconnection strategy configuration.\n */\nexport interface ReconnectConfig {\n /** Maximum reconnection attempts (0n = infinite) */\n maxAttempts: bigint\n /** Initial delay before first retry (ms) */\n initialDelayMs: bigint\n /** Maximum delay between retries (ms) */\n maxDelayMs: bigint\n /** Backoff multiplier */\n backoffMultiplier: bigint\n}\n\n/**\n * Default reconnection configuration.\n */\nexport const DEFAULT_RECONNECT_CONFIG: ReconnectConfig = {\n maxAttempts: 10n,\n initialDelayMs: 1000n,\n maxDelayMs: 30000n,\n backoffMultiplier: 2n,\n}\n\n/**\n * Parameters for creating an event subscription.\n */\nexport interface CreateEventSubscriptionParams {\n /** Public client (must have WebSocket transport) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors (subscription will auto-reconnect) */\n onError?: (error: Error) => void\n /** Callback for reconnection attempts */\n onReconnect?: (attempt: bigint, nextDelayMs: bigint) => void\n /** Callback when connected */\n onConnected?: () => void\n /** Reconnection strategy configuration */\n reconnect?: Partial<ReconnectConfig>\n}\n\n/**\n * Event subscription handle with additional state.\n */\nexport interface EventSubscriptionHandle extends EventSubscription {\n /** Start watching */\n start: () => void\n /** Stop watching (cleans up, no more reconnects) */\n stop: () => void\n /** Number of reconnection attempts */\n reconnectAttempts: bigint\n /** Last processed block number */\n lastProcessedBlock: bigint\n}\n\n/**\n * Create a resilient event subscription with auto-reconnect and gap filling.\n *\n * Unlike `watchEvents()`, this subscription automatically reconnects on\n * disconnection and fills gaps by fetching missed events.\n *\n * @param params - Subscription parameters\n * @returns Event subscription handle\n *\n * @example\n * ```typescript\n * const subscription = createEventSubscription({\n * client,\n * poolAddress,\n * eventTypes: ['OptionMinted', 'OptionBurnt', 'AccountLiquidated'],\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error('Subscription error:', error),\n * onReconnect: (attempt, nextDelay) => {\n * console.log(`Reconnecting (attempt ${attempt}, next in ${nextDelay}ms)`)\n * },\n * onConnected: () => console.log('Subscription connected'),\n * })\n *\n * // Start watching\n * subscription.start()\n *\n * // Check state\n * console.log('Connected:', subscription.isConnected())\n * console.log('Reconnect attempts:', subscription.reconnectAttempts)\n * console.log('Last processed block:', subscription.lastProcessedBlock)\n *\n * // Stop (cleans up, no more reconnects)\n * subscription.stop()\n * ```\n */\nexport function createEventSubscription(\n params: CreateEventSubscriptionParams,\n): EventSubscriptionHandle {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n onReconnect,\n onConnected,\n reconnect: reconnectConfig,\n } = params\n\n const config: ReconnectConfig = {\n ...DEFAULT_RECONNECT_CONFIG,\n ...reconnectConfig,\n }\n\n // State\n let isRunning = false\n let connected = false\n let reconnectAttempts = 0n\n let lastProcessedBlock = 0n\n let lastProcessedLogIndex = -1n\n let currentDelay = config.initialDelayMs\n let unwatchFns: (() => void)[] = []\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null\n\n const compareEvents = (a: PanopticEvent, b: PanopticEvent): number => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n if (a.logIndex !== b.logIndex) {\n return a.logIndex < b.logIndex ? -1 : 1\n }\n return 0\n }\n\n const isAfterCursor = (event: PanopticEvent): boolean => {\n if (event.blockNumber > lastProcessedBlock) {\n return true\n }\n if (event.blockNumber < lastProcessedBlock) {\n return false\n }\n return event.logIndex > lastProcessedLogIndex\n }\n\n const advanceCursor = (event: PanopticEvent): void => {\n lastProcessedBlock = event.blockNumber\n lastProcessedLogIndex = event.logIndex\n }\n\n // Pool event types\n const poolEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) =>\n [\n 'OptionMinted',\n 'OptionBurnt',\n 'AccountLiquidated',\n 'ForcedExercised',\n 'PremiumSettled',\n ].includes(t),\n )\n : ['OptionMinted', 'OptionBurnt', 'AccountLiquidated', 'ForcedExercised', 'PremiumSettled']\n\n // Collateral event types\n const collateralEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['Deposit', 'Withdraw', 'ProtocolLossRealized'].includes(t))\n : ['Deposit', 'Withdraw', 'ProtocolLossRealized']\n\n // RiskEngine event types\n const riskEngineEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['BorrowRateUpdated'].includes(t))\n : ['BorrowRateUpdated']\n\n // SFPM event types\n const sfpmEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['LiquidityChunkUpdated'].includes(t))\n : ['LiquidityChunkUpdated']\n\n // PoolManager event types\n const poolManagerEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['ModifyLiquidity', 'Swap', 'Donate'].includes(t))\n : ['ModifyLiquidity', 'Swap', 'Donate']\n\n /**\n * Fetch missed events between lastProcessedBlock and currentBlock.\n */\n async function fillGap(fromBlock: bigint, toBlock: bigint): Promise<void> {\n if (fromBlock >= toBlock) return\n\n const allEvents: PanopticEvent[] = []\n\n // Fetch pool events\n for (const eventType of poolEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`))\n }\n }\n\n // Fetch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n fromBlock,\n toBlock,\n })\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Sort by block number and log index, then drop anything at/before cursor.\n const newEvents = allEvents.sort(compareEvents).filter(isAfterCursor)\n\n if (newEvents.length > 0) {\n onLogs(newEvents)\n advanceCursor(newEvents[newEvents.length - 1])\n }\n }\n\n /**\n * Start watching events.\n */\n async function setupWatchers(): Promise<void> {\n // Clean up any existing watchers\n cleanup()\n\n try {\n // Get current block for gap detection\n const currentBlock = await client.getBlockNumber()\n\n // Fill gap if we have a previous position\n if (lastProcessedBlock > 0n && lastProcessedBlock < currentBlock) {\n await fillGap(lastProcessedBlock, currentBlock)\n }\n\n // Set baseline for this subscription start (from \"head\"), unless fillGap\n // already advanced us into this block with a concrete log index.\n if (currentBlock > lastProcessedBlock) {\n lastProcessedBlock = currentBlock\n lastProcessedLogIndex = -1n\n }\n\n const createOnLogsHandler = (\n parseLog: (log: DecodedLog) => PanopticEvent | null,\n ): ((logs: readonly unknown[]) => void) => {\n return (logs) => {\n const events: PanopticEvent[] = []\n for (const log of logs) {\n const parsed = parseLog(log as DecodedLog)\n if (parsed && isAfterCursor(parsed)) {\n events.push(parsed)\n }\n }\n if (events.length > 0) {\n events.sort(compareEvents)\n onLogs(events)\n advanceCursor(events[events.length - 1])\n }\n }\n }\n\n const createPoolOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parsePoolLog(log, eventType))\n const createCollateralOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseCollateralLog(log, eventType))\n const createRiskEngineOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseRiskEngineLog(log, eventType))\n const createSfpmOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parseSfpmLog(log, eventType))\n const createPoolManagerOnLogs = (eventType: PanopticEventType) =>\n createOnLogsHandler((log) => parsePoolManagerLog(log, eventType))\n\n // Watch pool events\n for (const eventType of poolEventTypes) {\n const unwatch = client.watchContractEvent({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n onLogs: createPoolOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n\n // Watch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(\n Boolean,\n ) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n const unwatch = client.watchContractEvent({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n onLogs: createCollateralOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n const unwatch = client.watchContractEvent({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n onLogs: createRiskEngineOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n const unwatch = client.watchContractEvent({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n onLogs: createSfpmOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Watch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n const unwatch = client.watchContractEvent({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n onLogs: createPoolManagerOnLogs(eventType),\n onError: handleError,\n })\n unwatchFns.push(unwatch)\n }\n }\n\n // Mark as connected\n connected = true\n reconnectAttempts = 0n\n currentDelay = config.initialDelayMs\n onConnected?.()\n } catch (error) {\n handleError(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n /**\n * Clean up watchers.\n */\n function cleanup(): void {\n for (const unwatch of unwatchFns) {\n try {\n unwatch()\n } catch {\n // Ignore cleanup errors\n }\n }\n unwatchFns = []\n connected = false\n }\n\n /**\n * Handle errors and schedule reconnection.\n */\n function handleError(error: Error): void {\n connected = false\n onError?.(error)\n\n if (!isRunning) return\n\n // Reconnect already scheduled; avoid duplicate timers.\n if (reconnectTimeout) return\n\n // Check if we've exceeded max attempts\n if (config.maxAttempts > 0n && reconnectAttempts >= config.maxAttempts) {\n onError?.(new Error(`Max reconnection attempts (${config.maxAttempts}) exceeded`))\n return\n }\n\n // Schedule reconnection\n reconnectAttempts++\n onReconnect?.(reconnectAttempts, currentDelay)\n\n reconnectTimeout = setTimeout(() => {\n reconnectTimeout = null\n if (isRunning) {\n setupWatchers()\n }\n }, Number(currentDelay))\n\n // Increase delay for next attempt (exponential backoff)\n currentDelay = currentDelay * config.backoffMultiplier\n if (currentDelay > config.maxDelayMs) {\n currentDelay = config.maxDelayMs\n }\n }\n\n /**\n * Start the subscription.\n */\n function start(): void {\n if (isRunning) return\n isRunning = true\n setupWatchers()\n }\n\n /**\n * Stop the subscription.\n */\n function stop(): void {\n isRunning = false\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout)\n }\n reconnectTimeout = null\n cleanup()\n }\n\n return {\n start,\n stop,\n unsubscribe: stop,\n isConnected: () => connected,\n get reconnectAttempts() {\n return reconnectAttempts\n },\n get lastProcessedBlock() {\n return lastProcessedBlock\n },\n }\n}\n","/**\n * HTTP polling-based event fetching for the Panoptic v2 SDK.\n * @module v2/events/poller\n */\n\nimport type { Address, PublicClient } from 'viem'\n\nimport {\n collateralTrackerV2Abi,\n panopticPoolV2Abi,\n riskEngineAbi,\n semiFungiblePositionManagerV4Abi,\n} from '../../../generated'\nimport { poolManagerAbi } from '../abis/poolManager'\nimport type { PanopticEvent, PanopticEventType } from '../types'\nimport type { DecodedLog } from './watchEvents'\nimport {\n parseCollateralLog,\n parsePoolLog,\n parsePoolManagerLog,\n parseRiskEngineLog,\n parseSfpmLog,\n} from './watchEvents'\n\n/**\n * Event poller handle.\n */\nexport interface EventPoller {\n /** Start polling */\n start: () => void\n /** Stop polling */\n stop: () => void\n /** Check if polling is active */\n isPolling: () => boolean\n /** Get last polled block */\n lastPolledBlock: bigint\n}\n\n/**\n * Parameters for creating an event poller.\n */\nexport interface CreateEventPollerParams {\n /** Public client (works with HTTP transport) */\n client: PublicClient\n /** PanopticPool address */\n poolAddress: Address\n /** CollateralTracker0 address (optional, for Deposit/Withdraw events) */\n collateralTracker0?: Address\n /** CollateralTracker1 address (optional, for Deposit/Withdraw/ProtocolLossRealized events) */\n collateralTracker1?: Address\n /** RiskEngine address (optional, for BorrowRateUpdated events) */\n riskEngineAddress?: Address\n /** SemiFungiblePositionManager address (optional, for LiquidityChunkUpdated events) */\n sfpmAddress?: Address\n /** v4 PoolManager address (optional, for ModifyLiquidity/Swap/Donate events) */\n poolManagerAddress?: Address\n /** Event types to filter (omit for all events) */\n eventTypes?: PanopticEventType[]\n /** Callback for received events */\n onLogs: (events: PanopticEvent[]) => void\n /** Callback for errors */\n onError?: (error: Error) => void\n /** Polling interval in milliseconds (default: 12000 = 1 block on mainnet) */\n intervalMs?: bigint\n /** Maximum blocks to query per poll (default: 1000) */\n maxBlockRange?: bigint\n /** Starting block number (default: current block) */\n fromBlock?: bigint\n}\n\n/**\n * Default polling interval (12 seconds = ~1 mainnet block).\n */\nconst DEFAULT_INTERVAL_MS = 12000n\n\n/**\n * Default maximum block range per poll.\n */\nconst DEFAULT_MAX_BLOCK_RANGE = 1000n\n\n/**\n * Create an HTTP polling-based event fetcher.\n *\n * Use this for environments where WebSocket connections are unreliable or unavailable.\n * It polls `eth_getLogs` at regular intervals to fetch new events.\n *\n * @param params - Poller parameters\n * @returns Event poller handle\n *\n * @example\n * ```typescript\n * const poller = createEventPoller({\n * client,\n * poolAddress,\n * onLogs: (events) => {\n * for (const event of events) {\n * console.log(event.type, event)\n * }\n * },\n * onError: (error) => console.error('Polling error:', error),\n * intervalMs: 12000n, // 12 seconds\n * maxBlockRange: 1000n,\n * })\n *\n * // Start polling\n * poller.start()\n *\n * // Check state\n * console.log('Polling:', poller.isPolling())\n * console.log('Last polled block:', poller.lastPolledBlock)\n *\n * // Stop polling\n * poller.stop()\n * ```\n */\nexport function createEventPoller(params: CreateEventPollerParams): EventPoller {\n const {\n client,\n poolAddress,\n collateralTracker0,\n collateralTracker1,\n riskEngineAddress,\n sfpmAddress,\n poolManagerAddress,\n eventTypes,\n onLogs,\n onError,\n intervalMs = DEFAULT_INTERVAL_MS,\n maxBlockRange = DEFAULT_MAX_BLOCK_RANGE,\n fromBlock,\n } = params\n\n // State\n let isRunning = false\n let lastPolledBlock = fromBlock ?? 0n\n let pollTimeout: ReturnType<typeof setTimeout> | null = null\n\n // Pool event types\n const poolEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) =>\n [\n 'OptionMinted',\n 'OptionBurnt',\n 'AccountLiquidated',\n 'ForcedExercised',\n 'PremiumSettled',\n ].includes(t),\n )\n : ['OptionMinted', 'OptionBurnt', 'AccountLiquidated', 'ForcedExercised', 'PremiumSettled']\n\n // Collateral event types\n const collateralEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['Deposit', 'Withdraw', 'ProtocolLossRealized'].includes(t))\n : ['Deposit', 'Withdraw', 'ProtocolLossRealized']\n\n // RiskEngine event types\n const riskEngineEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['BorrowRateUpdated'].includes(t))\n : ['BorrowRateUpdated']\n\n // SFPM event types\n const sfpmEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['LiquidityChunkUpdated'].includes(t))\n : ['LiquidityChunkUpdated']\n\n // PoolManager event types\n const poolManagerEventTypes: PanopticEventType[] = eventTypes\n ? eventTypes.filter((t) => ['ModifyLiquidity', 'Swap', 'Donate'].includes(t))\n : ['ModifyLiquidity', 'Swap', 'Donate']\n\n /**\n * Fetch events for a block range.\n */\n async function fetchEvents(from: bigint, to: bigint): Promise<PanopticEvent[]> {\n const allEvents: PanopticEvent[] = []\n\n // Fetch pool events\n for (const eventType of poolEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolAddress,\n abi: panopticPoolV2Abi,\n eventName: eventType as\n | 'OptionMinted'\n | 'OptionBurnt'\n | 'AccountLiquidated'\n | 'ForcedExercised'\n | 'PremiumSettled',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parsePoolLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`))\n }\n }\n\n // Fetch collateral events\n const collateralTrackers = [collateralTracker0, collateralTracker1].filter(Boolean) as Address[]\n for (const trackerAddress of collateralTrackers) {\n for (const eventType of collateralEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: trackerAddress,\n abi: collateralTrackerV2Abi,\n eventName: eventType as 'Deposit' | 'Withdraw' | 'ProtocolLossRealized',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseCollateralLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch RiskEngine events\n if (riskEngineAddress) {\n for (const eventType of riskEngineEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: riskEngineAddress,\n abi: riskEngineAbi,\n eventName: eventType as 'BorrowRateUpdated',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseRiskEngineLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch SFPM events\n if (sfpmAddress) {\n for (const eventType of sfpmEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: sfpmAddress,\n abi: semiFungiblePositionManagerV4Abi,\n eventName: eventType as 'LiquidityChunkUpdated',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parseSfpmLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Fetch PoolManager events\n if (poolManagerAddress) {\n for (const eventType of poolManagerEventTypes) {\n try {\n const logs = await client.getContractEvents({\n address: poolManagerAddress,\n abi: poolManagerAbi,\n eventName: eventType as 'ModifyLiquidity' | 'Swap' | 'Donate',\n fromBlock: from,\n toBlock: to,\n })\n for (const log of logs) {\n const parsed = parsePoolManagerLog(log as DecodedLog, eventType)\n if (parsed) {\n allEvents.push(parsed)\n }\n }\n } catch (error) {\n onError?.(\n error instanceof Error ? error : new Error(`Failed to fetch ${eventType} events`),\n )\n }\n }\n }\n\n // Sort by block number and log index\n allEvents.sort((a, b) => {\n if (a.blockNumber !== b.blockNumber) {\n return a.blockNumber < b.blockNumber ? -1 : 1\n }\n return a.logIndex < b.logIndex ? -1 : 1\n })\n\n return allEvents\n }\n\n /**\n * Perform a single poll iteration.\n */\n async function poll(): Promise<void> {\n if (!isRunning) return\n\n try {\n // Get current block\n const currentBlock = await client.getBlockNumber()\n\n // Initialize lastPolledBlock if not set\n if (lastPolledBlock === 0n) {\n lastPolledBlock = currentBlock\n schedulePoll()\n return\n }\n\n // Check if there are new blocks\n if (currentBlock <= lastPolledBlock) {\n schedulePoll()\n return\n }\n\n // Calculate range to query (respect maxBlockRange)\n let toBlock = currentBlock\n const range = toBlock - lastPolledBlock\n if (range > maxBlockRange) {\n toBlock = lastPolledBlock + maxBlockRange\n }\n\n // Fetch events\n const events = await fetchEvents(lastPolledBlock + 1n, toBlock)\n\n // Update last polled block\n lastPolledBlock = toBlock\n\n // Deliver events\n if (events.length > 0) {\n onLogs(events)\n }\n\n // If we didn't catch up to current block, poll again immediately\n if (toBlock < currentBlock && isRunning) {\n // Use setImmediate-like behavior with 0ms timeout\n pollTimeout = setTimeout(poll, 0)\n } else {\n schedulePoll()\n }\n } catch (error) {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n schedulePoll()\n }\n }\n\n /**\n * Schedule next poll.\n */\n function schedulePoll(): void {\n if (!isRunning) return\n pollTimeout = setTimeout(poll, Number(intervalMs))\n }\n\n /**\n * Start polling.\n */\n function start(): void {\n if (isRunning) return\n isRunning = true\n poll()\n }\n\n /**\n * Stop polling.\n */\n function stop(): void {\n isRunning = false\n if (pollTimeout) {\n clearTimeout(pollTimeout)\n pollTimeout = null\n }\n }\n\n return {\n start,\n stop,\n isPolling: () => isRunning,\n get lastPolledBlock() {\n return lastPolledBlock\n },\n }\n}\n"],"mappings":"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"}