@pafi-dev/trading 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/handlers.ts","../src/quoting/routes.ts","../src/quoting/quote.ts","../src/swap/approval.ts","../src/swap/universalRouter.ts","../src/swap/simulate.ts","../src/swap/buildSwap.ts","../src/swap/slippage.ts","../src/pools.ts","../src/direct/swapDirect.ts","../src/direct/swapDirectExactOut.ts","../src/direct/perpDepositDirect.ts","../src/direct/transferDirect.ts","../src/direct/addLiquidityDirect.ts","../src/liquidity/abi/nonfungiblePositionManager.ts","../src/liquidity/abi/v3Pool.ts","../src/liquidity/constants.ts","../src/liquidity/math.ts","../src/liquidity/readPosition.ts","../src/liquidity/readPoolState.ts","../src/liquidity/buildMint.ts","../src/liquidity/buildIncreaseLiquidity.ts","../src/liquidity/buildDecreaseLiquidity.ts","../src/liquidity/buildCollect.ts","../src/liquidity/buildBurn.ts","../src/liquidity/buildClosePosition.ts","../src/liquidity/readTickBitmap.ts","../src/liquidity/buildLiquidityCurve.ts","../src/liquidity/fetchAllInitializedTicks.ts","../src/liquidity/fetchLiquidityCurve.ts","../src/direct/increaseLiquidityDirect.ts","../src/direct/removeLiquidityDirect.ts","../src/direct/closePositionDirect.ts","../src/direct/collectFeesDirect.ts"],"sourcesContent":["import { getAddress } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport {\n buildPerpDepositWithGasDeduction,\n buildPerpDepositViaRelay,\n buildErc20TransferUserOp,\n ORDERLY_RELAY_ABI,\n getContractAddresses,\n UNIVERSAL_ROUTER_ADDRESSES,\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n BROKER_HASHES,\n TOKEN_HASHES,\n ValidationError,\n computeAccountId,\n quoteOperatorFeePt,\n quoteOperatorFeeUsdt,\n quoteOperatorFeeForTransfer,\n} from \"@pafi-dev/core\";\nimport { findBestQuote, findBestQuoteExactOut } from \"../quoting\";\nimport {\n MAX_SLIPPAGE_BPS,\n buildSwapUserOp,\n buildSwapUserOpExactOut,\n isValidSlippageBps,\n} from \"../swap\";\nimport type {\n ApiQuoteRequest,\n ApiQuoteResponse,\n ApiSwapRequest,\n ApiSwapResponse,\n ApiQuoteExactOutRequest,\n ApiQuoteExactOutResponse,\n ApiSwapExactOutRequest,\n ApiSwapExactOutResponse,\n ApiPerpDepositRequest,\n ApiPerpDepositResponse,\n ApiErc20TransferRequest,\n ApiErc20TransferResponse,\n} from \"./types\";\n\nexport interface TradingHandlersConfig {\n provider: PublicClient;\n chainId: number;\n}\n\n/**\n * Framework-agnostic handlers for on-chain trading actions.\n *\n * All handlers are stateless — they need only a PublicClient for RPC\n * calls. No ledger, no signer, no DB. Issuers wrap these in their own\n * HTTP controllers (Express / NestJS / Hono / etc.) the same way they\n * wrap `IssuerApiHandlers` from `@pafi-dev/issuer`.\n *\n * Example (NestJS):\n *\n * const trading = new TradingHandlers({ provider, chainId });\n *\n * // GET /quote\n * const quote = await trading.handleQuote({ chainId, pointTokenAddress, amount, pools });\n *\n * // POST /swap\n * const swap = await trading.handleSwap({ chainId, userAddress, pointTokenAddress, amount, aaNonce });\n *\n * // POST /perp-deposit\n * const deposit = await trading.handlePerpDeposit({ chainId, userAddress, amount, aaNonce, brokerId });\n */\nexport class TradingHandlers {\n private readonly provider: PublicClient;\n private readonly chainId: number;\n\n constructor(config: TradingHandlersConfig) {\n this.provider = config.provider;\n this.chainId = config.chainId;\n }\n\n // =========================================================================\n // GET /quote\n // =========================================================================\n\n /**\n * Quote exact-input PT → USDT via Uniswap V3 QuoterV2.\n *\n * Uses multicall to batch all candidate routes into a single RPC call.\n * Returns `quoteError: \"QUOTE_UNAVAILABLE\"` when no pool/path exists\n * rather than throwing, so callers can show a soft \"unavailable\" UI\n * state without 500-ing.\n */\n async handleQuote(request: ApiQuoteRequest): Promise<ApiQuoteResponse> {\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleQuote: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount === 0n) {\n return {\n inputAmount: 0n,\n estimatedOutputAmount: 0n,\n outputNet: 0n,\n feeAmountOutput: 0n,\n gasEstimate: 0n,\n };\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const pools = request.pools ?? [];\n\n try {\n const best = await findBestQuote(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n const feeAmountOutput = await quoteOperatorFeeOutput(\n this.provider,\n request.chainId,\n outputTokenAddress,\n ).catch(() => 0n);\n const outputNet =\n best.bestRoute.amountOut > feeAmountOutput\n ? best.bestRoute.amountOut - feeAmountOutput\n : 0n;\n return {\n inputAmount: request.amount,\n estimatedOutputAmount: best.bestRoute.amountOut,\n outputNet,\n feeAmountOutput,\n gasEstimate: best.bestRoute.gasEstimate,\n };\n } catch {\n return {\n inputAmount: request.amount,\n estimatedOutputAmount: 0n,\n outputNet: 0n,\n feeAmountOutput: 0n,\n gasEstimate: 0n,\n quoteError: \"QUOTE_UNAVAILABLE\",\n };\n }\n }\n\n // =========================================================================\n // POST /swap\n // =========================================================================\n\n /**\n * Build a swap UserOp (direction-agnostic).\n *\n * Quotes the best route, applies slippage, then encodes a 4-step\n * batch: input.approve → Permit2.approve → UniversalRouter.execute →\n * output.transfer (fee in OUTPUT token, omitted when fee = 0).\n *\n * v0.3 — Fee model is OUTPUT-side (token-availability rule). User\n * holds exactly `amountIn` of input; receives `outputGross - fee`\n * net. Quote response surfaces both `estimatedOutputAmount` (gross)\n * and `outputNet` so the FE can display reality.\n *\n * `authenticatedAddress` first param: caller (issuer controller / FE\n * proxy) MUST pass the address extracted from the verified\n * session/JWT. Handler asserts it equals `request.userAddress`.\n */\n async handleSwap(\n authenticatedAddress: Address,\n request: ApiSwapRequest,\n ): Promise<ApiSwapResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleSwap: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleSwap: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handleSwap: amount must be positive\",\n );\n }\n if (!isValidSlippageBps(request.slippageBps)) {\n throw new ValidationError(\n \"INVALID_SLIPPAGE\",\n `handleSwap: slippageBps (${request.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n { received: request.slippageBps, max: MAX_SLIPPAGE_BPS },\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(request.chainId);\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[request.chainId];\n if (!universalRouter) {\n throw new ValidationError(\n \"ROUTER_NOT_DEPLOYED\",\n `handleSwap: no UniversalRouter for chainId ${request.chainId}`,\n );\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const userAddress = getAddress(request.userAddress);\n const pools = request.pools ?? [];\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuote>>;\n try {\n quoteResult = await findBestQuote(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new ValidationError(\n \"NO_SWAP_PATH\",\n `handleSwap: no swap path found from ${inputTokenAddress} to ${outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n // Resolve the operator fee in OUTPUT token units. Auto-quote uses\n // the right underlying quoter based on output token (USDT vs PT).\n const gasFeeAmountOutput =\n request.gasFeeAmountOutput !== undefined\n ? request.gasFeeAmountOutput\n : await quoteOperatorFeeOutput(\n this.provider,\n request.chainId,\n outputTokenAddress,\n ).catch(() => 0n);\n\n const hops = quoteResult.bestRoute.path.fees.length;\n // Multi-hop routes compound slippage across legs — bias higher when\n // caller didn't override. 50 bps single-hop, 100 bps multi-hop.\n const slippageBps =\n request.slippageBps ?? (hops > 1 ? 100 : 50);\n\n const estimatedOutputAmount = quoteResult.bestRoute.amountOut;\n const minAmountOut = (estimatedOutputAmount * BigInt(10000 - slippageBps)) / 10000n;\n\n if (gasFeeAmountOutput > 0n && minAmountOut < gasFeeAmountOutput) {\n throw new ValidationError(\n \"AMOUNT_TOO_SMALL_FOR_FEE\",\n `handleSwap: minAmountOut (${minAmountOut}) below operator fee (${gasFeeAmountOutput}) — increase swap amount or accept tighter slippage`,\n {\n minAmountOut: minAmountOut.toString(),\n gasFeeAmountOutput: gasFeeAmountOutput.toString(),\n },\n );\n }\n\n const deadline = BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const userOp = buildSwapUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: request.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // Fee-stripped fallback for paymaster-refused path.\n const userOpFallback =\n gasFeeAmountOutput > 0n\n ? buildSwapUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: request.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput: 0n,\n feeRecipient: pafiFeeRecipient,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n estimatedOutputAmount,\n minAmountOut,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // GET /quote/exact-out — V3 exact-output quote\n // =========================================================================\n\n /**\n * Quote the input required to receive `request.amount` of the output\n * token via Uniswap V3 QuoterV2. Input-side operator fee is auto-quoted, so\n * `inputGross = estimatedInputAmount + feeAmountInput` is the total\n * the user must hold.\n *\n * Returns `quoteError: \"QUOTE_UNAVAILABLE\"` rather than throwing when\n * no path exists.\n */\n async handleQuoteExactOut(\n request: ApiQuoteExactOutRequest,\n ): Promise<ApiQuoteExactOutResponse> {\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleQuoteExactOut: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount === 0n) {\n return {\n outputAmount: 0n,\n estimatedInputAmount: 0n,\n inputGross: 0n,\n feeAmountInput: 0n,\n gasEstimate: 0n,\n };\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const pools = request.pools ?? [];\n\n try {\n const best = await findBestQuoteExactOut(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n const feeAmountInput = await quoteOperatorFeeInput(\n this.provider,\n request.chainId,\n inputTokenAddress,\n ).catch(() => 0n);\n const estimatedInputAmount = best.bestRoute.amountIn;\n return {\n outputAmount: request.amount,\n estimatedInputAmount,\n inputGross: estimatedInputAmount + feeAmountInput,\n feeAmountInput,\n gasEstimate: best.bestRoute.gasEstimate,\n };\n } catch {\n return {\n outputAmount: request.amount,\n estimatedInputAmount: 0n,\n inputGross: 0n,\n feeAmountInput: 0n,\n gasEstimate: 0n,\n quoteError: \"QUOTE_UNAVAILABLE\",\n };\n }\n }\n\n // =========================================================================\n // POST /swap/exact-out — V3 exact-output swap UserOp\n // =========================================================================\n\n /**\n * Build a V3 exact-output swap UserOp.\n *\n * Quotes the best exact-output route, applies slippage as a CEILING on\n * `maxAmountIn` (so the cap is never silently tightened by floor\n * division), then encodes a 4-step batch:\n *\n * inputToken.transfer(feeRecipient, gasFeeAmountInput) [if > 0]\n * → input.approve(Permit2, maxAmountIn)\n * → Permit2.approve(router, maxAmountIn)\n * → UniversalRouter.execute (V3_SWAP_EXACT_OUT)\n *\n * Operator fee is INPUT-token-side (charged before swap) so the user\n * receives exactly `request.amount` of output.\n *\n * `authenticatedAddress` first param: caller MUST pass the address\n * extracted from the verified session/JWT. Handler asserts equality\n * with `request.userAddress`.\n */\n async handleSwapExactOut(\n authenticatedAddress: Address,\n request: ApiSwapExactOutRequest,\n ): Promise<ApiSwapExactOutResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleSwapExactOut: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleSwapExactOut: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handleSwapExactOut: amount must be positive\",\n );\n }\n if (!isValidSlippageBps(request.slippageBps)) {\n throw new ValidationError(\n \"INVALID_SLIPPAGE\",\n `handleSwapExactOut: slippageBps (${request.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n { received: request.slippageBps, max: MAX_SLIPPAGE_BPS },\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(request.chainId);\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[request.chainId];\n if (!universalRouter) {\n throw new ValidationError(\n \"ROUTER_NOT_DEPLOYED\",\n `handleSwapExactOut: no UniversalRouter for chainId ${request.chainId}`,\n );\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const userAddress = getAddress(request.userAddress);\n const pools = request.pools ?? [];\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuoteExactOut>>;\n try {\n quoteResult = await findBestQuoteExactOut(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new ValidationError(\n \"NO_SWAP_PATH\",\n `handleSwapExactOut: no swap path found from ${inputTokenAddress} to ${outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n // Auto-quote the operator fee in INPUT-token units when caller didn't\n // override. Uses the input-token-aware sibling of quoteOperatorFeeOutput.\n const gasFeeAmountInput =\n request.gasFeeAmountInput !== undefined\n ? request.gasFeeAmountInput\n : await quoteOperatorFeeInput(\n this.provider,\n request.chainId,\n inputTokenAddress,\n ).catch(() => 0n);\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = request.slippageBps ?? (hops > 1 ? 100 : 50);\n\n const estimatedInputAmount = quoteResult.bestRoute.amountIn;\n // Ceiling division: maxAmountIn = ceil(estimated * (10000 + slippageBps) / 10000)\n // — if we used floor, the cap would round DOWN and could silently\n // be tighter than the caller intended, causing edge-case reverts.\n const slippageNumerator =\n estimatedInputAmount * BigInt(10000 + slippageBps);\n const maxAmountIn = (slippageNumerator + 9999n) / 10000n;\n\n const deadline = BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const userOp = buildSwapUserOpExactOut({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: request.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // Fee-stripped fallback for paymaster-refused path.\n const userOpFallback =\n gasFeeAmountInput > 0n\n ? buildSwapUserOpExactOut({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: request.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput: 0n,\n feeRecipient: pafiFeeRecipient,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n outputAmount: request.amount,\n estimatedInputAmount,\n maxAmountIn,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // POST /perp-deposit\n // =========================================================================\n\n /**\n * Build an Orderly perp deposit UserOp.\n *\n * Default path is the **PAFI Orderly Relay** (`viaRelay: true`):\n * USDC.approve(relay) + relay.deposit(req). The Relay holds an ETH\n * reserve and pays Orderly's LayerZero `msg.value` out of it; the\n * user pays a USDC fee (quoted via `Relay.quoteTokenFee`) instead.\n * No native ETH on the user wallet is required, so paymaster\n * sponsorship of the ERC-4337 gas is sufficient end-to-end.\n *\n * Fallback path (`viaRelay: false`): direct `Vault.deposit{value}`.\n * Reserved for chains where no Relay is deployed — the user wallet\n * **must** hold `layerZeroFee` as native ETH.\n *\n * The Relay path automatically falls back to Vault when\n * `getContractAddresses(chainId).orderlyRelay` is the placeholder\n * sentinel (Relay not deployed for that chain).\n */\n async handlePerpDeposit(\n authenticatedAddress: Address,\n request: ApiPerpDepositRequest,\n ): Promise<ApiPerpDepositResponse> {\n // Auth-context check — caller MUST pass the verified address.\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handlePerpDeposit: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handlePerpDeposit: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handlePerpDeposit: amount must be positive\",\n );\n }\n\n const vault = ORDERLY_VAULT_ADDRESSES[request.chainId];\n if (!vault) {\n throw new ValidationError(\n \"VAULT_NOT_DEPLOYED\",\n `handlePerpDeposit: no Orderly Vault for chainId ${request.chainId}`,\n );\n }\n\n const brokerHash = BROKER_HASHES[request.brokerId as keyof typeof BROKER_HASHES];\n if (!brokerHash) {\n throw new ValidationError(\n \"UNKNOWN_BROKER_ID\",\n `handlePerpDeposit: unknown brokerId \"${request.brokerId}\"`,\n { brokerId: request.brokerId },\n );\n }\n const tokenHash = TOKEN_HASHES.USDC;\n const userAddress = getAddress(request.userAddress);\n\n const [usdcAddress, brokerAllowed] = await Promise.all([\n this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedToken\",\n args: [tokenHash],\n }) as Promise<Address>,\n this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedBroker\",\n args: [brokerHash],\n }) as Promise<boolean>,\n ]);\n\n if (!brokerAllowed) {\n throw new ValidationError(\n \"BROKER_NOT_WHITELISTED\",\n `handlePerpDeposit: broker \"${request.brokerId}\" is not whitelisted on Orderly Vault`,\n { brokerId: request.brokerId, brokerHash },\n );\n }\n\n const accountId = computeAccountId(userAddress, brokerHash);\n const depositData = {\n accountId,\n brokerHash,\n tokenHash,\n tokenAmount: request.amount,\n };\n\n // Always read layerZeroFee for response — even on the Relay path\n // it's useful informational output (lets the FE show \"Relay\n // covers ~X ETH for you\").\n const layerZeroFee = (await this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getDepositFee\",\n args: [userAddress, depositData],\n })) as bigint;\n\n const useRelay = request.viaRelay !== false;\n const { orderlyRelay: relayAddress, pafiFeeRecipient } =\n getContractAddresses(request.chainId);\n const relayDeployed = !isPlaceholderAddress(relayAddress);\n\n // Resolve operator fee in USDC (input-token). Only applied to the\n // Relay path; the legacy direct-Vault path skips operator fee\n // entirely (it's already gas-heavy due to the user-paid\n // LayerZero msg.value, and PAFI doesn't sponsor that path on Base\n // anyway).\n const gasFeeUsdc =\n request.gasFeeUsdc !== undefined\n ? request.gasFeeUsdc\n : useRelay && relayDeployed\n ? await quoteOperatorFeeUsdt({\n provider: this.provider,\n chainId: request.chainId,\n }).catch(() => 0n)\n : 0n;\n\n if (useRelay && relayDeployed) {\n // Cap = max(amount * 5%, 2 USDC). The Relay fee is a flat USDC\n // amount derived from the LayerZero ETH cost at oracle price —\n // it does NOT scale with deposit size. A pure percentage cap\n // breaks for small deposits (e.g. 0.01 USDC test deposit, 5%\n // cap = 500 wei < 14k wei real fee). The 2 USDC floor covers\n // normal LayerZero pricing on Base; the 5% slope still guards\n // against oracle spikes on large deposits.\n const RELAY_FEE_FLOOR_USDC = 2_000_000n; // 2 USDC (6 decimals)\n const percentCap = (request.amount * 500n) / 10_000n;\n const maxRelayFee =\n request.maxRelayFee ??\n (percentCap > RELAY_FEE_FLOOR_USDC ? percentCap : RELAY_FEE_FLOOR_USDC);\n\n const relayRequest = {\n token: usdcAddress,\n receiver: userAddress,\n brokerHash,\n totalAmount: request.amount,\n maxFee: maxRelayFee,\n };\n\n const relayTokenFee = (await this.provider.readContract({\n address: relayAddress,\n abi: ORDERLY_RELAY_ABI,\n functionName: \"quoteTokenFee\",\n args: [relayRequest],\n })) as bigint;\n\n if (relayTokenFee > maxRelayFee) {\n throw new ValidationError(\n \"RELAY_FEE_EXCEEDS_MAX\",\n `handlePerpDeposit: Relay tokenFee ${relayTokenFee} (≈ ${\n Number(relayTokenFee) / 1e6\n } USDC) exceeds maxRelayFee ${maxRelayFee} — pass a larger ` +\n `\\`maxRelayFee\\` or increase the deposit \\`amount\\` so the fee ` +\n `becomes a smaller share of the total.`,\n {\n relayTokenFee: relayTokenFee.toString(),\n maxRelayFee: maxRelayFee.toString(),\n },\n );\n }\n\n // Sanity-check: Relay forwards `(totalAmount − tokenFee)` to\n // Orderly Vault. When `tokenFee >= totalAmount` the forwarded\n // amount is zero / negative and the Relay reverts on-chain with\n // `FeeExceedsAmount(fee, totalAmount)` (selector 0x536766bf),\n // which propagates as an opaque `BatchExecutor.CallFailed(1, …)`\n // revert at simulation time. Catch this early on the client so\n // the UX shows an actionable message instead of an AA21/AA34\n // bundler error wrapped around the raw selector.\n if (relayTokenFee >= request.amount) {\n const feeUsdc = Number(relayTokenFee) / 1e6;\n const amountUsdc = Number(request.amount) / 1e6;\n throw new ValidationError(\n \"RELAY_FEE_EXCEEDS_AMOUNT\",\n `handlePerpDeposit: deposit amount ${amountUsdc} USDC is below the ` +\n `Relay fee ${feeUsdc} USDC — increase \\`amount\\` to at least ` +\n `${(feeUsdc * 2).toFixed(6)} USDC so a meaningful balance reaches ` +\n `your Orderly account after the Relay charge.`,\n {\n relayTokenFee: relayTokenFee.toString(),\n amount: request.amount.toString(),\n },\n );\n }\n\n // USDC fee transferred FIRST in the batch (input-token rule —\n // user holds USDC at start). Recipient = pafiFeeRecipient.\n const userOp = buildPerpDepositViaRelay({\n userAddress,\n aaNonce: request.aaNonce,\n relayAddress,\n request: relayRequest,\n gasFeeUsdc: gasFeeUsdc > 0n ? gasFeeUsdc : undefined,\n gasFeeUsdcRecipient: gasFeeUsdc > 0n ? pafiFeeRecipient : undefined,\n });\n\n // Same shape, no USDC fee transfer — for the paymaster-refused\n // fallback path. The Relay still charges its own USDC token-fee\n // (compensates LayerZero ETH spend, NOT PAFI's gas).\n const userOpFallback =\n gasFeeUsdc > 0n\n ? buildPerpDepositViaRelay({\n userAddress,\n aaNonce: request.aaNonce,\n relayAddress,\n request: relayRequest,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n path: \"relay\",\n layerZeroFee,\n relayTokenFee,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress,\n feeAmountUsed: gasFeeUsdc,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // Fallback: direct Vault.deposit{value} — user wallet MUST hold\n // `layerZeroFee` as native ETH (paymaster does not sponsor msg.value).\n const userOp = buildPerpDepositWithGasDeduction({\n userAddress,\n aaNonce: request.aaNonce,\n chainId: request.chainId,\n usdcAddress,\n amount: request.amount,\n depositData,\n layerZeroFee,\n });\n\n return {\n userOp,\n path: \"vault\",\n layerZeroFee,\n relayTokenFee: 0n,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress: vault,\n // Vault path doesn't include the PT operator fee transfer (it's\n // an unsponsored path on chains without a Relay deployment, and\n // the user is paying msg.value in ETH already). Echo 0n + the\n // canonical recipient so the response shape stays consistent.\n feeAmountUsed: 0n,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // POST /erc20-transfer — gasless ERC-20 send (USDC/USDT/active-PT)\n // =========================================================================\n\n /**\n * Build a sponsored ERC-20 transfer UserOp pair (sponsored + fallback).\n *\n * Sponsored variant: `[token.transfer(PAFI, fee), token.transfer(recipient, amount)]`.\n * Fallback variant: `[token.transfer(recipient, amount)]` (user pays ETH).\n *\n * Both calls hit the SAME token contract — fee currency equals the\n * token being sent, so the user needs only ONE token (≥ `amount + fee`)\n * to complete a gasless send.\n *\n * Allowlist enforced HERE (client-side fail-fast) **and** server-side\n * by sponsor-relayer's IntentValidator:\n * - USDC (`getContractAddresses(chainId).usdc`)\n * - USDT (`getContractAddresses(chainId).usdt`)\n * - active PointToken (caller responsibility to check\n * `IssuerRegistry.isActiveByPointToken` if not stable)\n *\n * Recipient rejected when equal to `pafiFeeRecipient` (self-fee abuse)\n * or `0x0` (use the burn scenario for that).\n *\n * See `docs/SPONSORED_ERC20_TRANSFER_SPEC.md` for the full call\n * pattern, error codes, and edge cases.\n */\n async handleErc20Transfer(\n authenticatedAddress: Address,\n request: ApiErc20TransferRequest,\n ): Promise<ApiErc20TransferResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleErc20Transfer: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleErc20Transfer: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"ZERO_AMOUNT\",\n \"handleErc20Transfer: amount must be positive\",\n );\n }\n\n const userAddress = getAddress(request.userAddress);\n const tokenAddress = getAddress(request.tokenAddress);\n const recipient = getAddress(request.recipient);\n\n const addrs = getContractAddresses(request.chainId);\n const pafiFeeRecipient = addrs.pafiFeeRecipient;\n\n // Recipient block list — surfaces fast in FE before the sponsor\n // relayer rejects the same payload server-side.\n if (recipient.toLowerCase() === pafiFeeRecipient.toLowerCase()) {\n throw new ValidationError(\n \"SELF_FEE_ABUSE\",\n \"handleErc20Transfer: recipient cannot be the PAFI fee recipient\",\n { recipient, pafiFeeRecipient },\n );\n }\n if (recipient === \"0x0000000000000000000000000000000000000000\") {\n throw new ValidationError(\n \"USE_BURN_SCENARIO\",\n \"handleErc20Transfer: recipient cannot be the zero address — use the burn scenario instead\",\n );\n }\n\n // Stable-coin fast path (USDC + USDT are unconditionally allowed).\n // For non-stables, the caller (issuer-backend or controller layer)\n // is responsible for verifying the token is an active PointToken\n // via IssuerRegistry. The sponsor-relayer re-checks server-side, so\n // an unchecked PT here just gets rejected at submit time — fail\n // closed, not open.\n const isStable =\n (addrs.usdc &&\n tokenAddress.toLowerCase() === addrs.usdc.toLowerCase()) ||\n tokenAddress.toLowerCase() === addrs.usdt.toLowerCase();\n\n // Auto-quote fee unless overridden.\n let feeAmount: bigint;\n if (request.feeAmount !== undefined) {\n feeAmount = request.feeAmount > 0n ? request.feeAmount : 0n;\n } else {\n feeAmount = await quoteOperatorFeeForTransfer({\n provider: this.provider,\n chainId: request.chainId,\n tokenAddress,\n });\n }\n\n if (feeAmount > 0n && feeAmount >= request.amount) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n `handleErc20Transfer: fee (${feeAmount}) must be strictly less than amount (${request.amount})`,\n { feeAmount, amount: request.amount },\n );\n }\n\n const userOp = buildErc20TransferUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n tokenAddress,\n recipient,\n amount: request.amount,\n feeAmount: feeAmount > 0n ? feeAmount : undefined,\n feeRecipient: feeAmount > 0n ? pafiFeeRecipient : undefined,\n });\n\n // Fallback variant emitted only when there IS a fee to strip —\n // matches the perp-deposit + swap response shape.\n const userOpFallback =\n feeAmount > 0n\n ? buildErc20TransferUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n tokenAddress,\n recipient,\n amount: request.amount,\n // No feeAmount → 1-call variant (transfer only).\n })\n : undefined;\n\n // Quiet `isStable` \"unused\" warning while preserving the on-chain\n // semantic comment above — actual whitelist enforcement is\n // server-side (sponsor-relayer + issuer-backend).\n void isStable;\n\n return {\n userOp,\n userOpFallback,\n feeAmountUsed: feeAmount,\n feeRecipient: pafiFeeRecipient,\n tokenAddress,\n };\n }\n}\n\n/**\n * `addresses.ts` uses `0x000…<suffix>` sentinels for chains where a\n * given contract is not yet deployed. Detect them by upper-160-bits =\n * 0 so we route to the Vault fallback automatically.\n */\nfunction isPlaceholderAddress(addr: Address): boolean {\n return /^0x0{36}[0-9a-fA-F]{4}$/i.test(addr);\n}\n\n/**\n * Quote the operator gas fee in OUTPUT token raw units. Picks the right\n * underlying quoter:\n *\n * - Output is USDT (canonical address from `getContractAddresses`):\n * `quoteOperatorFeeUsdt` — pure Chainlink ETH/USD, no V4 hop.\n * - Output is anything else (PT0, PT1, ...): `quoteOperatorFeePt`\n * against the output token's V4 pool.\n *\n * Used by `handleQuote` (display the user-facing net output) and\n * `handleSwap` (auto-quote when caller didn't override\n * `gasFeeAmountOutput`).\n */\nasync function quoteOperatorFeeOutput(\n provider: PublicClient,\n chainId: number,\n outputTokenAddress: Address,\n): Promise<bigint> {\n const { usdt } = getContractAddresses(chainId);\n if (\n usdt &&\n getAddress(outputTokenAddress) === getAddress(usdt as Address)\n ) {\n return quoteOperatorFeeUsdt({ provider, chainId });\n }\n return quoteOperatorFeePt({\n provider,\n chainId,\n pointTokenAddress: outputTokenAddress,\n });\n}\n\n/**\n * Quote the operator gas fee in INPUT token raw units. Same dispatch\n * logic as `quoteOperatorFeeOutput` but reads `inputTokenAddress` —\n * used by the exact-output handlers, where the operator fee is charged\n * input-side (pre-swap) so the user receives a precise output amount.\n */\nasync function quoteOperatorFeeInput(\n provider: PublicClient,\n chainId: number,\n inputTokenAddress: Address,\n): Promise<bigint> {\n const { usdt } = getContractAddresses(chainId);\n if (\n usdt &&\n getAddress(inputTokenAddress) === getAddress(usdt as Address)\n ) {\n return quoteOperatorFeeUsdt({ provider, chainId });\n }\n return quoteOperatorFeePt({\n provider,\n chainId,\n pointTokenAddress: inputTokenAddress,\n });\n}\n","import type { Address } from \"viem\";\nimport type { PoolKey, V3Path } from \"@pafi-dev/core\";\nimport { COMMON_POOLS, POINT_TOKEN_POOLS } from \"@pafi-dev/core\";\n\n/**\n * Combine point-token-specific pools and common pools for a given chain.\n * Point token pools are listed first so callers can prioritise them.\n */\nexport function combineRoutes(\n chainId: number,\n pointTokenAddress: Address,\n): PoolKey[] {\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const pointPools = POINT_TOKEN_POOLS[chainId]?.[pointTokenAddress] ?? [];\n return [...pointPools, ...commonPools];\n}\n\n/**\n * Build all possible V3 swap paths from `tokenIn` to `tokenOut` using\n * the given pools. Returns an array of `V3Path` routes (each up to\n * `maxHops` hops, in canonical input→output orientation).\n *\n * Supports both direct single-hop routes and multi-hop routes through\n * intermediate tokens. Each pool is used at most once per path.\n *\n * @param pools - Available pools to route through\n * @param tokenIn - Input token address\n * @param tokenOut - Desired output token address\n * @param maxHops - Maximum number of hops (default 3)\n */\nexport function buildAllPaths(\n pools: PoolKey[],\n tokenIn: Address,\n tokenOut: Address,\n maxHops = 3,\n): V3Path[] {\n const results: V3Path[] = [];\n\n function dfs(\n currentToken: Address,\n tokens: Address[],\n fees: number[],\n usedPoolIndices: Set<number>,\n ) {\n // tokens.length - 1 is the number of hops accumulated so far.\n const hopsSoFar = tokens.length - 1;\n if (hopsSoFar > maxHops) return;\n\n if (\n hopsSoFar > 0 &&\n currentToken.toLowerCase() === tokenOut.toLowerCase()\n ) {\n results.push({ tokens: [...tokens], fees: [...fees] });\n return;\n }\n\n for (let i = 0; i < pools.length; i++) {\n if (usedPoolIndices.has(i)) continue;\n\n const pool = pools[i]!;\n const t0 = pool.token0.toLowerCase();\n const t1 = pool.token1.toLowerCase();\n const curr = currentToken.toLowerCase();\n\n let nextToken: Address | null = null;\n if (curr === t0) {\n nextToken = pool.token1 as Address;\n } else if (curr === t1) {\n nextToken = pool.token0 as Address;\n }\n\n if (!nextToken) continue;\n\n usedPoolIndices.add(i);\n tokens.push(nextToken);\n fees.push(pool.fee);\n dfs(nextToken, tokens, fees, usedPoolIndices);\n tokens.pop();\n fees.pop();\n usedPoolIndices.delete(i);\n }\n }\n\n dfs(tokenIn, [tokenIn], [], new Set());\n return results;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type {\n BestQuote,\n ExactOutputBestQuote,\n ExactOutputQuoteResult,\n PoolKey,\n QuoteResult,\n V3Path,\n} from \"@pafi-dev/core\";\nimport {\n COMMON_POOLS,\n QUOTER_V2_ADDRESSES,\n encodeV3Path,\n encodeV3PathReversed,\n v3QuoterV2Abi,\n} from \"@pafi-dev/core\";\nimport { buildAllPaths } from \"./routes\";\n\n// =========================================================================\n// V3 QuoterV2 wrappers\n// =========================================================================\n//\n// QuoterV2 returns a 4-tuple\n// `(amountOut, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate)`\n// for multi-hop and a 4-tuple\n// `(amountOut, sqrtPriceX96After, initializedTicksCrossed, gasEstimate)`\n// for single-hop. The wrappers below collapse to `{amountOut, gasEstimate}`\n// for API parity with the previous V4-Quoter shape. Callers needing the\n// sqrt-price / ticks-crossed signals must read the raw ABI directly.\n// =========================================================================\n\n/**\n * Quote exact-input for a multi-hop V3 path.\n *\n * `path` is in canonical input→output orientation; the encoder produces\n * `tokens[0] ‖ fees[0] ‖ tokens[1] ‖ ... ‖ tokens[N]` packed bytes.\n */\nexport async function quoteExactInput(\n client: PublicClient,\n quoterAddress: Address,\n path: V3Path,\n exactAmount: bigint,\n): Promise<QuoteResult> {\n const pathBytes = encodeV3Path(path);\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInput\",\n args: [pathBytes, exactAmount],\n })) as readonly [bigint, readonly bigint[], readonly number[], bigint];\n const [amountOut, , , gasEstimate] = result;\n\n return { amountOut, gasEstimate, path };\n}\n\n/**\n * Quote exact-input for a single-hop V3 swap, given an explicit pool\n * and direction. `sqrtPriceLimitX96 = 0n` disables the price-limit\n * guard (the on-chain \"no limit\" sentinel).\n */\nexport async function quoteExactInputSingle(\n client: PublicClient,\n quoterAddress: Address,\n tokenIn: Address,\n tokenOut: Address,\n fee: number,\n exactAmount: bigint,\n sqrtPriceLimitX96: bigint = 0n,\n): Promise<{ amountOut: bigint; gasEstimate: bigint }> {\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn,\n tokenOut,\n amountIn: exactAmount,\n fee,\n sqrtPriceLimitX96,\n },\n ],\n })) as readonly [bigint, bigint, number, bigint];\n const [amountOut, , , gasEstimate] = result;\n\n return { amountOut, gasEstimate };\n}\n\n/**\n * Try multiple V3Path routes and return the best quote plus all results.\n * Routes that fail (e.g. pool does not exist, insufficient liquidity)\n * are silently skipped. The first failure reason is included in the\n * error message when EVERY route fails.\n *\n * Uses viem multicall to batch all quotes into a single RPC call.\n */\nexport async function quoteBestRoute(\n client: PublicClient,\n quoterAddress: Address,\n routes: V3Path[],\n exactAmount: bigint,\n): Promise<BestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInput\" as const,\n args: [encodeV3Path(path), exactAmount] as const,\n })),\n allowFailure: true,\n });\n\n const allRoutes: QuoteResult[] = [];\n let firstFailure: string | undefined;\n for (let i = 0; i < results.length; i++) {\n const r = results[i]!;\n if (r.status === \"success\") {\n const tuple = r.result as unknown as readonly [\n bigint,\n readonly bigint[],\n readonly number[],\n bigint,\n ];\n if (!Array.isArray(tuple) || tuple.length < 4) {\n if (firstFailure === undefined) {\n const len = Array.isArray(tuple) ? tuple.length : \"n/a\";\n firstFailure = `unexpected QuoterV2 return shape (length=${len})`;\n }\n continue;\n }\n const [amountOut, , , gasEstimate] = tuple;\n allRoutes.push({ amountOut, gasEstimate, path: routes[i]! });\n } else if (firstFailure === undefined) {\n const errMsg =\n r.error instanceof Error\n ? r.error.message\n : String((r as { error?: unknown }).error ?? \"unknown\");\n firstFailure = errMsg;\n }\n }\n\n if (allRoutes.length === 0) {\n throw new Error(\n `No valid routes found (${routes.length} candidates probed)` +\n (firstFailure ? `; first failure: ${firstFailure}` : \"\"),\n );\n }\n\n const bestRoute = allRoutes.reduce((best, current) =>\n current.amountOut > best.amountOut ? current : best,\n );\n\n return { bestRoute, allRoutes };\n}\n\n/**\n * Find and quote the best V3 swap route from `tokenIn` to `tokenOut`.\n *\n * Combines the caller's `pools` with `COMMON_POOLS[chainId]`, builds all\n * possible paths (up to `maxHops`), then quotes them all via a single\n * multicall and returns the best result.\n *\n * @param client - viem PublicClient\n * @param chainId - Chain ID (used to look up COMMON_POOLS and QUOTER_V2_ADDRESSES)\n * @param tokenIn - Input token address\n * @param tokenOut - Desired output token address\n * @param exactAmount - Exact input amount\n * @param pools - Additional pools to consider (e.g. point-token-specific)\n * @param quoterAddress - Override the default V3 QuoterV2 address for this chain\n * @param maxHops - Maximum number of hops per path (default 3)\n */\nexport async function findBestQuote(\n client: PublicClient,\n chainId: number,\n tokenIn: Address,\n tokenOut: Address,\n exactAmount: bigint,\n pools: PoolKey[] = [],\n quoterAddress?: Address,\n maxHops = 3,\n): Promise<BestQuote> {\n const quoter = quoterAddress ?? QUOTER_V2_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V3 QuoterV2 address configured for chain ${chainId}`);\n }\n\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const allPools = [...pools, ...commonPools];\n const paths = buildAllPaths(allPools, tokenIn, tokenOut, maxHops);\n\n if (paths.length === 0) {\n throw new Error(`No paths found from ${tokenIn} to ${tokenOut}`);\n }\n\n return quoteBestRoute(client, quoter, paths, exactAmount);\n}\n\n// =========================================================================\n// V3 exact-output quoting\n// =========================================================================\n//\n// CAUTION: the on-chain `quoteExactOutput` walks the path output→input.\n// Callers of this SDK should pass paths in canonical input→output\n// orientation; the encoder reverses internally.\n// =========================================================================\n\n/**\n * Quote V3 exact-output for a multi-hop path.\n *\n * @param path - V3Path in canonical input→output orientation.\n * The encoder reverses for the on-chain call.\n * @param exactAmount - Exact OUTPUT amount the user wants to receive.\n * @returns `{ amountIn, gasEstimate, path }` — the input amount required.\n */\nexport async function quoteExactOutput(\n client: PublicClient,\n quoterAddress: Address,\n path: V3Path,\n exactAmount: bigint,\n): Promise<ExactOutputQuoteResult> {\n const pathBytes = encodeV3PathReversed(path);\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutput\",\n args: [pathBytes, exactAmount],\n })) as readonly [bigint, readonly bigint[], readonly number[], bigint];\n const [amountIn, , , gasEstimate] = result;\n\n return { amountIn, gasEstimate, path };\n}\n\n/**\n * Quote V3 exact-output for a single-hop swap, given an explicit\n * `tokenIn`/`tokenOut`/`fee` triple.\n */\nexport async function quoteExactOutputSingle(\n client: PublicClient,\n quoterAddress: Address,\n tokenIn: Address,\n tokenOut: Address,\n fee: number,\n exactAmount: bigint,\n sqrtPriceLimitX96: bigint = 0n,\n): Promise<{ amountIn: bigint; gasEstimate: bigint }> {\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutputSingle\",\n args: [\n {\n tokenIn,\n tokenOut,\n amount: exactAmount,\n fee,\n sqrtPriceLimitX96,\n },\n ],\n })) as readonly [bigint, bigint, number, bigint];\n const [amountIn, , , gasEstimate] = result;\n\n return { amountIn, gasEstimate };\n}\n\n/**\n * Try multiple V3Path routes for an exact-output swap and return the\n * route requiring the **smallest** input amount, plus all results.\n * Routes that fail are silently skipped.\n */\nexport async function quoteBestRouteExactOut(\n client: PublicClient,\n quoterAddress: Address,\n routes: V3Path[],\n exactAmount: bigint,\n): Promise<ExactOutputBestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutput\" as const,\n args: [encodeV3PathReversed(path), exactAmount] as const,\n })),\n allowFailure: true,\n });\n\n const allRoutes: ExactOutputQuoteResult[] = [];\n let firstFailure: string | undefined;\n for (let i = 0; i < results.length; i++) {\n const r = results[i]!;\n if (r.status === \"success\") {\n const tuple = r.result as unknown as readonly [\n bigint,\n readonly bigint[],\n readonly number[],\n bigint,\n ];\n if (!Array.isArray(tuple) || tuple.length < 4) {\n if (firstFailure === undefined) {\n const len = Array.isArray(tuple) ? tuple.length : \"n/a\";\n firstFailure = `unexpected QuoterV2 return shape (length=${len})`;\n }\n continue;\n }\n const [amountIn, , , gasEstimate] = tuple;\n allRoutes.push({ amountIn, gasEstimate, path: routes[i]! });\n } else if (firstFailure === undefined) {\n const errMsg =\n r.error instanceof Error\n ? r.error.message\n : String((r as { error?: unknown }).error ?? \"unknown\");\n firstFailure = errMsg;\n }\n }\n\n if (allRoutes.length === 0) {\n throw new Error(\n `No valid exact-output routes found (${routes.length} candidates probed)` +\n (firstFailure ? `; first failure: ${firstFailure}` : \"\"),\n );\n }\n\n const bestRoute = allRoutes.reduce((best, current) =>\n current.amountIn < best.amountIn ? current : best,\n );\n\n return { bestRoute, allRoutes };\n}\n\n/**\n * Find and quote the best V3 exact-output route from `tokenIn` to\n * `tokenOut` for a desired output amount.\n *\n * Symmetric to `findBestQuote` but `exactAmount` is denominated in\n * `tokenOut` (the OUTPUT token). Paths are enumerated input→output (the\n * canonical SDK orientation) — the QuoterV2 wrapper reverses for the\n * on-chain call.\n *\n * @param client - viem PublicClient.\n * @param chainId - Chain ID (looks up COMMON_POOLS + QUOTER_V2_ADDRESSES).\n * @param tokenIn - Input token address (what user pays).\n * @param tokenOut - Output token address (what user wants exactly).\n * @param exactAmount - Exact OUTPUT amount.\n * @param pools - Additional pools (e.g. point-token-specific).\n * @param quoterAddress - Override the default V3 QuoterV2 address.\n * @param maxHops - Maximum number of hops per path (default 3).\n */\nexport async function findBestQuoteExactOut(\n client: PublicClient,\n chainId: number,\n tokenIn: Address,\n tokenOut: Address,\n exactAmount: bigint,\n pools: PoolKey[] = [],\n quoterAddress?: Address,\n maxHops = 3,\n): Promise<ExactOutputBestQuote> {\n const quoter = quoterAddress ?? QUOTER_V2_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V3 QuoterV2 address configured for chain ${chainId}`);\n }\n\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const allPools = [...pools, ...commonPools];\n\n const paths = buildAllPaths(allPools, tokenIn, tokenOut, maxHops);\n\n if (paths.length === 0) {\n throw new Error(\n `No exact-output paths found from ${tokenIn} to ${tokenOut}`,\n );\n }\n\n return quoteBestRouteExactOut(client, quoter, paths, exactAmount);\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex, PublicClient } from \"viem\";\nimport { erc20Abi } from \"@pafi-dev/core\";\nimport { permit2Abi } from \"@pafi-dev/core\";\n\nexport async function checkAllowance(\n client: PublicClient,\n token: Address,\n owner: Address,\n spender: Address,\n): Promise<bigint> {\n return client.readContract({\n address: token,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner, spender],\n });\n}\n\n/**\n * Encode an ERC-20 approve(spender, amount) call.\n */\nexport function buildErc20ApprovalCalldata(\n spender: Address,\n amount: bigint,\n): Hex {\n return encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n });\n}\n\n/**\n * Encode a Permit2 approve(token, spender, amount, expiration) call.\n */\nexport function buildPermit2ApprovalCalldata(\n token: Address,\n spender: Address,\n amount: bigint,\n expiration: number,\n): Hex {\n return encodeFunctionData({\n abi: permit2Abi,\n functionName: \"approve\",\n args: [token, spender, amount, expiration],\n });\n}\n","import { encodeAbiParameters, encodePacked } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { encodeV3Path, encodeV3PathReversed, type V3Path } from \"@pafi-dev/core\";\n\n// -------------------------------------------------------------------------\n// V3 UniversalRouter command constants\n// Reference: https://github.com/Uniswap/universal-router/blob/main/contracts/libraries/Commands.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V3 exact-input swap. */\nexport const V3_SWAP_EXACT_IN = 0x00 as const;\n\n/** UniversalRouter command byte for V3 exact-output swap. */\nexport const V3_SWAP_EXACT_OUT = 0x01 as const;\n\n/** Max value of a uint128 — used to guard exact-out `maxAmountIn` and `amountOut`. */\nconst UINT128_MAX = 2n ** 128n - 1n;\n\n// -------------------------------------------------------------------------\n// V3 swap input encoding (V3_SWAP_EXACT_IN / V3_SWAP_EXACT_OUT)\n//\n// Universal Router input layout for V3 swaps:\n// abi.encode(\n// address recipient,\n// uint256 amountIn / amountOut,\n// uint256 amountOutMinimum / amountInMaximum,\n// bytes path,\n// bool payerIsUser,\n// )\n//\n// `payerIsUser = true` instructs the router to pull tokens from the user\n// via Permit2 (the only path the SDK supports). Setting it to `false`\n// would make the router spend its own balance — relevant for chained\n// swaps and not applicable here.\n// -------------------------------------------------------------------------\n\nconst V3_EXACT_IN_INPUT_ABI = [\n { name: \"recipient\", type: \"address\" },\n { name: \"amountIn\", type: \"uint256\" },\n { name: \"amountOutMinimum\", type: \"uint256\" },\n { name: \"path\", type: \"bytes\" },\n { name: \"payerIsUser\", type: \"bool\" },\n] as const;\n\nconst V3_EXACT_OUT_INPUT_ABI = [\n { name: \"recipient\", type: \"address\" },\n { name: \"amountOut\", type: \"uint256\" },\n { name: \"amountInMaximum\", type: \"uint256\" },\n { name: \"path\", type: \"bytes\" },\n { name: \"payerIsUser\", type: \"bool\" },\n] as const;\n\n/**\n * Build the calldata `inputs[0]` payload for the `V3_SWAP_EXACT_IN`\n * command. Path bytes are packed input→output; the router walks the\n * same direction.\n */\nexport function buildV3SwapInputExactIn(\n recipient: Address,\n path: V3Path,\n amountIn: bigint,\n minAmountOut: bigint,\n): Hex {\n if (amountIn <= 0n || amountIn > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactIn: amountIn (${amountIn}) must be in (0, 2^128-1]`,\n );\n }\n if (minAmountOut < 0n) {\n throw new Error(\n `buildV3SwapInputExactIn: minAmountOut (${minAmountOut}) must be non-negative`,\n );\n }\n\n const pathBytes = encodeV3Path(path);\n\n return encodeAbiParameters(V3_EXACT_IN_INPUT_ABI, [\n recipient,\n amountIn,\n minAmountOut,\n pathBytes,\n true, // payerIsUser — router pulls via Permit2 (the SDK's only flow)\n ]);\n}\n\n/**\n * Build the calldata `inputs[0]` payload for the `V3_SWAP_EXACT_OUT`\n * command. Path bytes are packed output→input — the router walks the\n * desired output back to the input, taking only as much input as needed\n * (capped by `maxAmountIn`).\n *\n * The `path` argument is in canonical input→output orientation; the\n * encoder reverses internally so callers don't have to reason about\n * direction.\n */\nexport function buildV3SwapInputExactOut(\n recipient: Address,\n path: V3Path,\n amountOut: bigint,\n maxAmountIn: bigint,\n): Hex {\n if (amountOut <= 0n || amountOut > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactOut: amountOut (${amountOut}) must be in (0, 2^128-1]`,\n );\n }\n if (maxAmountIn <= 0n || maxAmountIn > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactOut: maxAmountIn (${maxAmountIn}) must be in (0, 2^128-1]`,\n );\n }\n\n const pathBytes = encodeV3PathReversed(path);\n\n return encodeAbiParameters(V3_EXACT_OUT_INPUT_ABI, [\n recipient,\n amountOut,\n maxAmountIn,\n pathBytes,\n true, // payerIsUser\n ]);\n}\n\n/**\n * Build the full `commands` + `inputs` args for `UniversalRouter.execute`\n * for an exact-input V3 swap.\n */\nexport function buildUniversalRouterExecuteArgs(\n recipient: Address,\n path: V3Path,\n amountIn: bigint,\n minAmountOut: bigint,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V3_SWAP_EXACT_IN]);\n const inputs: Hex[] = [\n buildV3SwapInputExactIn(recipient, path, amountIn, minAmountOut),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build the full `commands` + `inputs` args for `UniversalRouter.execute`\n * for an exact-output V3 swap.\n */\nexport function buildUniversalRouterExecuteArgsExactOut(\n recipient: Address,\n path: V3Path,\n amountOut: bigint,\n maxAmountIn: bigint,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V3_SWAP_EXACT_OUT]);\n const inputs: Hex[] = [\n buildV3SwapInputExactOut(recipient, path, amountOut, maxAmountIn),\n ];\n return { commands, inputs };\n}\n","import type { Address, Hex, PublicClient } from \"viem\";\nimport { universalRouterAbi } from \"@pafi-dev/core\";\nimport { SimulationError } from \"@pafi-dev/core\";\n\nexport interface SwapSimulationResult {\n success: boolean;\n gasEstimate: bigint;\n}\n\n/**\n * Simulate a UniversalRouter.execute swap call via eth_call (no gas spent).\n *\n * Runs the full V4 swap flow — token transfer via Permit2, swap via\n * PoolManager, output settlement — without submitting a transaction.\n * If the simulation reverts, throws a `SimulationError` with the reason.\n *\n * @param client - viem PublicClient\n * @param routerAddress - UniversalRouter contract address\n * @param commands - Packed command bytes (from buildSwapFromQuote)\n * @param inputs - Encoded inputs per command (from buildSwapFromQuote)\n * @param deadline - Unix timestamp after which the tx expires\n * @param from - Address that will execute the swap\n */\nexport async function simulateSwap(\n client: PublicClient,\n routerAddress: Address,\n commands: Hex,\n inputs: Hex[],\n deadline: bigint,\n from: Address,\n): Promise<SwapSimulationResult> {\n try {\n const gasEstimate = await client.estimateContractGas({\n address: routerAddress,\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, deadline],\n account: from,\n });\n\n return { success: true, gasEstimate };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Unknown simulation error\";\n throw new SimulationError(\"swap\", message);\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport {\n PERMIT2_ADDRESS,\n buildPartialUserOperation,\n erc20ApproveOp,\n erc20TransferOp,\n rawCallOp,\n universalRouterAbi,\n type Operation,\n type PartialUserOperation,\n type V3Path,\n} from \"@pafi-dev/core\";\nimport {\n buildUniversalRouterExecuteArgs,\n buildUniversalRouterExecuteArgsExactOut,\n} from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\n\n/**\n * v0.5 — Generalized swap UserOp builder. Direction-agnostic: works\n * for **any** ERC-20 → ERC-20 pair routable through PAFI's V3 pools:\n *\n * - PT → USDT (cashout)\n * - USDT → PT (buy PT with USDT)\n * - PT0 → PT1 (same-issuer multi-token swap; routes via USDT)\n *\n * UserOp shape (atomic batch via EIP-7702 BatchExecutor):\n *\n * 1. `inputToken.approve(Permit2, amountIn)` — exactly the swap amount.\n * 2. `Permit2.approve(inputToken, router, amountIn, deadline)` — Permit2\n * authorization to UniversalRouter.\n * 3. `UniversalRouter.execute(commands, inputs, deadline)` — V3 swap\n * `inputToken → outputToken`; user receives ≥ `minAmountOut`.\n * 4. `outputToken.transfer(feeRecipient, gasFeeAmountOutput)` —\n * operator gas reimbursement, paid in OUTPUT token (omitted when 0).\n *\n * ## Fee model — output-token strategy (token-availability rule)\n *\n * Fee is charged in the **output token** AFTER the swap, because the\n * user holds output token at that point in the batch. Three benefits:\n *\n * - User holds exactly `amountIn` of input token (FE quote = chain\n * reality). No \"you need 1010 to swap 1000\" UX surprise.\n * - Quote API returns `outputNet = outputGross - feeOutput` directly,\n * matching what user actually receives.\n * - PT → USDT: PAFI receives USDT (universally liquid, clean accounting).\n *\n * Caller MUST ensure `minAmountOut >= gasFeeAmountOutput` (fee transfer\n * reverts otherwise → whole batch reverts).\n *\n * ## Pool-level fees\n *\n * PAFI's PT pools are standard Uniswap V3 — no swap-time hooks. The\n * protocol's gas-recoupment fee lives in `MintFeeWrapper` on the mint\n * path; the only pool-level economics here are Uniswap's regular LP\n * fee tier (per the PoolKey's `fee` field), already baked into the\n * quote returned by `findBestQuote`. This builder doesn't apply or\n * model any additional swap-time fee on top.\n */\nexport interface BuildSwapUserOpParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Token being spent — approved to Permit2 + UniversalRouter. */\n inputTokenAddress: Address;\n /** Token user receives. */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** Input token units to swap. User must hold exactly this much input token. */\n amountIn: bigint;\n /**\n * Minimum output (gross) to accept from the swap. Caller applies\n * slippage against a fresh quote. MUST be ≥ `gasFeeAmountOutput` or\n * the post-swap fee transfer reverts.\n */\n minAmountOut: bigint;\n\n /**\n * V3 swap path. `tokens.length === fees.length + 1`. Get this from\n * `findBestQuote().bestRoute.path`. Single-hop has 2 tokens + 1 fee;\n * multi-hop has N+1 tokens + N fees.\n */\n swapPath: V3Path;\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /**\n * Operator gas-reimbursement fee — paid in OUTPUT token. Omitted\n * from the batch when 0n. Caller quotes this via `quoteOperatorFee*`\n * helpers (USDT/PT depending on output token).\n *\n * v0.3 — switched from input-side fee (v0.2 `gasFeeAmount`) to\n * output-side fee. See \"Fee model\" comment above.\n */\n gasFeeAmountOutput: bigint;\n /**\n * Where the gas fee lands — typically the canonical PAFI fee\n * recipient from `getContractAddresses(chainId).pafiFeeRecipient`.\n */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for the generalized swap flow.\n *\n * @throws when `amountIn` is non-positive, `gasFeeAmountOutput` is\n * negative, `swapPath` is empty, or `minAmountOut < gasFeeAmountOutput`.\n */\nexport function buildSwapUserOp(\n params: BuildSwapUserOpParams,\n): PartialUserOperation {\n if (params.amountIn <= 0n) {\n throw new Error(\"buildSwapUserOp: amountIn must be positive\");\n }\n if (params.minAmountOut < 0n) {\n throw new Error(\"buildSwapUserOp: minAmountOut must be non-negative\");\n }\n if (params.gasFeeAmountOutput < 0n) {\n throw new Error(\"buildSwapUserOp: gasFeeAmountOutput must be non-negative\");\n }\n if (\n params.gasFeeAmountOutput > 0n &&\n params.minAmountOut < params.gasFeeAmountOutput\n ) {\n throw new Error(\n \"buildSwapUserOp: minAmountOut must be >= gasFeeAmountOutput so the post-swap fee transfer cannot revert\",\n );\n }\n if (params.swapPath.tokens.length < 2 || params.swapPath.fees.length < 1) {\n throw new Error(\n \"buildSwapUserOp: swapPath must contain at least one hop (>=2 tokens, >=1 fee)\",\n );\n }\n if (params.swapPath.tokens.length !== params.swapPath.fees.length + 1) {\n throw new Error(\n \"buildSwapUserOp: swapPath.tokens.length must equal swapPath.fees.length + 1\",\n );\n }\n // Assert deadline fits Permit2's uint48 expiration field (max 2^48 - 1\n // ≈ year 8,921,478 in unix seconds). Catches the common bug where a\n // caller passes deadline in milliseconds; also guards against any\n // future caller passing > 2^53 (Number cast lossy).\n const PERMIT2_EXPIRATION_MAX = 2n ** 48n - 1n;\n if (params.deadline <= 0n || params.deadline > PERMIT2_EXPIRATION_MAX) {\n throw new Error(\n `buildSwapUserOp: deadline (${params.deadline}) must be unix seconds in (0, 2^48-1]. ` +\n `Did you accidentally pass milliseconds?`,\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgs(\n params.userAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n // Approve only the swap amount — fee comes out of swap proceeds.\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.inputTokenAddress,\n params.universalRouterAddress,\n params.amountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [\n erc20ApproveOp(params.inputTokenAddress, PERMIT2_ADDRESS, params.amountIn),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n ];\n\n // Fee transfer in OUTPUT token, AFTER swap, when user holds output.\n if (params.gasFeeAmountOutput > 0n) {\n operations.push(\n erc20TransferOp(\n params.outputTokenAddress,\n params.feeRecipient,\n params.gasFeeAmountOutput,\n ),\n );\n }\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 700_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n\n// =========================================================================\n// V3 exact-output swap UserOp builder\n// =========================================================================\n//\n// Symmetric to `buildSwapUserOp` but for the exact-output flow. Two\n// design choices that diverge:\n//\n// 1. Operation order — fee transfer goes FIRST (pre-swap, in INPUT\n// token). At post-swap time the user receives *exactly* `amountOut`\n// of output; charging an output-side fee would silently break the\n// \"exact output\" guarantee. Mirrors the v0.3 input-side fee pattern\n// used by perp-deposit (Relay path).\n//\n// 2. Permit2 + ERC-20 approvals cover `maxAmountIn` (cap), not the\n// exact pull. V3's exact-output router pulls only the amount the\n// swap actually consumed and reverts if it would exceed the cap.\n//\n// Caller pre-conditions (none enforced on chain — caller must arrange):\n//\n// - User holds at least `maxAmountIn + gasFeeAmountInput` of input token.\n// - `maxAmountIn` already includes the slippage cushion the caller\n// wants (recommended: `maxAmountIn = ceil(estimatedInputAmount *\n// (10000 + slippageBps) / 10000)`).\n//\n// =========================================================================\n\n/**\n * Parameters for `buildSwapUserOpExactOut`.\n *\n * @remarks\n * The user must hold **`maxAmountIn + gasFeeAmountInput`** of\n * `inputTokenAddress` before this UserOp executes — the operator-fee\n * transfer is pre-swap, so it cannot be paid from swap proceeds.\n */\nexport interface BuildSwapUserOpExactOutParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Token being spent — approved to Permit2 + UniversalRouter. */\n inputTokenAddress: Address;\n /** Token user receives (exactly `amountOut` of). */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** Exact OUTPUT token amount the user wants to receive. */\n amountOut: bigint;\n /**\n * Maximum INPUT token amount the user is willing to spend on the swap\n * (slippage cap). The Permit2 approval covers this amount; the swap\n * settles only the actual amount consumed.\n */\n maxAmountIn: bigint;\n\n /**\n * V3 swap path in canonical **input→output** orientation. The encoder\n * reverses internally for the on-chain exact-output Router call.\n * Get this from `findBestQuoteExactOut().bestRoute.path`.\n */\n swapPath: V3Path;\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /**\n * Operator gas-reimbursement fee — paid in INPUT token, transferred\n * BEFORE the swap. Omitted from the batch when 0n.\n *\n * Charged input-side rather than output-side because exact-output\n * promises the user a precise output amount; deducting from output\n * would silently break that promise. Mirrors the v0.3 input-side fee\n * pattern used by perp-deposit.\n */\n gasFeeAmountInput: bigint;\n /**\n * Where the gas fee lands — typically the canonical PAFI fee\n * recipient from `getContractAddresses(chainId).pafiFeeRecipient`.\n */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for the V3 exact-output swap flow.\n *\n * UserOp shape (atomic batch via EIP-7702 BatchExecutor):\n *\n * 1. `inputToken.transfer(feeRecipient, gasFeeAmountInput)` — operator\n * gas reimbursement, paid in INPUT token (omitted when 0).\n * 2. `inputToken.approve(Permit2, maxAmountIn)` — cap, not exact.\n * 3. `Permit2.approve(inputToken, router, maxAmountIn, deadline)` —\n * Permit2 authorization to UniversalRouter for up to `maxAmountIn`.\n * 4. `UniversalRouter.execute(commands, inputs, deadline)` — V3\n * exact-output swap; user receives exactly `amountOut`.\n *\n * @throws when `amountOut`/`maxAmountIn` are non-positive,\n * `gasFeeAmountInput` is negative, `swapPath` is malformed, or\n * `deadline` is out of Permit2's uint48 range.\n */\nexport function buildSwapUserOpExactOut(\n params: BuildSwapUserOpExactOutParams,\n): PartialUserOperation {\n if (params.amountOut <= 0n) {\n throw new Error(\"buildSwapUserOpExactOut: amountOut must be positive\");\n }\n if (params.maxAmountIn <= 0n) {\n throw new Error(\"buildSwapUserOpExactOut: maxAmountIn must be positive\");\n }\n if (params.gasFeeAmountInput < 0n) {\n throw new Error(\n \"buildSwapUserOpExactOut: gasFeeAmountInput must be non-negative\",\n );\n }\n if (params.swapPath.tokens.length < 2 || params.swapPath.fees.length < 1) {\n throw new Error(\n \"buildSwapUserOpExactOut: swapPath must contain at least one hop (>=2 tokens, >=1 fee)\",\n );\n }\n if (params.swapPath.tokens.length !== params.swapPath.fees.length + 1) {\n throw new Error(\n \"buildSwapUserOpExactOut: swapPath.tokens.length must equal swapPath.fees.length + 1\",\n );\n }\n // Same Permit2-uint48 deadline check as buildSwapUserOp.\n const PERMIT2_EXPIRATION_MAX = 2n ** 48n - 1n;\n if (params.deadline <= 0n || params.deadline > PERMIT2_EXPIRATION_MAX) {\n throw new Error(\n `buildSwapUserOpExactOut: deadline (${params.deadline}) must be unix seconds in (0, 2^48-1]. ` +\n `Did you accidentally pass milliseconds?`,\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgsExactOut(\n params.userAddress,\n params.swapPath,\n params.amountOut,\n params.maxAmountIn,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n // Approve up to maxAmountIn — swap settles only the actual amount used.\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.inputTokenAddress,\n params.universalRouterAddress,\n params.maxAmountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [];\n\n // Op 0 (optional): pre-swap input-token fee transfer to PAFI fee recipient.\n if (params.gasFeeAmountInput > 0n) {\n operations.push(\n erc20TransferOp(\n params.inputTokenAddress,\n params.feeRecipient,\n params.gasFeeAmountInput,\n ),\n );\n }\n\n // Ops 1-3 (or 0-2 when fee is skipped): approval chain + swap.\n operations.push(\n erc20ApproveOp(params.inputTokenAddress, PERMIT2_ADDRESS, params.maxAmountIn),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n );\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n // +50k headroom for the additional pre-swap ERC-20 transfer when\n // the input-side fee is non-zero. Keeps margin even when fee=0n.\n callGasLimit: params.gasLimits?.callGasLimit ?? 750_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","/**\n * Slippage tolerance bounds shared by every swap call site (exact-in\n * + exact-out, handler + FE-direct).\n *\n * - Lower bound `0` — caller asks for zero slippage tolerance. Legal,\n * but the swap is virtually guaranteed to revert on any pool\n * movement; we let it through so callers can opt into strict mode.\n * - Upper bound `5000` (50%) — catches obvious caller bugs (passing\n * a percentage instead of basis points: `50` → ✓, `0.5` → ✗ via\n * the integer check; `50_00_00` → ✗ via this cap). Larger values\n * would let a misconfigured caller authorize a `maxAmountIn` (or\n * accept a `minAmountOut`) wildly outside the quoted band.\n *\n * The cap is intentionally generous — even pathological PT pools\n * post-incident shouldn't need >50% slippage. A caller that genuinely\n * needs more should split the trade.\n */\nexport const MAX_SLIPPAGE_BPS = 5000 as const;\n\n/**\n * Validate a caller-supplied `slippageBps` value. Returns `true` for\n * `undefined` (means \"use the default\") and any integer in\n * `[0, MAX_SLIPPAGE_BPS]`. Returns `false` otherwise — callers should\n * surface a typed error appropriate for their layer (handler →\n * `ValidationError(\"INVALID_SLIPPAGE\", ...)`; direct path → plain\n * `Error`).\n *\n * Rejects:\n * - non-finite numbers (`NaN`, `Infinity`)\n * - non-integers (`0.5`, `50.5`)\n * - negative values (would invert the slippage formula)\n * - values exceeding `MAX_SLIPPAGE_BPS`\n */\nexport function isValidSlippageBps(value: number | undefined): boolean {\n if (value === undefined) return true;\n return (\n Number.isInteger(value) &&\n value >= 0 &&\n value <= MAX_SLIPPAGE_BPS\n );\n}\n","// Re-export from @pafi-dev/core — fetchPafiPools lives in core so all\n// SDK packages share one implementation.\nexport { fetchPafiPools, PAFI_SUBGRAPH_URL } from \"@pafi-dev/core\";\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n UNIVERSAL_ROUTER_ADDRESSES,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n BATCH_EXECUTOR_7702_IMPL,\n type PoolKey,\n} from \"@pafi-dev/core\";\nimport { findBestQuote } from \"../quoting\";\nimport { MAX_SLIPPAGE_BPS, buildSwapUserOp, isValidSlippageBps } from \"../swap\";\n\nexport interface SwapDirectParams {\n /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */\n userAddress: Address;\n chainId: number;\n inputTokenAddress: Address;\n outputTokenAddress: Address;\n /** Input amount (raw token decimals). */\n amount: bigint;\n /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */\n pools?: PoolKey[];\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Slippage tolerance in basis points. Default 50 single-hop / 100\n * multi-hop (handler picks based on `bestRoute.path.length`).\n */\n slippageBps?: number;\n /** Swap deadline (unix seconds). Default = now + 5 minutes. */\n deadline?: bigint;\n /**\n * Operator fee in OUTPUT token, paid to PAFI fee recipient.\n *\n * - `undefined` (default for direct path): **skip the fee transfer\n * entirely** — PAFI is not sponsoring this swap, no reimbursement\n * owed. Most callers want this.\n * - `0n` — same as above, explicit.\n * - explicit `bigint` — include the fee transfer (rare; only when\n * issuer dev/test wants to mirror sponsored behaviour).\n */\n gasFeeAmountOutput?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface SwapDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n estimatedOutputAmount: bigint;\n minAmountOut: bigint;\n hops: number;\n deadline: bigint;\n feeAmountUsed: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct swap** path — no AA, no bundler,\n * no PAFI sponsor-relayer. The user EOA pays gas in ETH and broadcasts\n * a single type-2 transaction calling its own EIP-7702 delegated\n * bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl\n * (canonically Pimlico's `Simple7702Account`; the legacy Coinbase\n * Smart Wallet v2 BatchExecutor is still accepted by\n * `detectDelegateImpl` for EOAs delegated earlier). Throw with a\n * clear hint pointing at `delegateDirect()` if not delegated at\n * all.\n * 2. `findBestQuote` → best route + gross output.\n * 3. `buildSwapUserOp` → encoded `executeBatch(calls)` calldata.\n * 4. `walletClient.sendTransaction({ to: userAddress, data: callData })`\n * — self-call into the delegated bytecode, which dispatches the\n * batch (input.approve → Permit2.approve → UR.execute → optional\n * fee transfer).\n * 5. Wait for receipt (optional).\n *\n * Use when:\n * - The FE doesn't have a Pimlico API key + doesn't want to depend on\n * PAFI sponsor-relayer.\n * - The user already has a small ETH balance.\n * - You need a deterministic, single-tx swap (vs. AA UserOp's longer\n * bundler round-trip).\n *\n * Throws when the user is NOT yet delegated — caller should run\n * `delegateDirect` first or use the AA path (`TradingHandlers.handleSwap`\n * + `permissionless`).\n *\n * @example\n * ```ts\n * import { swapDirect, fetchPafiPools } from \"@pafi-dev/trading\";\n *\n * const pools = await fetchPafiPools(8453, POINT_TOKEN);\n * const result = await swapDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * inputTokenAddress: POINT_TOKEN,\n * outputTokenAddress: USDT,\n * amount: parseUnits(\"100\", 18),\n * pools,\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Swap tx:\", result.txHash);\n * ```\n */\nexport async function swapDirect(\n params: SwapDirectParams,\n): Promise<SwapDirectResult> {\n // 1. Cheap, sync input validation — runs first so a malformed call\n // fails immediately without burning an RPC quota on getCode.\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[params.chainId];\n if (!universalRouter) {\n throw new Error(`swapDirect: no UniversalRouter for chainId ${params.chainId}`);\n }\n if (params.amount <= 0n) {\n throw new Error(\"swapDirect: amount must be positive\");\n }\n if (!isValidSlippageBps(params.slippageBps)) {\n throw new Error(\n `swapDirect: slippageBps (${params.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n );\n }\n\n // Wallet's account MUST be the user EOA — the native tx is sent from\n // `account.address`, and BatchExecutor's executeBatch reverts unless\n // `msg.sender == address(this)` (i.e. the EOA itself executes its\n // delegated bytecode). Catching the mismatch here saves a wasted gas\n // attempt and produces a clear, immediate error.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"swapDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `swapDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress}) — ` +\n `the native tx must be sent from the same EOA whose 7702-delegated bytecode is being executed`,\n );\n }\n\n // 2. Delegation precondition — `executeBatch` only works when the\n // EOA has 7702 bytecode pointing at a known impl.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `swapDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first (user pays a one-time delegation tx) ` +\n `or use the AA path via \\`TradingHandlers.handleSwap()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `swapDirect: user delegated to ${delegate} which is not a PAFI-recognised impl ` +\n `(expected ${SIMPLE_7702_IMPL_BASE_MAINNET} or ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuote>>;\n try {\n quoteResult = await findBestQuote(\n params.publicClient,\n params.chainId,\n params.inputTokenAddress,\n params.outputTokenAddress,\n params.amount,\n params.pools ?? [],\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new Error(\n `swapDirect: no swap path found from ${params.inputTokenAddress} to ${params.outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = params.slippageBps ?? (hops > 1 ? 100 : 50);\n const estimatedOutputAmount = quoteResult.bestRoute.amountOut;\n const minAmountOut =\n (estimatedOutputAmount * BigInt(10000 - slippageBps)) / 10000n;\n const gasFeeAmountOutput = params.gasFeeAmountOutput ?? 0n;\n if (gasFeeAmountOutput > 0n && minAmountOut < gasFeeAmountOutput) {\n throw new Error(\n `swapDirect: minAmountOut (${minAmountOut}) below operator fee (${gasFeeAmountOutput})`,\n );\n }\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 3. Build the UserOp purely to extract its callData (encoded\n // `executeBatch(calls)`). We send that as a native tx instead.\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const userOp = buildSwapUserOp({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path; nonce comes from EOA tx count\n inputTokenAddress: params.inputTokenAddress,\n outputTokenAddress: params.outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: params.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // 4. Send native tx — to: userAddress, data: encoded executeBatch.\n // (`account` validated up-front against `userAddress`.)\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: userOp.callData,\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `swapDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n estimatedOutputAmount,\n minAmountOut,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountOutput,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n UNIVERSAL_ROUTER_ADDRESSES,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n BATCH_EXECUTOR_7702_IMPL,\n type PoolKey,\n} from \"@pafi-dev/core\";\nimport { findBestQuoteExactOut } from \"../quoting\";\nimport {\n MAX_SLIPPAGE_BPS,\n buildSwapUserOpExactOut,\n isValidSlippageBps,\n} from \"../swap\";\n\nexport interface SwapDirectExactOutParams {\n /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */\n userAddress: Address;\n chainId: number;\n inputTokenAddress: Address;\n outputTokenAddress: Address;\n /** Exact OUTPUT amount the user wants to receive (raw token decimals). */\n amount: bigint;\n /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */\n pools?: PoolKey[];\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Slippage tolerance in basis points. Default 50 single-hop / 100\n * multi-hop. Slippage is applied as a CEILING on `maxAmountIn`.\n */\n slippageBps?: number;\n /** Swap deadline (unix seconds). Default = now + 5 minutes. */\n deadline?: bigint;\n /**\n * Operator fee in INPUT token, paid to PAFI fee recipient.\n *\n * - `undefined` (default for direct path): **skip the fee transfer\n * entirely** — PAFI is not sponsoring this swap, no reimbursement\n * owed. Most callers want this.\n * - `0n` — same as above, explicit.\n * - explicit `bigint` — include the fee transfer (rare; only when\n * issuer dev/test wants to mirror sponsored behaviour).\n */\n gasFeeAmountInput?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface SwapDirectExactOutResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Echoes `params.amount` — the exact output. */\n outputAmount: bigint;\n /** Raw input amount from the V3 quoter, before slippage. */\n estimatedInputAmount: bigint;\n /** Slippage-bumped cap on input — encoded in the swap calldata. */\n maxAmountIn: bigint;\n hops: number;\n deadline: bigint;\n feeAmountUsed: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct exact-output swap** path — no AA,\n * no bundler, no PAFI sponsor-relayer. Symmetric to `swapDirect` but\n * specifies the OUTPUT amount and bumps slippage UPWARD on `maxAmountIn`.\n *\n * Caller pre-conditions:\n *\n * - User EOA already has EIP-7702 delegation (`delegateDirect` first).\n * - User EOA holds **`maxAmountIn + gasFeeAmountInput`** of\n * `inputTokenAddress` (not just `amount` — that's output).\n *\n * Flow:\n * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl.\n * 2. `findBestQuoteExactOut` → best route + required input.\n * 3. Slippage ceiling → `maxAmountIn`.\n * 4. `buildSwapUserOpExactOut` → encoded `executeBatch(calls)` calldata.\n * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.\n * 6. Wait for receipt (optional).\n *\n * @example\n * ```ts\n * import { swapDirectExactOut, fetchPafiPools } from \"@pafi-dev/trading\";\n *\n * const pools = await fetchPafiPools(8453, POINT_TOKEN);\n * const result = await swapDirectExactOut({\n * userAddress: wallet.address,\n * chainId: 8453,\n * inputTokenAddress: POINT_TOKEN,\n * outputTokenAddress: USDT,\n * amount: parseUnits(\"50\", 6), // exactly 50 USDT\n * pools,\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Swap tx:\", result.txHash);\n * ```\n */\nexport async function swapDirectExactOut(\n params: SwapDirectExactOutParams,\n): Promise<SwapDirectExactOutResult> {\n // 1. Cheap, sync input validation — runs first so a malformed call\n // fails immediately without burning an RPC quota on getCode.\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[params.chainId];\n if (!universalRouter) {\n throw new Error(\n `swapDirectExactOut: no UniversalRouter for chainId ${params.chainId}`,\n );\n }\n if (params.amount <= 0n) {\n throw new Error(\"swapDirectExactOut: amount must be positive\");\n }\n if (!isValidSlippageBps(params.slippageBps)) {\n throw new Error(\n `swapDirectExactOut: slippageBps (${params.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n );\n }\n\n // Wallet's account MUST be the user EOA — same rationale as `swapDirect`.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"swapDirectExactOut: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `swapDirectExactOut: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress}) — ` +\n `the native tx must be sent from the same EOA whose 7702-delegated bytecode is being executed`,\n );\n }\n\n // 2. Delegation precondition — same as exact-in.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `swapDirectExactOut: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handleSwapExactOut()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `swapDirectExactOut: user delegated to ${delegate} which is not a PAFI-recognised impl ` +\n `(expected ${SIMPLE_7702_IMPL_BASE_MAINNET} or ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuoteExactOut>>;\n try {\n quoteResult = await findBestQuoteExactOut(\n params.publicClient,\n params.chainId,\n params.inputTokenAddress,\n params.outputTokenAddress,\n params.amount,\n params.pools ?? [],\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new Error(\n `swapDirectExactOut: no swap path found from ${params.inputTokenAddress} to ${params.outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = params.slippageBps ?? (hops > 1 ? 100 : 50);\n const estimatedInputAmount = quoteResult.bestRoute.amountIn;\n // Ceiling division — see `handleSwapExactOut` for the rationale.\n const slippageNumerator =\n estimatedInputAmount * BigInt(10000 + slippageBps);\n const maxAmountIn = (slippageNumerator + 9999n) / 10000n;\n const gasFeeAmountInput = params.gasFeeAmountInput ?? 0n;\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 3. Build the UserOp purely to extract its callData (encoded\n // `executeBatch(calls)`). We send that as a native tx instead.\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const userOp = buildSwapUserOpExactOut({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path; nonce comes from EOA tx count\n inputTokenAddress: params.inputTokenAddress,\n outputTokenAddress: params.outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: params.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // 4. Send native tx — to: userAddress, data: encoded executeBatch.\n // (`account` validated up-front against `userAddress`.)\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: userOp.callData,\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `swapDirectExactOut: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n outputAmount: params.amount,\n estimatedInputAmount,\n maxAmountIn,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountInput,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n BROKER_HASHES,\n ORDERLY_RELAY_ABI,\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n TOKEN_HASHES,\n buildPerpDepositViaRelay,\n computeAccountId,\n detectDelegateImpl,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n BATCH_EXECUTOR_7702_IMPL,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n} from \"@pafi-dev/core\";\n\nexport interface PerpDepositDirectParams {\n /** User EOA — must be EIP-7702 delegated. */\n userAddress: Address;\n chainId: number;\n /** USDC amount to deposit (6-decimal raw units). */\n amount: bigint;\n /** Orderly broker — `'orderly' | 'woofi_pro' | 'logx'`. */\n brokerId: keyof typeof BROKER_HASHES;\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Max acceptable USDC fee charged by the Relay (slippage cap on its\n * USD-pricing of `msg.value`). Default `max(amount * 5%, 2 USDC)` —\n * matches `TradingHandlers.handlePerpDeposit`.\n */\n maxRelayFee?: bigint;\n /**\n * Operator fee in USDC (input-token, BEFORE deposit). Same semantics\n * as `swapDirect.gasFeeAmountOutput`:\n *\n * - `undefined` (default for direct path): **skip the fee transfer**\n * — PAFI is not sponsoring this deposit.\n * - explicit `bigint` — include the fee transfer.\n */\n gasFeeUsdc?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface PerpDepositDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Resolved USDC fee charged by the Relay. */\n relayTokenFee: bigint;\n /** Cap applied to the Relay fee (slippage allowance). */\n maxFee: bigint;\n /** USDC reaching Orderly Vault after Relay's fee = amount - relayTokenFee. */\n netDeposit: bigint;\n /** Operator fee actually included (0n on default direct path). */\n feeAmountUsed: bigint;\n accountId: Hex;\n brokerHash: Hex;\n usdcAddress: Address;\n relayAddress: Address;\n}\n\n/**\n * One-shot helper for the **FE-direct perp deposit** path — no AA, no\n * bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and\n * broadcasts a single type-2 transaction calling its own EIP-7702\n * delegated bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Verify EIP-7702 delegation (same precondition as `swapDirect`).\n * 2. Resolve USDC + verify broker is whitelisted on Orderly Vault.\n * 3. Quote `Relay.tokenFee` for the deposit; compute `netDeposit`.\n * 4. `buildPerpDepositViaRelay` → encoded `executeBatch(calls)`\n * (USDC.approve(relay) + Relay.deposit + optional fee transfer).\n * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.\n * 6. Wait for receipt (optional).\n *\n * Use when: same conditions as `swapDirect` — FE doesn't have Pimlico\n * key, doesn't want sponsor-relayer dependency, user has small ETH.\n *\n * Throws when the user is NOT yet delegated.\n *\n * @example\n * ```ts\n * import { perpDepositDirect } from \"@pafi-dev/trading\";\n *\n * const result = await perpDepositDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * amount: parseUnits(\"10\", 6), // 10 USDC\n * brokerId: \"orderly\",\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Deposit tx:\", result.txHash);\n * console.log(\"Net deposit to Orderly:\", result.netDeposit, \"USDC raw\");\n * ```\n */\nexport async function perpDepositDirect(\n params: PerpDepositDirectParams,\n): Promise<PerpDepositDirectResult> {\n if (params.amount <= 0n) {\n throw new Error(\"perpDepositDirect: amount must be positive\");\n }\n\n // 1. Delegation precondition.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `perpDepositDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handlePerpDeposit()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `perpDepositDirect: user delegated to ${delegate} (not a PAFI-recognised impl ` +\n `${SIMPLE_7702_IMPL_BASE_MAINNET} / ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n // 2. Resolve USDC + verify broker.\n const vault = ORDERLY_VAULT_ADDRESSES[params.chainId];\n if (!vault) {\n throw new Error(\n `perpDepositDirect: no Orderly Vault for chainId ${params.chainId}`,\n );\n }\n const brokerHash = BROKER_HASHES[params.brokerId];\n if (!brokerHash) {\n throw new Error(\n `perpDepositDirect: unknown brokerId \"${params.brokerId}\"`,\n );\n }\n const tokenHash = TOKEN_HASHES.USDC;\n\n const [usdcAddress, brokerAllowed] = await Promise.all([\n params.publicClient.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedToken\",\n args: [tokenHash],\n }) as Promise<Address>,\n params.publicClient.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedBroker\",\n args: [brokerHash],\n }) as Promise<boolean>,\n ]);\n if (!brokerAllowed) {\n throw new Error(\n `perpDepositDirect: broker \"${params.brokerId}\" is not whitelisted on Orderly Vault`,\n );\n }\n\n // 3. Quote Relay fee.\n const { orderlyRelay: relayAddress, pafiFeeRecipient } = getContractAddresses(\n params.chainId,\n );\n // Cap = max(amount * 5%, 2 USDC) — same heuristic as TradingHandlers.\n const RELAY_FEE_FLOOR_USDC = 2_000_000n;\n const percentCap = (params.amount * 500n) / 10_000n;\n const maxFee =\n params.maxRelayFee ??\n (percentCap > RELAY_FEE_FLOOR_USDC ? percentCap : RELAY_FEE_FLOOR_USDC);\n\n const relayRequest = {\n token: usdcAddress,\n receiver: params.userAddress,\n brokerHash,\n totalAmount: params.amount,\n maxFee,\n };\n\n const relayTokenFee = (await params.publicClient.readContract({\n address: relayAddress,\n abi: ORDERLY_RELAY_ABI,\n functionName: \"quoteTokenFee\",\n args: [relayRequest],\n })) as bigint;\n\n if (relayTokenFee > maxFee) {\n throw new Error(\n `perpDepositDirect: Relay tokenFee ${relayTokenFee} exceeds maxFee ${maxFee} — ` +\n `pass a larger \\`maxRelayFee\\` or increase \\`amount\\`.`,\n );\n }\n if (relayTokenFee >= params.amount) {\n throw new Error(\n `perpDepositDirect: deposit amount ${params.amount} below Relay fee ${relayTokenFee} — increase \\`amount\\`.`,\n );\n }\n\n // 4. Build calldata via core helper.\n const gasFeeUsdc = params.gasFeeUsdc ?? 0n;\n const partial = buildPerpDepositViaRelay({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path\n relayAddress,\n request: relayRequest,\n gasFeeUsdc: gasFeeUsdc > 0n ? gasFeeUsdc : undefined,\n gasFeeUsdcRecipient: gasFeeUsdc > 0n ? pafiFeeRecipient : undefined,\n });\n\n // 5. Send native tx — self-call into delegated bytecode.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"perpDepositDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 6. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `perpDepositDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n const accountId = computeAccountId(params.userAddress, brokerHash);\n\n return {\n txHash,\n receipt,\n relayTokenFee,\n maxFee,\n netDeposit: params.amount - relayTokenFee,\n feeAmountUsed: gasFeeUsdc,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n buildErc20TransferUserOp,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n BATCH_EXECUTOR_7702_IMPL,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n} from \"@pafi-dev/core\";\n\n/**\n * Direct (non-AA) gasless ERC-20 transfer — for users who already hold\n * native ETH and want to skip the paymaster/bundler round-trip. Same\n * sponsored-shape calls but submitted as a self-call to the EOA's\n * EIP-7702 delegated bytecode.\n *\n * Mirrors `perpDepositDirect`: requires 7702 delegation, builds the\n * batch via the core helper, sends via `walletClient.sendTransaction`.\n *\n * For the AA / paymaster-sponsored path (zero ETH on user wallet), use\n * `TradingHandlers.handleErc20Transfer` and submit the returned UserOp.\n */\nexport interface TransferDirectParams {\n userAddress: Address;\n chainId: number;\n tokenAddress: Address;\n recipient: Address;\n amount: bigint;\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Operator fee. Same semantics as `perpDepositDirect.gasFeeUsdc`:\n * - `undefined` (default for direct path): NO fee transfer. PAFI\n * is not sponsoring; treating as a regular wallet send.\n * - explicit `bigint`: include the fee transfer (rare for the\n * direct path, but supported for symmetry).\n */\n feeAmount?: bigint;\n\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n /** Optional non-fatal warning sink (e.g. unexpected impl on delegation). */\n onWarning?: (msg: string) => void;\n}\n\nexport interface TransferDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Echo of the fee actually included in the batch. `0n` when omitted. */\n feeAmountUsed: bigint;\n feeRecipient: Address;\n tokenAddress: Address;\n}\n\nexport async function transferDirect(\n params: TransferDirectParams,\n): Promise<TransferDirectResult> {\n if (params.amount <= 0n) {\n throw new Error(\"transferDirect: amount must be positive\");\n }\n if (\n params.recipient ===\n \"0x0000000000000000000000000000000000000000\"\n ) {\n throw new Error(\n \"transferDirect: recipient cannot be the zero address\",\n );\n }\n\n // 1. Delegation precondition (matches perpDepositDirect).\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `transferDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handleErc20Transfer()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `transferDirect: user delegated to ${delegate} (not a PAFI-recognised impl ` +\n `${SIMPLE_7702_IMPL_BASE_MAINNET} / ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const feeAmount = params.feeAmount ?? 0n;\n\n // 2. Build calldata via core helper — same shape as the sponsored\n // path, just sent natively instead of through the bundler.\n const partial = buildErc20TransferUserOp({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path\n tokenAddress: params.tokenAddress,\n recipient: params.recipient,\n amount: params.amount,\n feeAmount: feeAmount > 0n ? feeAmount : undefined,\n feeRecipient: feeAmount > 0n ? pafiFeeRecipient : undefined,\n });\n\n // 3. Send native tx — self-call into delegated bytecode.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"transferDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 4. Optional receipt wait.\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `transferDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n feeAmountUsed: feeAmount,\n feeRecipient: pafiFeeRecipient,\n tokenAddress: params.tokenAddress,\n };\n}\n","import {\n decodeEventLog,\n type Address,\n type Hex,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildMint,\n readPoolState,\n estimateLiquidityFromOneSide,\n applyMintSlippage,\n tickToSqrtPriceX96,\n tickSpacingForFee,\n nonfungiblePositionManagerAbi,\n} from \"../liquidity\";\n\nexport interface AddLiquidityDirectParams {\n /** User EOA — must be EIP-7702 delegated. */\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /** Pool token0 (must be sorted < token1). */\n token0: Address;\n /** Pool token1. */\n token1: Address;\n /** V3 fee tier (e.g. 500, 3000, 10000). */\n fee: number;\n\n /** Position range — both ticks must be multiples of the pool's tickSpacing. */\n tickLower: number;\n tickUpper: number;\n\n /** Caller pins ONE side; the other is computed by the SDK. */\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n\n /** bps, default 50. Capped at 10000. */\n slippageBps?: number;\n /** Unix seconds. Default `now + 5min`. */\n deadline?: bigint;\n\n /** Wait for receipt + parse tokenId. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface AddLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Newly-minted position NFT id. Available when `waitForReceipt !== false`. */\n tokenId?: bigint;\n /** Amount0 baked into the calldata (after estimation). */\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** L value computed off-chain from amounts + range. Informational. */\n liquidity: bigint;\n deadline: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct add-liquidity** path — no AA, no\n * bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and\n * broadcasts a single type-2 transaction calling its own EIP-7702\n * delegated bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Validate inputs (tick range, single-amount guard, slippage).\n * 2. Verify the EOA is EIP-7702 delegated.\n * 3. Read pool state (sqrtPriceX96).\n * 4. Estimate the other side's amount + liquidity from one pinned side.\n * 5. Apply slippage → (amount0Min, amount1Min).\n * 6. Build 3-op batch: approve token0, approve token1, NPM.mint.\n * 7. Send native tx.\n * 8. Wait receipt + parse `Transfer(0x0 → user, tokenId)` → return tokenId.\n *\n * @example\n * ```ts\n * const result = await addLiquidityDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * publicClient,\n * walletClient,\n * token0: PT,\n * token1: USDC,\n * fee: 3000,\n * tickLower: -60000,\n * tickUpper: -54000,\n * amount0Desired: parseUnits(\"100\", 18),\n * });\n * console.log(\"Minted position:\", result.tokenId);\n * ```\n */\nexport async function addLiquidityDirect(\n params: AddLiquidityDirectParams,\n): Promise<AddLiquidityDirectResult> {\n // 1. Sync input validation.\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `addLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(\n `addLiquidityDirect: no V3 factory for chainId ${params.chainId}`,\n );\n }\n if (params.tickLower >= params.tickUpper) {\n throw new Error(\n `addLiquidityDirect: tickLower (${params.tickLower}) must be strictly less than tickUpper (${params.tickUpper})`,\n );\n }\n const ts = tickSpacingForFee(params.fee);\n if (ts !== undefined) {\n if (params.tickLower % ts !== 0 || params.tickUpper % ts !== 0) {\n throw new Error(\n `addLiquidityDirect: ticks must be multiples of tickSpacing ${ts} for fee ${params.fee}`,\n );\n }\n }\n const has0 = params.amount0Desired !== undefined && params.amount0Desired > 0n;\n const has1 = params.amount1Desired !== undefined && params.amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"addLiquidityDirect: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `addLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"addLiquidityDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `addLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n // 2. Delegation precondition.\n const code = await params.publicClient.getCode({ address: params.userAddress });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `addLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path.`,\n );\n }\n\n // 3. Read pool state.\n const pool = computeV3PoolAddress({\n factory,\n tokenA: params.token0,\n tokenB: params.token1,\n fee: params.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n // 4. Estimate from one pinned side.\n const sqrtL = tickToSqrtPriceX96(params.tickLower);\n const sqrtU = tickToSqrtPriceX96(params.tickUpper);\n const { liquidity, amount0, amount1 } = estimateLiquidityFromOneSide({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: sqrtL,\n sqrtPriceX96Upper: sqrtU,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n });\n\n // 5. Slippage.\n const { amount0Min, amount1Min } = applyMintSlippage({\n amount0Desired: amount0,\n amount1Desired: amount1,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 6. Build batch.\n const operations = buildMint({\n npm,\n token0: params.token0,\n token1: params.token1,\n fee: params.fee,\n tickLower: params.tickLower,\n tickUpper: params.tickUpper,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n recipient: params.userAddress,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n // 7. Send native tx.\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 8. Optional receipt + tokenId parse.\n let receipt: TransactionReceipt | undefined;\n let tokenId: bigint | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n tokenId = parseMintedTokenId(receipt, npm, params.userAddress);\n } catch (err) {\n params.onWarning?.(\n `addLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n tokenId,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n liquidity,\n deadline,\n };\n}\n\n/**\n * Find the `Transfer(from=0x0, to=userAddress, tokenId)` log in a mint\n * receipt and return the tokenId.\n *\n * The NPM emits a standard ERC-721 `Transfer` event for every mint; the\n * `from` field is the zero address for newly-minted tokens. We scan the\n * receipt logs for the matching event from the NPM contract address.\n */\nfunction parseMintedTokenId(\n receipt: TransactionReceipt,\n npm: Address,\n user: Address,\n): bigint | undefined {\n const userLower = user.toLowerCase();\n const zero = \"0x0000000000000000000000000000000000000000\";\n for (const log of receipt.logs) {\n if (log.address.toLowerCase() !== npm.toLowerCase()) continue;\n try {\n const decoded = decodeEventLog({\n abi: nonfungiblePositionManagerAbi,\n data: log.data,\n topics: log.topics,\n });\n if (decoded.eventName !== \"Transfer\") continue;\n const args = decoded.args as { from: Address; to: Address; tokenId: bigint };\n if (\n args.from.toLowerCase() === zero &&\n args.to.toLowerCase() === userLower\n ) {\n return args.tokenId;\n }\n } catch {\n // Not a Transfer log we can decode — skip.\n }\n }\n return undefined;\n}\n","/**\n * Uniswap V3 NonfungiblePositionManager (NPM) ABI — subset used by the\n * `@pafi-dev/trading` liquidity flows. PAFI deployment lives at\n * `V3_NPM_ADDRESSES[chainId]`.\n *\n * Hand-authored (not generated) — same convention as `v3QuoterV2Abi` in\n * `@pafi-dev/core`. Only the methods + events the SDK actually uses are\n * declared, to keep the surface small and the type narrowing precise.\n *\n * Intentionally omitted: `multicall`, `WETH9`, `refundETH`, `sweepToken`,\n * `unwrapWETH9` (ETH wrap helpers — out of v1 scope), `tokenURI`, `name`,\n * `symbol`, `tokenOfOwnerByIndex` (ERC-721 metadata + enumerable — position\n * listing is the consumer backend's job), `permit`, `safeTransferFrom`.\n */\nexport const nonfungiblePositionManagerAbi = [\n // ─── Write methods ───────────────────────────────────────────────────────\n\n {\n type: \"function\",\n name: \"mint\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\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: \"amount0Desired\", type: \"uint256\" },\n { name: \"amount1Desired\", type: \"uint256\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"recipient\", type: \"address\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"increaseLiquidity\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"amount0Desired\", type: \"uint256\" },\n { name: \"amount1Desired\", type: \"uint256\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"decreaseLiquidity\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"collect\",\n stateMutability: \"payable\",\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 },\n\n {\n type: \"function\",\n name: \"burn\",\n stateMutability: \"payable\",\n inputs: [{ name: \"tokenId\", type: \"uint256\" }],\n outputs: [],\n },\n\n // ─── Read methods ────────────────────────────────────────────────────────\n\n // Returns the legacy V3 12-tuple. `readPosition` wraps this into a struct.\n {\n type: \"function\",\n name: \"positions\",\n stateMutability: \"view\",\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 },\n\n // Used by the ABI smoke test to verify NPM is wired to the expected\n // PafiV3Factory.\n {\n type: \"function\",\n name: \"factory\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n\n // ─── Events (for receipt parsing) ────────────────────────────────────────\n\n // Emitted from address(0) on mint; addLiquidityDirect parses this to\n // extract the newly-minted tokenId.\n {\n type: \"event\",\n name: \"Transfer\",\n inputs: [\n { name: \"from\", type: \"address\", indexed: true },\n { name: \"to\", type: \"address\", indexed: true },\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n ],\n },\n\n {\n type: \"event\",\n name: \"IncreaseLiquidity\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"liquidity\", type: \"uint128\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n\n {\n type: \"event\",\n name: \"DecreaseLiquidity\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"liquidity\", type: \"uint128\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n\n {\n type: \"event\",\n name: \"Collect\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"recipient\", type: \"address\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n] as const;\n","/**\n * Uniswap V3 Pool ABI — read-only subset used by the\n * `@pafi-dev/trading` liquidity flows to estimate amounts off-chain.\n *\n * Pool addresses are derived from `V3_FACTORY_ADDRESSES` +\n * `V3_POOL_INIT_CODE_HASH` (both in `@pafi-dev/core`) via\n * `computeV3PoolAddress()`.\n *\n * Intentionally omitted: pool-direct write methods (`swap`, `flash`,\n * `mint`, `burn`, `collect`) — every write call goes through NPM, never\n * the pool. Also omitted: `positions(bytes32)` (NPM-side is the canonical\n * read), `protocolFees`, `observe`, `snapshotCumulativesInside`.\n */\nexport const v3PoolAbi = [\n // Pool's underlying tokens. Read on-chain to verify the\n // `computeV3PoolAddress(factory, token0, token1, fee)` derivation matches\n // an already-deployed pool — and useful generally for consumers that\n // discovered a pool by address (e.g. from a Transfer log) and need the\n // tokens.\n {\n type: \"function\",\n name: \"token0\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n {\n type: \"function\",\n name: \"token1\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n\n // (sqrtPriceX96, tick, observationIndex, observationCardinality,\n // observationCardinalityNext, feeProtocol, unlocked)\n {\n type: \"function\",\n name: \"slot0\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n { name: \"sqrtPriceX96\", type: \"uint160\" },\n { name: \"tick\", type: \"int24\" },\n { name: \"observationIndex\", type: \"uint16\" },\n { name: \"observationCardinality\", type: \"uint16\" },\n { name: \"observationCardinalityNext\", type: \"uint16\" },\n { name: \"feeProtocol\", type: \"uint8\" },\n { name: \"unlocked\", type: \"bool\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"liquidity\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint128\" }],\n },\n\n {\n type: \"function\",\n name: \"tickSpacing\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"int24\" }],\n },\n\n {\n type: \"function\",\n name: \"fee\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint24\" }],\n },\n\n // (Token-0 / token-1 cumulative fee growth per unit of liquidity, in\n // Q128.128.) Used with `ticks(...)` to derive the pending-fee estimate\n // for collectFeesDirect.\n {\n type: \"function\",\n name: \"feeGrowthGlobal0X128\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n\n {\n type: \"function\",\n name: \"feeGrowthGlobal1X128\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n\n // Per-tick state. The SDK reads `ticks(tickLower)` + `ticks(tickUpper)`\n // for a position to compute its `feeGrowthInside0/1` in the canonical\n // V3 formula (current global - outside lower - outside upper, branched\n // on whether `slot0.tick` is below / inside / above the range).\n {\n type: \"function\",\n name: \"ticks\",\n stateMutability: \"view\",\n inputs: [{ name: \"tick\", type: \"int24\" }],\n outputs: [\n { name: \"liquidityGross\", type: \"uint128\" },\n { name: \"liquidityNet\", type: \"int128\" },\n { name: \"feeGrowthOutside0X128\", type: \"uint256\" },\n { name: \"feeGrowthOutside1X128\", type: \"uint256\" },\n { name: \"tickCumulativeOutside\", type: \"int56\" },\n { name: \"secondsPerLiquidityOutsideX128\", type: \"uint160\" },\n { name: \"secondsOutside\", type: \"uint56\" },\n { name: \"initialized\", type: \"bool\" },\n ],\n },\n\n // Per-word initialized-tick bitset. Each uint256 word covers 256\n // compressed tick positions (compressed = tick / tickSpacing). The\n // off-chain liquidity-curve scanner reads every word in\n // `[wordOf(minUsableTick), wordOf(maxUsableTick)]` then decodes set\n // bits into absolute tick indices via `(wordPos * 256 + bit) * spacing`.\n // See `fetchAllInitializedTicks.ts`.\n {\n type: \"function\",\n name: \"tickBitmap\",\n stateMutability: \"view\",\n inputs: [{ name: \"wordPosition\", type: \"int16\" }],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n] as const;\n","import type { Address } from \"viem\";\n\n/**\n * PAFI's V3 NonfungiblePositionManager (NPM) per chain. All LP flows\n * encode calls against this address.\n *\n * Source of truth: `contracts.md` at the repo root.\n */\nexport const V3_NPM_ADDRESSES: Record<number, Address> = {\n // Base mainnet — PAFI's V3 NPM deployment.\n 8453: \"0xD7db6931B5EbeaE033605db0781DE6C91F05CCdf\",\n};\n\n/**\n * uint128 ceiling. Used as `amount0Max` / `amount1Max` on\n * `NPM.collect(...)` to mean \"transfer everything owed.\"\n */\nexport const UINT128_MAX: bigint = (1n << 128n) - 1n;\n","/**\n * Uniswap V3 liquidity math — hand-rolled bigint primitives.\n *\n * Mirrors the algorithms in `@uniswap/v3-sdk` (TickMath, SqrtPriceMath,\n * LiquidityAmounts) without taking the package as a runtime dependency.\n * Unit tests cross-check golden values against the upstream SDK; the\n * runtime trades a ~200 LoC implementation for zero new dependencies.\n *\n * All functions are pure and side-effect-free.\n */\n\n// ─── Constants ──────────────────────────────────────────────────────────────\n\n/** Minimum tick allowed by the V3 tick range. */\nexport const MIN_TICK = -887272;\n\n/** Maximum tick allowed by the V3 tick range. */\nexport const MAX_TICK = 887272;\n\n/** sqrtPriceX96 at MIN_TICK. */\nexport const MIN_SQRT_RATIO: bigint = 4295128739n;\n\n/** sqrtPriceX96 at MAX_TICK. */\nexport const MAX_SQRT_RATIO: bigint =\n 1461446703485210103287273052203988822378723970342n;\n\n/** 2^96 — the X96 scaling factor. */\nexport const Q96: bigint = 1n << 96n;\n\n/** 2^192 — used in sqrt² → ratio conversions. */\nexport const Q192: bigint = 1n << 192n;\n\n// ─── Internal helpers (not exported) ────────────────────────────────────────\n\nfunction mulShift(val: bigint, mulBy: bigint): bigint {\n return (val * mulBy) >> 128n;\n}\n\nfunction mulDivFloor(a: bigint, b: bigint, denominator: bigint): bigint {\n return (a * b) / denominator;\n}\n\nfunction mulDivCeil(a: bigint, b: bigint, denominator: bigint): bigint {\n const product = a * b;\n return product % denominator === 0n\n ? product / denominator\n : product / denominator + 1n;\n}\n\n// ─── Tick ↔ sqrtPriceX96 ────────────────────────────────────────────────────\n\n/**\n * Convert a tick to its sqrtPriceX96, using V3's exact lookup-table\n * algorithm. Equivalent to `TickMath.getSqrtRatioAtTick(tick)`.\n *\n * @throws if `tick` is outside `[MIN_TICK, MAX_TICK]`\n */\nexport function tickToSqrtPriceX96(tick: number): bigint {\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToSqrtPriceX96: tick must be an integer, got ${tick}`);\n }\n if (tick < MIN_TICK || tick > MAX_TICK) {\n throw new Error(\n `tickToSqrtPriceX96: tick ${tick} out of range [${MIN_TICK}, ${MAX_TICK}]`,\n );\n }\n\n const absTick = BigInt(tick < 0 ? -tick : tick);\n\n let ratio: bigint =\n (absTick & 0x1n) !== 0n\n ? 0xfffcb933bd6fad37aa2d162d1a594001n\n : 0x100000000000000000000000000000000n;\n\n if ((absTick & 0x2n) !== 0n)\n ratio = mulShift(ratio, 0xfff97272373d413259a46990580e213an);\n if ((absTick & 0x4n) !== 0n)\n ratio = mulShift(ratio, 0xfff2e50f5f656932ef12357cf3c7fdccn);\n if ((absTick & 0x8n) !== 0n)\n ratio = mulShift(ratio, 0xffe5caca7e10e4e61c3624eaa0941cd0n);\n if ((absTick & 0x10n) !== 0n)\n ratio = mulShift(ratio, 0xffcb9843d60f6159c9db58835c926644n);\n if ((absTick & 0x20n) !== 0n)\n ratio = mulShift(ratio, 0xff973b41fa98c081472e6896dfb254c0n);\n if ((absTick & 0x40n) !== 0n)\n ratio = mulShift(ratio, 0xff2ea16466c96a3843ec78b326b52861n);\n if ((absTick & 0x80n) !== 0n)\n ratio = mulShift(ratio, 0xfe5dee046a99a2a811c461f1969c3053n);\n if ((absTick & 0x100n) !== 0n)\n ratio = mulShift(ratio, 0xfcbe86c7900a88aedcffc83b479aa3a4n);\n if ((absTick & 0x200n) !== 0n)\n ratio = mulShift(ratio, 0xf987a7253ac413176f2b074cf7815e54n);\n if ((absTick & 0x400n) !== 0n)\n ratio = mulShift(ratio, 0xf3392b0822b70005940c7a398e4b70f3n);\n if ((absTick & 0x800n) !== 0n)\n ratio = mulShift(ratio, 0xe7159475a2c29b7443b29c7fa6e889d9n);\n if ((absTick & 0x1000n) !== 0n)\n ratio = mulShift(ratio, 0xd097f3bdfd2022b8845ad8f792aa5825n);\n if ((absTick & 0x2000n) !== 0n)\n ratio = mulShift(ratio, 0xa9f746462d870fdf8a65dc1f90e061e5n);\n if ((absTick & 0x4000n) !== 0n)\n ratio = mulShift(ratio, 0x70d869a156d2a1b890bb3df62baf32f7n);\n if ((absTick & 0x8000n) !== 0n)\n ratio = mulShift(ratio, 0x31be135f97d08fd981231505542fcfa6n);\n if ((absTick & 0x10000n) !== 0n)\n ratio = mulShift(ratio, 0x9aa508b5b7a84e1c677de54f3e99bc9n);\n if ((absTick & 0x20000n) !== 0n)\n ratio = mulShift(ratio, 0x5d6af8dedb81196699c329225ee604n);\n if ((absTick & 0x40000n) !== 0n)\n ratio = mulShift(ratio, 0x2216e584f5fa1ea926041bedfe98n);\n if ((absTick & 0x80000n) !== 0n)\n ratio = mulShift(ratio, 0x48a170391f7dc42444e8fa2n);\n\n if (tick > 0) {\n const max256 = (1n << 256n) - 1n;\n ratio = max256 / ratio;\n }\n\n // Shift from Q128.128 → Q64.96 with ceiling rounding (matches the\n // reference Solidity behavior).\n return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n);\n}\n\n/**\n * Convert a sqrtPriceX96 back to the largest tick whose\n * `tickToSqrtPriceX96(tick)` is <= the input. Inverse of\n * `tickToSqrtPriceX96`, equivalent to\n * `TickMath.getTickAtSqrtRatio(sqrtPriceX96)`.\n *\n * Uses a most-significant-bit (MSB) search + iterative refinement.\n *\n * @throws if `sqrtPriceX96` is outside `[MIN_SQRT_RATIO, MAX_SQRT_RATIO)`\n */\nexport function sqrtPriceX96ToTick(sqrtPriceX96: bigint): number {\n if (sqrtPriceX96 < MIN_SQRT_RATIO || sqrtPriceX96 >= MAX_SQRT_RATIO) {\n throw new Error(\n `sqrtPriceX96ToTick: sqrtPriceX96 ${sqrtPriceX96} out of range ` +\n `[${MIN_SQRT_RATIO}, ${MAX_SQRT_RATIO})`,\n );\n }\n\n const ratio = sqrtPriceX96 << 32n;\n\n // Find the most significant bit (MSB) of `ratio`.\n let r = ratio;\n let msb = 0n;\n for (const [shift, value] of [\n [128n, 0xffffffffffffffffffffffffffffffffn],\n [64n, 0xffffffffffffffffn],\n [32n, 0xffffffffn],\n [16n, 0xffffn],\n [8n, 0xffn],\n [4n, 0xfn],\n [2n, 0x3n],\n [1n, 0x1n],\n ] as const) {\n const f = r > value ? shift : 0n;\n msb |= f;\n r >>= f;\n }\n\n // Normalize to Q128.128 fixed point.\n r = msb >= 128n ? ratio >> (msb - 127n) : ratio << (127n - msb);\n\n let log2: bigint = (msb - 128n) << 64n;\n\n for (let i = 0; i < 14; i++) {\n r = (r * r) >> 127n;\n const f = r >> 128n;\n log2 |= f << BigInt(63 - i);\n r >>= f;\n }\n\n const logSqrt10001 = log2 * 255738958999603826347141n;\n\n const tickLow = Number(\n (logSqrt10001 - 3402992956809132418596140100660247210n) >> 128n,\n );\n const tickHigh = Number(\n (logSqrt10001 + 291339464771989622907027621153398088495n) >> 128n,\n );\n\n if (tickLow === tickHigh) return tickLow;\n return tickToSqrtPriceX96(tickHigh) <= sqrtPriceX96 ? tickHigh : tickLow;\n}\n\n// ─── Tick spacing helpers ───────────────────────────────────────────────────\n\n/**\n * Snap a tick to the nearest multiple of `tickSpacing` (rounds toward\n * zero). Use to convert a user-entered tick to one the pool will accept.\n */\nexport function nearestUsableTick(tick: number, tickSpacing: number): number {\n if (!Number.isInteger(tick) || !Number.isInteger(tickSpacing)) {\n throw new Error(\"nearestUsableTick: both arguments must be integers\");\n }\n if (tickSpacing <= 0) {\n throw new Error(\n `nearestUsableTick: tickSpacing must be positive, got ${tickSpacing}`,\n );\n }\n const rounded = Math.round(tick / tickSpacing) * tickSpacing;\n if (rounded < MIN_TICK) return rounded + tickSpacing;\n if (rounded > MAX_TICK) return rounded - tickSpacing;\n return rounded;\n}\n\n/** Minimum tick aligned to `tickSpacing`, clipped to `MIN_TICK`. */\nexport function minUsableTick(tickSpacing: number): number {\n return Math.ceil(MIN_TICK / tickSpacing) * tickSpacing;\n}\n\n/** Maximum tick aligned to `tickSpacing`, clipped to `MAX_TICK`. */\nexport function maxUsableTick(tickSpacing: number): number {\n return Math.floor(MAX_TICK / tickSpacing) * tickSpacing;\n}\n\n/**\n * Standard fee-tier → tickSpacing mapping. Matches Uniswap V3 mainnet\n * conventions and is verified on-chain for PAFI's V3-fork deployment.\n * Returns `undefined` for non-standard fees; the caller should then read\n * `factory.feeAmountTickSpacing(fee)` to be safe.\n */\nexport function tickSpacingForFee(fee: number): number | undefined {\n switch (fee) {\n case 100:\n return 1;\n case 500:\n return 10;\n case 3000:\n return 60;\n case 10000:\n return 200;\n default:\n return undefined;\n }\n}\n\n// ─── Price ↔ tick (decimals-aware) ─────────────────────────────────────────\n\n/**\n * Convert a human-readable price (`token1` per `token0`) to a tick.\n * Decimals are factored in so callers can pass real-world quantities.\n *\n * Returned tick may need `nearestUsableTick()` to be pool-valid.\n */\nexport function priceToTick(params: {\n price: number;\n token0Decimals: number;\n token1Decimals: number;\n}): number {\n const { price, token0Decimals, token1Decimals } = params;\n if (price <= 0 || !Number.isFinite(price)) {\n throw new Error(`priceToTick: price must be a positive finite number, got ${price}`);\n }\n // Raw-amount price = human_price * 10^(decimals1 - decimals0).\n const rawPrice = price * 10 ** (token1Decimals - token0Decimals);\n // tick = log_{1.0001}(price) = ln(price) / ln(1.0001)\n return Math.floor(Math.log(rawPrice) / Math.log(1.0001));\n}\n\n/**\n * Convert a tick back to a human-readable price (`token1` per `token0`).\n * Inverse of `priceToTick`.\n */\nexport function tickToPrice(params: {\n tick: number;\n token0Decimals: number;\n token1Decimals: number;\n}): number {\n const { tick, token0Decimals, token1Decimals } = params;\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToPrice: tick must be an integer, got ${tick}`);\n }\n const rawPrice = Math.pow(1.0001, tick);\n return rawPrice / 10 ** (token1Decimals - token0Decimals);\n}\n\n// ─── Amount ↔ liquidity ─────────────────────────────────────────────────────\n\n/**\n * Token0 amount required to provide `liquidity` over [sqrtL, sqrtU].\n * Matches `SqrtPriceMath.getAmount0Delta(..., roundUp=true)` from V3.\n */\nexport function getAmount0ForLiquidity(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n liquidity: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (liquidity <= 0n) return 0n;\n const numerator = liquidity << 96n;\n const diff = sqrtPriceX96Upper - sqrtPriceX96Lower;\n return mulDivCeil(numerator * diff, 1n, sqrtPriceX96Upper * sqrtPriceX96Lower);\n}\n\n/**\n * Token1 amount required to provide `liquidity` over [sqrtL, sqrtU].\n * Matches `SqrtPriceMath.getAmount1Delta(..., roundUp=true)` from V3.\n */\nexport function getAmount1ForLiquidity(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n liquidity: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (liquidity <= 0n) return 0n;\n return mulDivCeil(liquidity, sqrtPriceX96Upper - sqrtPriceX96Lower, Q96);\n}\n\n/**\n * Canonical \"given liquidity + range + current price, compute amounts\"\n * helper. Handles the three V3 cases (current below, in, or above range).\n */\nexport function getAmountsForLiquidity(params: {\n sqrtPriceX96Current: bigint;\n sqrtPriceX96Lower: bigint;\n sqrtPriceX96Upper: bigint;\n liquidity: bigint;\n}): { amount0: bigint; amount1: bigint } {\n let { sqrtPriceX96Lower, sqrtPriceX96Upper } = params;\n const { sqrtPriceX96Current, liquidity } = params;\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n\n if (sqrtPriceX96Current <= sqrtPriceX96Lower) {\n // Current price below range — position is all token0.\n return {\n amount0: getAmount0ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n ),\n amount1: 0n,\n };\n } else if (sqrtPriceX96Current < sqrtPriceX96Upper) {\n // Current price in range — position straddles both sides.\n return {\n amount0: getAmount0ForLiquidity(\n sqrtPriceX96Current,\n sqrtPriceX96Upper,\n liquidity,\n ),\n amount1: getAmount1ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Current,\n liquidity,\n ),\n };\n } else {\n // Current price above range — position is all token1.\n return {\n amount0: 0n,\n amount1: getAmount1ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n ),\n };\n }\n}\n\n/**\n * Liquidity that `amount0` of token0 would buy over [sqrtL, sqrtU].\n * Used when the user pins `amount0Desired` and the range is at-or-below\n * current price.\n */\nexport function getLiquidityForAmount0(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n amount0: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (amount0 <= 0n) return 0n;\n const intermediate = mulDivFloor(sqrtPriceX96Lower, sqrtPriceX96Upper, Q96);\n return mulDivFloor(amount0, intermediate, sqrtPriceX96Upper - sqrtPriceX96Lower);\n}\n\n/**\n * Liquidity that `amount1` of token1 would buy over [sqrtL, sqrtU].\n * Used when the user pins `amount1Desired` and the range is at-or-above\n * current price.\n */\nexport function getLiquidityForAmount1(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n amount1: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (amount1 <= 0n) return 0n;\n return mulDivFloor(amount1, Q96, sqrtPriceX96Upper - sqrtPriceX96Lower);\n}\n\n/**\n * High-level estimator. Caller has current spot + range + ONE side's\n * amount; returns the liquidity and the matching amounts.\n *\n * Branches:\n * - Current spot below range → amount0 drives, amount1 = 0.\n * - Current spot above range → amount1 drives, amount0 = 0.\n * - Current spot in range → caller's pinned side drives liquidity;\n * the other side is recomputed from that\n * liquidity at the current price.\n *\n * @throws if neither or both of amount0Desired / amount1Desired are set,\n * or if the pinned side is incompatible with the position\n * (e.g. amount1 pinned but spot < range).\n */\nexport function estimateLiquidityFromOneSide(params: {\n sqrtPriceX96Current: bigint;\n sqrtPriceX96Lower: bigint;\n sqrtPriceX96Upper: bigint;\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n}): { liquidity: bigint; amount0: bigint; amount1: bigint } {\n let { sqrtPriceX96Lower, sqrtPriceX96Upper } = params;\n const {\n sqrtPriceX96Current,\n amount0Desired,\n amount1Desired,\n } = params;\n\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n\n const has0 = amount0Desired !== undefined && amount0Desired > 0n;\n const has1 = amount1Desired !== undefined && amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"estimateLiquidityFromOneSide: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n\n if (sqrtPriceX96Current <= sqrtPriceX96Lower) {\n // Current price below range — token0-only position.\n if (!has0) {\n throw new Error(\n \"estimateLiquidityFromOneSide: spot is below range; pin amount0Desired (token1 isn't required)\",\n );\n }\n const liquidity = getLiquidityForAmount0(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n amount0Desired!,\n );\n return { liquidity, amount0: amount0Desired!, amount1: 0n };\n }\n\n if (sqrtPriceX96Current >= sqrtPriceX96Upper) {\n // Current price above range — token1-only position.\n if (!has1) {\n throw new Error(\n \"estimateLiquidityFromOneSide: spot is above range; pin amount1Desired (token0 isn't required)\",\n );\n }\n const liquidity = getLiquidityForAmount1(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n amount1Desired!,\n );\n return { liquidity, amount0: 0n, amount1: amount1Desired! };\n }\n\n // Current price in range — both sides active. Pinned side drives L.\n let liquidity: bigint;\n if (has0) {\n liquidity = getLiquidityForAmount0(\n sqrtPriceX96Current,\n sqrtPriceX96Upper,\n amount0Desired!,\n );\n } else {\n liquidity = getLiquidityForAmount1(\n sqrtPriceX96Lower,\n sqrtPriceX96Current,\n amount1Desired!,\n );\n }\n const amounts = getAmountsForLiquidity({\n sqrtPriceX96Current,\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n });\n return {\n liquidity,\n amount0: has0 ? amount0Desired! : amounts.amount0,\n amount1: has1 ? amount1Desired! : amounts.amount1,\n };\n}\n\n// ─── Slippage helpers ───────────────────────────────────────────────────────\n\n/**\n * Apply slippage to `(amount0Desired, amount1Desired)` for an add or\n * increase, returning the `(amount0Min, amount1Min)` tuple to send to\n * NPM. Floor div — the on-chain minimum must round DOWN for safety.\n */\nexport function applyMintSlippage(params: {\n amount0Desired: bigint;\n amount1Desired: bigint;\n slippageBps: number;\n}): { amount0Min: bigint; amount1Min: bigint } {\n const { amount0Desired, amount1Desired, slippageBps } = params;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `applyMintSlippage: slippageBps must be integer in [0, 10000], got ${slippageBps}`,\n );\n }\n const num = BigInt(10000 - slippageBps);\n return {\n amount0Min: (amount0Desired * num) / 10000n,\n amount1Min: (amount1Desired * num) / 10000n,\n };\n}\n\n/**\n * Apply slippage to expected `(amount0, amount1)` for a decrease/close,\n * returning `(amount0Min, amount1Min)` to send to NPM. Floor div, same\n * rationale as `applyMintSlippage`.\n */\nexport function applyRemoveSlippage(params: {\n amount0Expected: bigint;\n amount1Expected: bigint;\n slippageBps: number;\n}): { amount0Min: bigint; amount1Min: bigint } {\n const { amount0Expected, amount1Expected, slippageBps } = params;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `applyRemoveSlippage: slippageBps must be integer in [0, 10000], got ${slippageBps}`,\n );\n }\n const num = BigInt(10000 - slippageBps);\n return {\n amount0Min: (amount0Expected * num) / 10000n,\n amount1Min: (amount1Expected * num) / 10000n,\n };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\n/**\n * Decoded `NPM.positions(tokenId)` row.\n *\n * Fields mirror the 12-tuple returned by the contract, named for\n * readability. `feeGrowthInside*LastX128` are Q128.128 fixed-point —\n * used together with `pool.feeGrowthGlobal*X128()` and `pool.ticks(...)`\n * to derive pending fees in `collectFeesDirect`.\n */\nexport interface PositionInfo {\n nonce: bigint;\n operator: Address;\n token0: Address;\n token1: Address;\n fee: number;\n tickLower: number;\n tickUpper: number;\n liquidity: bigint;\n feeGrowthInside0LastX128: bigint;\n feeGrowthInside1LastX128: bigint;\n tokensOwed0: bigint;\n tokensOwed1: bigint;\n}\n\n/**\n * Read an NFT position's state by tokenId.\n *\n * @param client viem PublicClient\n * @param npm NonfungiblePositionManager address (`V3_NPM_ADDRESSES[chainId]`)\n * @param tokenId The NFT id\n */\nexport async function readPosition(\n client: PublicClient,\n npm: Address,\n tokenId: bigint,\n): Promise<PositionInfo> {\n const result = (await client.readContract({\n address: npm,\n abi: nonfungiblePositionManagerAbi,\n functionName: \"positions\",\n args: [tokenId],\n })) as readonly [\n bigint, // nonce\n Address, // operator\n Address, // token0\n Address, // token1\n number, // fee\n number, // tickLower\n number, // tickUpper\n bigint, // liquidity\n bigint, // feeGrowthInside0LastX128\n bigint, // feeGrowthInside1LastX128\n bigint, // tokensOwed0\n bigint, // tokensOwed1\n ];\n\n return {\n nonce: result[0],\n operator: result[1],\n token0: result[2],\n token1: result[3],\n fee: result[4],\n tickLower: result[5],\n tickUpper: result[6],\n liquidity: result[7],\n feeGrowthInside0LastX128: result[8],\n feeGrowthInside1LastX128: result[9],\n tokensOwed0: result[10],\n tokensOwed1: result[11],\n };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { v3PoolAbi } from \"./abi\";\n\n/**\n * Distilled V3 pool state — the fields LP flows need to estimate amounts\n * and validate ticks.\n */\nexport interface PoolState {\n sqrtPriceX96: bigint;\n /** Current tick (`int24` from slot0). */\n tick: number;\n /** In-range liquidity at the current tick. */\n liquidity: bigint;\n tickSpacing: number;\n /** Fee tier in hundredths of a basis point (e.g. `3000` = 0.3%). */\n fee: number;\n}\n\n/**\n * Per-tick state read from `pool.ticks(tick)`. Only the fields LP flows\n * use are kept; the rest of the tuple is dropped.\n */\nexport interface TickInfo {\n liquidityGross: bigint;\n liquidityNet: bigint;\n feeGrowthOutside0X128: bigint;\n feeGrowthOutside1X128: bigint;\n initialized: boolean;\n}\n\n/**\n * Pool fee-growth globals — used together with `TickInfo` and the\n * position's `feeGrowthInside*LastX128` to compute pending fees.\n */\nexport interface PoolFeeGrowthGlobals {\n feeGrowthGlobal0X128: bigint;\n feeGrowthGlobal1X128: bigint;\n}\n\n/**\n * Read a pool's current state in a single multicall.\n *\n * @param client viem PublicClient\n * @param pool Pool address (use `computeV3PoolAddress` to derive)\n */\nexport async function readPoolState(\n client: PublicClient,\n pool: Address,\n /** Pin reads to this block. Default: latest (matches prior behavior). */\n blockNumber?: bigint,\n): Promise<PoolState> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"slot0\" },\n { address: pool, abi: v3PoolAbi, functionName: \"liquidity\" },\n { address: pool, abi: v3PoolAbi, functionName: \"tickSpacing\" },\n { address: pool, abi: v3PoolAbi, functionName: \"fee\" },\n ],\n allowFailure: false,\n blockNumber,\n });\n\n const slot0 = results[0] as readonly [\n bigint, // sqrtPriceX96\n number, // tick\n number,\n number,\n number,\n number,\n boolean,\n ];\n\n return {\n sqrtPriceX96: slot0[0],\n tick: slot0[1],\n liquidity: results[1] as bigint,\n tickSpacing: results[2] as number,\n fee: results[3] as number,\n };\n}\n\n/**\n * Read tick info for `tickLower` and `tickUpper` in a single multicall.\n *\n * Used by `collectFeesDirect` to compute `feeGrowthInside*` (and from\n * that, the pending-fee estimate).\n */\nexport async function readTicksAt(\n client: PublicClient,\n pool: Address,\n tickLower: number,\n tickUpper: number,\n): Promise<{ lower: TickInfo; upper: TickInfo }> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"ticks\", args: [tickLower] },\n { address: pool, abi: v3PoolAbi, functionName: \"ticks\", args: [tickUpper] },\n ],\n allowFailure: false,\n });\n\n const toTickInfo = (r: unknown): TickInfo => {\n const tuple = r as readonly [\n bigint, // liquidityGross\n bigint, // liquidityNet\n bigint, // feeGrowthOutside0X128\n bigint, // feeGrowthOutside1X128\n bigint, // tickCumulativeOutside\n bigint, // secondsPerLiquidityOutsideX128\n bigint, // secondsOutside\n boolean,\n ];\n return {\n liquidityGross: tuple[0],\n liquidityNet: tuple[1],\n feeGrowthOutside0X128: tuple[2],\n feeGrowthOutside1X128: tuple[3],\n initialized: tuple[7],\n };\n };\n\n return {\n lower: toTickInfo(results[0]),\n upper: toTickInfo(results[1]),\n };\n}\n\n/**\n * Read pool fee-growth globals.\n *\n * Could be folded into `readPoolState` but kept separate so that flows\n * which don't need fee tracking (mint, decrease) don't waste an RPC on\n * the extra two reads.\n */\nexport async function readFeeGrowthGlobals(\n client: PublicClient,\n pool: Address,\n): Promise<PoolFeeGrowthGlobals> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"feeGrowthGlobal0X128\" },\n { address: pool, abi: v3PoolAbi, functionName: \"feeGrowthGlobal1X128\" },\n ],\n allowFailure: false,\n });\n\n return {\n feeGrowthGlobal0X128: results[0] as bigint,\n feeGrowthGlobal1X128: results[1] as bigint,\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { erc20ApproveOp } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildMintParams {\n /** NonfungiblePositionManager address (`V3_NPM_ADDRESSES[chainId]`). */\n npm: Address;\n token0: Address;\n token1: Address;\n fee: number;\n tickLower: number;\n tickUpper: number;\n /** Exact amount0 caller is approving + sending. */\n amount0Desired: bigint;\n /** Exact amount1 caller is approving + sending. */\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** Position NFT recipient — typically the user's EOA. */\n recipient: Address;\n /** Unix seconds. NPM reverts if `block.timestamp > deadline`. */\n deadline: bigint;\n}\n\n/**\n * Build the 3-op batch for `addLiquidityDirect`:\n *\n * 1. token0.approve(NPM, amount0Desired)\n * 2. token1.approve(NPM, amount1Desired)\n * 3. NPM.mint({ ... })\n *\n * Approvals are per-call exact (not `max`) — leaves zero residual\n * allowance after the batch, preventing a stale approve from being\n * front-run on a later mint.\n *\n * Caller is responsible for ordering `token0 < token1` (V3 invariant);\n * this builder doesn't sort, since the desired/min amounts are\n * positional and re-sorting would break them.\n */\nexport function buildMint(params: BuildMintParams): Operation[] {\n return [\n erc20ApproveOp(params.token0, params.npm, params.amount0Desired),\n erc20ApproveOp(params.token1, params.npm, params.amount1Desired),\n {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"mint\",\n args: [\n {\n token0: params.token0,\n token1: params.token1,\n fee: params.fee,\n tickLower: params.tickLower,\n tickUpper: params.tickUpper,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n recipient: params.recipient,\n deadline: params.deadline,\n },\n ],\n }),\n },\n ];\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { erc20ApproveOp } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildIncreaseLiquidityParams {\n npm: Address;\n token0: Address;\n token1: Address;\n tokenId: bigint;\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Build the 3-op batch for `increaseLiquidityDirect`:\n *\n * 1. token0.approve(NPM, amount0Desired)\n * 2. token1.approve(NPM, amount1Desired)\n * 3. NPM.increaseLiquidity({ tokenId, ... })\n *\n * Range comes from the existing position — caller resolves it via\n * `readPosition(tokenId)` before calling this builder.\n */\nexport function buildIncreaseLiquidity(\n params: BuildIncreaseLiquidityParams,\n): Operation[] {\n return [\n erc20ApproveOp(params.token0, params.npm, params.amount0Desired),\n erc20ApproveOp(params.token1, params.npm, params.amount1Desired),\n {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"increaseLiquidity\",\n args: [\n {\n tokenId: params.tokenId,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n },\n ],\n }),\n },\n ];\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildDecreaseLiquidityParams {\n npm: Address;\n tokenId: bigint;\n liquidity: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Build a single `NPM.decreaseLiquidity({ ... })` Operation.\n *\n * No approvals needed — NPM doesn't pull tokens on decrease (it credits\n * the position's `tokensOwed0/1`, which a subsequent `collect()` flushes\n * to the recipient).\n */\nexport function buildDecreaseLiquidity(\n params: BuildDecreaseLiquidityParams,\n): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"decreaseLiquidity\",\n args: [\n {\n tokenId: params.tokenId,\n liquidity: params.liquidity,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n },\n ],\n }),\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\nimport { UINT128_MAX } from \"./constants\";\n\nexport interface BuildCollectParams {\n npm: Address;\n tokenId: bigint;\n /** Where the collected fees + principal go. Typically the user's EOA. */\n recipient: Address;\n /** Caps on the transfer. Default `UINT128_MAX` → take everything owed. */\n amount0Max?: bigint;\n amount1Max?: bigint;\n}\n\n/**\n * Build a single `NPM.collect({ ... })` Operation.\n *\n * When the position still has `liquidity > 0`, NPM internally calls\n * `pool.burn(tickLower, tickUpper, 0)` to flush newly-accrued fees into\n * `tokensOwed*` before transferring. So a standalone collect on an\n * active position both accrues AND claims in one tx.\n *\n * For collect-everything use the default `UINT128_MAX` caps.\n */\nexport function buildCollect(params: BuildCollectParams): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"collect\",\n args: [\n {\n tokenId: params.tokenId,\n recipient: params.recipient,\n amount0Max: params.amount0Max ?? UINT128_MAX,\n amount1Max: params.amount1Max ?? UINT128_MAX,\n },\n ],\n }),\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildBurnParams {\n npm: Address;\n tokenId: bigint;\n}\n\n/**\n * Build a single `NPM.burn(tokenId)` Operation.\n *\n * NPM enforces three preconditions on burn:\n * - `position.liquidity == 0`\n * - `position.tokensOwed0 == 0`\n * - `position.tokensOwed1 == 0`\n *\n * For a full close, batch `decreaseLiquidity(all) → collect → burn`. The\n * `buildClosePosition` orchestrator wires that for you; this builder is\n * exposed for callers that already know the preconditions hold (e.g.\n * burning an already-emptied position).\n */\nexport function buildBurn(params: BuildBurnParams): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"burn\",\n args: [params.tokenId],\n }),\n };\n}\n","import type { Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { buildDecreaseLiquidity } from \"./buildDecreaseLiquidity\";\nimport { buildCollect } from \"./buildCollect\";\nimport { buildBurn } from \"./buildBurn\";\n\nexport interface BuildClosePositionParams {\n npm: Address;\n tokenId: bigint;\n /** Current `position.liquidity`. Determines batch shape. */\n liquidity: bigint;\n /** `tokensOwed0 + tokensOwed1 > 0` → still need a collect leg. */\n hasOutstandingFees: boolean;\n /** Recipient of the collected tokens. Typically the user's EOA. */\n recipient: Address;\n /** Slippage-applied minimums for the decrease leg. */\n amount0Min: bigint;\n amount1Min: bigint;\n /** Unix seconds. Required for the decrease leg if liquidity > 0. */\n deadline: bigint;\n}\n\n/**\n * Build the full-close batch:\n *\n * - `liquidity > 0`: decreaseLiquidity(all) → collect → burn\n * - `liquidity == 0` + fees: collect → burn\n * - `liquidity == 0` + no fees: burn (only)\n *\n * The shape selection avoids unnecessary calls — burning an empty\n * position with no fees is a 1-op batch. Callers don't need to think\n * about the cases; pass the snapshot and the builder picks.\n */\nexport function buildClosePosition(\n params: BuildClosePositionParams,\n): Operation[] {\n const ops: Operation[] = [];\n\n if (params.liquidity > 0n) {\n ops.push(\n buildDecreaseLiquidity({\n npm: params.npm,\n tokenId: params.tokenId,\n liquidity: params.liquidity,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n }),\n );\n }\n\n if (params.liquidity > 0n || params.hasOutstandingFees) {\n ops.push(\n buildCollect({\n npm: params.npm,\n tokenId: params.tokenId,\n recipient: params.recipient,\n }),\n );\n }\n\n ops.push(buildBurn({ npm: params.npm, tokenId: params.tokenId }));\n\n return ops;\n}\n","import { minUsableTick, maxUsableTick } from \"./math\";\n\n/**\n * Compute the (word, bit) position of a tick in V3's bitmap layout.\n *\n * Mirrors Solidity `TickBitmap.position(int24)`:\n * compressed = tick / tickSpacing (floor div, not trunc)\n * word = compressed >> 8 (JS arithmetic shift on int32)\n * bit = ((compressed % 256) + 256) % 256 (JS `%` is sign-preserving — normalize)\n *\n * Throws if `tick` or `tickSpacing` is not an integer, if `tickSpacing <= 0`,\n * or if `tick` is not aligned to `tickSpacing`.\n */\nexport function tickToBitmapPosition(\n tick: number,\n tickSpacing: number,\n): { word: number; bit: number } {\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToBitmapPosition: tick (${tick}) must be an integer`);\n }\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new Error(\n `tickToBitmapPosition: tickSpacing (${tickSpacing}) must be a positive integer`,\n );\n }\n if (tick % tickSpacing !== 0) {\n throw new Error(\n `tickToBitmapPosition: tick (${tick}) must be a multiple of tickSpacing ${tickSpacing}`,\n );\n }\n const compressed = Math.floor(tick / tickSpacing);\n const word = compressed >> 8;\n const bit = ((compressed % 256) + 256) % 256;\n return { word, bit };\n}\n\n/**\n * Decode set bits of a single bitmap word into absolute tick indices.\n * Returns sorted ascending. O(1) when `bitmap === 0n`.\n *\n * Bitmap is uint256 → scans bit positions 0..255 inclusive. Decoded with\n * bigint primitives — `Number` would lose bits past position 53.\n */\nexport function decodeBitmapWord(\n bitmap: bigint,\n wordPos: number,\n tickSpacing: number,\n): number[] {\n if (bitmap === 0n) return [];\n const out: number[] = [];\n for (let bit = 0; bit < 256; bit++) {\n if ((bitmap & (1n << BigInt(bit))) !== 0n) {\n out.push((wordPos * 256 + bit) * tickSpacing);\n }\n }\n return out;\n}\n\n/**\n * Min/max wordPos required to scan an entire V3 pool's bitmap for the\n * given tickSpacing. Derived from `minUsableTick(spacing)` /\n * `maxUsableTick(spacing)`, not raw MIN/MAX_TICK.\n */\nexport function bitmapWordRange(tickSpacing: number): { min: number; max: number } {\n const lo = minUsableTick(tickSpacing);\n const hi = maxUsableTick(tickSpacing);\n return {\n min: Math.floor(lo / tickSpacing) >> 8,\n max: Math.floor(hi / tickSpacing) >> 8,\n };\n}\n","import {\n minUsableTick,\n maxUsableTick,\n tickToSqrtPriceX96,\n} from \"./math\";\nimport type { TickInfo } from \"./readPoolState\";\n\n/**\n * Discriminated error codes for the liquidity-curve subsystem. Use with\n * `LiquidityCurveError`: callers `instanceof LiquidityCurveError` then\n * branch on `code` to decide retry / Sentry / user-copy behavior.\n */\nexport enum LiquidityCurveErrorCode {\n /** fetchAllInitializedTicks: initTicks.length > maxTicks. Recovery: raise maxTicks. */\n TOO_MANY_TICKS = \"TOO_MANY_TICKS\",\n /** fetchAllInitializedTicks: bitmap-vs-ticks() mismatch. Recovery: retry against latest. */\n ATOMICITY_VIOLATION = \"ATOMICITY_VIOLATION\",\n /** buildLiquidityCurve: sum(liquidityNet) !== 0. Tick set incomplete or stale. */\n CURVE_SUM_NONZERO = \"CURVE_SUM_NONZERO\",\n /** buildLiquidityCurve: cumulative L went negative during walk. */\n CURVE_NEGATIVE_L = \"CURVE_NEGATIVE_L\",\n /** buildLiquidityCurve: edge L !== 0. currentLiquidity inconsistent with ticks. */\n CURVE_EDGE_NONZERO = \"CURVE_EDGE_NONZERO\",\n}\n\nexport class LiquidityCurveError extends Error {\n readonly code: LiquidityCurveErrorCode;\n constructor(code: LiquidityCurveErrorCode, message: string) {\n super(message);\n this.name = \"LiquidityCurveError\";\n this.code = code;\n }\n}\n\nexport interface InitializedTick extends TickInfo {\n /** Absolute tick index — integer, divisible by `tickSpacing`. */\n tick: number;\n}\n\nexport interface LiquidityCurveSegment {\n /** Inclusive lower bound. For the leftmost segment, equals `minUsableTick(spacing)`. */\n tickLower: number;\n /** Exclusive upper bound. For the rightmost segment, equals `maxUsableTick(spacing)`. */\n tickUpper: number;\n /** `tickToSqrtPriceX96(tickLower)`. */\n sqrtPriceLowerX96: bigint;\n /** `tickToSqrtPriceX96(tickUpper)`. */\n sqrtPriceUpperX96: bigint;\n /** Active liquidity (`L`) constant across `[tickLower, tickUpper)`. */\n liquidityActive: bigint;\n}\n\nexport interface BuildLiquidityCurveParams {\n /** From `fetchAllInitializedTicks`. Must be the COMPLETE set, sorted asc. */\n ticks: InitializedTick[];\n /** From `poolState.tick`. */\n currentTick: number;\n /** From `poolState.liquidity`. */\n currentLiquidity: bigint;\n /** From `poolState.tickSpacing`. Drives edge-clamp + sqrt-price boundaries. */\n tickSpacing: number;\n}\n\n/**\n * Pure transformer. Produces N+1 half-open segments covering\n * `[minUsableTick(spacing), maxUsableTick(spacing))`, each with the\n * active liquidity that holds across it.\n *\n * Throws `LiquidityCurveError` on inconsistent input (see error codes).\n */\nexport function buildLiquidityCurve(\n params: BuildLiquidityCurveParams,\n): LiquidityCurveSegment[] {\n const { ticks, currentTick, currentLiquidity, tickSpacing } = params;\n const TICK_LO = minUsableTick(tickSpacing);\n const TICK_HI = maxUsableTick(tickSpacing);\n const N = ticks.length;\n\n // Consistency check 1: complete tick set sums to zero net.\n const sumNet = ticks.reduce((acc, t) => acc + t.liquidityNet, 0n);\n if (sumNet !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_SUM_NONZERO,\n `buildLiquidityCurve: sum(liquidityNet) = ${sumNet}, expected 0. ` +\n `Tick set is incomplete or fetched at a different block.`,\n );\n }\n\n // Empty pool: single segment spanning the full usable range.\n if (N === 0) {\n return [\n {\n tickLower: TICK_LO,\n tickUpper: TICK_HI,\n sqrtPriceLowerX96: tickToSqrtPriceX96(TICK_LO),\n sqrtPriceUpperX96: tickToSqrtPriceX96(TICK_HI),\n liquidityActive: currentLiquidity,\n },\n ];\n }\n\n // Binary search: i_above = first index with tick > currentTick.\n let lo = 0;\n let hi = N;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (ticks[mid]!.tick > currentTick) hi = mid;\n else lo = mid + 1;\n }\n const i_above = lo;\n const i_below = i_above - 1;\n\n // Invariant: segments[i] covers [low_i, high_i) where\n // low_i = (i === 0 ? TICK_LO : ticks[i-1].tick)\n // high_i = (i === N ? TICK_HI : ticks[i].tick)\n // Write-sets {i_above}, {0..i_below}, {i_above+1..N} partition [0,N].\n const segments: LiquidityCurveSegment[] = new Array(N + 1);\n\n const anchorLower = i_below >= 0 ? ticks[i_below]!.tick : TICK_LO;\n const anchorUpper = i_above < N ? ticks[i_above]!.tick : TICK_HI;\n segments[i_above] = {\n tickLower: anchorLower,\n tickUpper: anchorUpper,\n sqrtPriceLowerX96: 0n, // filled below\n sqrtPriceUpperX96: 0n,\n liquidityActive: currentLiquidity,\n };\n\n // Walk LEFT.\n let L = currentLiquidity;\n for (let k = i_below; k >= 0; k--) {\n L = L - ticks[k]!.liquidityNet;\n if (L < 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_NEGATIVE_L,\n `buildLiquidityCurve: active liquidity went negative at tick ${ticks[k]!.tick} ` +\n `during left walk. Indicates inconsistent input.`,\n );\n }\n const lower = k - 1 >= 0 ? ticks[k - 1]!.tick : TICK_LO;\n segments[k] = {\n tickLower: lower,\n tickUpper: ticks[k]!.tick,\n sqrtPriceLowerX96: 0n,\n sqrtPriceUpperX96: 0n,\n liquidityActive: L,\n };\n }\n\n // Walk RIGHT.\n L = currentLiquidity;\n for (let j = i_above; j < N; j++) {\n L = L + ticks[j]!.liquidityNet;\n if (L < 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_NEGATIVE_L,\n `buildLiquidityCurve: active liquidity went negative at tick ${ticks[j]!.tick} ` +\n `during right walk.`,\n );\n }\n const upper = j + 1 < N ? ticks[j + 1]!.tick : TICK_HI;\n segments[j + 1] = {\n tickLower: ticks[j]!.tick,\n tickUpper: upper,\n sqrtPriceLowerX96: 0n,\n sqrtPriceUpperX96: 0n,\n liquidityActive: L,\n };\n }\n\n // Consistency check 2: outside any LP range, L must be 0.\n if (segments[0]!.liquidityActive !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_EDGE_NONZERO,\n `buildLiquidityCurve: leftmost L = ${segments[0]!.liquidityActive}, expected 0. ` +\n `currentLiquidity inconsistent with tick set.`,\n );\n }\n if (segments[N]!.liquidityActive !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_EDGE_NONZERO,\n `buildLiquidityCurve: rightmost L = ${segments[N]!.liquidityActive}, expected 0.`,\n );\n }\n\n // Fill sqrt-price boundaries.\n for (const seg of segments) {\n seg.sqrtPriceLowerX96 = tickToSqrtPriceX96(seg.tickLower);\n seg.sqrtPriceUpperX96 = tickToSqrtPriceX96(seg.tickUpper);\n }\n\n return segments;\n}\n\n/**\n * Clip a curve to a tick viewport. Returns a new sub-range of `curve`\n * covering `[tickLo, tickHi]`, splitting segments that straddle the\n * viewport edges. Pure. O(log N) via binary search on `tickLower`.\n *\n * Returns `[]` if the viewport is entirely outside the curve's coverage.\n */\nexport function clipCurveToTickRange(\n curve: LiquidityCurveSegment[],\n tickLo: number,\n tickHi: number,\n): LiquidityCurveSegment[] {\n if (curve.length === 0 || tickHi <= tickLo) return [];\n\n // Binary search: first index with tickUpper > tickLo.\n let lo = 0;\n let hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickUpper > tickLo) hi = mid;\n else lo = mid + 1;\n }\n const startIdx = lo;\n\n // First index with tickLower >= tickHi.\n lo = 0;\n hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickLower >= tickHi) hi = mid;\n else lo = mid + 1;\n }\n const endIdx = lo; // exclusive\n\n if (startIdx >= endIdx) return [];\n\n const out: LiquidityCurveSegment[] = [];\n for (let i = startIdx; i < endIdx; i++) {\n const seg = curve[i]!;\n const newLower = Math.max(seg.tickLower, tickLo);\n const newUpper = Math.min(seg.tickUpper, tickHi);\n if (newLower === seg.tickLower && newUpper === seg.tickUpper) {\n out.push(seg);\n } else {\n out.push({\n tickLower: newLower,\n tickUpper: newUpper,\n sqrtPriceLowerX96: tickToSqrtPriceX96(newLower),\n sqrtPriceUpperX96: tickToSqrtPriceX96(newUpper),\n liquidityActive: seg.liquidityActive,\n });\n }\n }\n return out;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { v3PoolAbi } from \"./abi\";\nimport { bitmapWordRange, decodeBitmapWord } from \"./readTickBitmap\";\nimport {\n LiquidityCurveError,\n LiquidityCurveErrorCode,\n type InitializedTick,\n} from \"./buildLiquidityCurve\";\n\n/** Bytes of calldata per Phase 1 / Phase 2 call:\n * 4 (selector) + 32 (single int16 or int24 arg, ABI-padded) = 36 bytes.\n * Update this constant if a wider arg is ever added. */\nexport const CALLDATA_BYTES_PER_CALL = 36;\n\nconst DEFAULT_CALLS_PER_BATCH = 250;\nconst DEFAULT_MAX_TICKS = 50_000;\n\nexport interface FetchAllInitializedTicksParams {\n client: PublicClient;\n pool: Address;\n /** Pin reads to this block. Default: latest at fetch start. */\n blockNumber?: bigint;\n /** Override pool.tickSpacing read. Saves 1 RPC if caller has it. */\n tickSpacing?: number;\n /** Maximum *calls* per HTTP eth_call sub-batch. Default 250.\n * Translated to viem's byte-oriented batchSize via `* CALLDATA_BYTES_PER_CALL`. */\n callsPerBatch?: number;\n /** Hard cap on returned tick count. Default 50_000. */\n maxTicks?: number;\n}\n\nexport interface FetchAllInitializedTicksResult {\n blockNumber: bigint;\n tickSpacing: number;\n /** Sorted ascending by `tick`. */\n ticks: InitializedTick[];\n}\n\n/**\n * Fetch every initialized tick of a V3 pool atomically via two-phase\n * multicall (`tickBitmap` → `ticks`), pinned to a single `blockNumber`.\n */\nexport async function fetchAllInitializedTicks(\n params: FetchAllInitializedTicksParams,\n): Promise<FetchAllInitializedTicksResult> {\n const callsPerBatch = params.callsPerBatch ?? DEFAULT_CALLS_PER_BATCH;\n const maxTicks = params.maxTicks ?? DEFAULT_MAX_TICKS;\n const batchSizeBytes = callsPerBatch * CALLDATA_BYTES_PER_CALL;\n\n // Pin a block.\n const blockNumber =\n params.blockNumber ?? (await params.client.getBlockNumber());\n\n // Resolve tickSpacing.\n let tickSpacing = params.tickSpacing;\n if (tickSpacing === undefined) {\n const [resolved] = await params.client.multicall({\n contracts: [\n {\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"tickSpacing\",\n },\n ],\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n });\n tickSpacing = Number(resolved);\n }\n\n // ── Phase 1: bitmap multicall over the full word range ──────────────────\n const { min: wordLo, max: wordHi } = bitmapWordRange(tickSpacing);\n const bitmapContracts = [];\n for (let w = wordLo; w <= wordHi; w++) {\n bitmapContracts.push({\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"tickBitmap\" as const,\n args: [w] as const,\n });\n }\n\n const bitmaps = (await params.client.multicall({\n contracts: bitmapContracts,\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n })) as bigint[];\n\n // Decode set bits into a flat sorted list of tick indices.\n const initTicks: number[] = [];\n for (let i = 0; i < bitmaps.length; i++) {\n const word = bitmaps[i]!;\n if (word === 0n) continue;\n const wordPos = wordLo + i;\n const decoded = decodeBitmapWord(word, wordPos, tickSpacing);\n for (const t of decoded) initTicks.push(t);\n }\n\n if (initTicks.length > maxTicks) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.TOO_MANY_TICKS,\n `fetchAllInitializedTicks: pool ${params.pool} has ${initTicks.length} ` +\n `initialized ticks, exceeds maxTicks=${maxTicks}. ` +\n `Pass maxTicks explicitly if you want the full set.`,\n );\n }\n\n // Short-circuit empty pool.\n if (initTicks.length === 0) {\n return { blockNumber, tickSpacing, ticks: [] };\n }\n\n // ── Phase 2: ticks multicall ────────────────────────────────────────────\n const ticksContracts = initTicks.map(\n (tick) =>\n ({\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"ticks\" as const,\n args: [tick] as const,\n } as const),\n );\n\n const ticksTuples = (await params.client.multicall({\n contracts: ticksContracts,\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n })) as readonly (readonly [\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n boolean,\n ])[];\n\n const ticks: InitializedTick[] = ticksTuples.map((tuple, i) => ({\n tick: initTicks[i]!,\n liquidityGross: tuple[0],\n liquidityNet: tuple[1],\n feeGrowthOutside0X128: tuple[2],\n feeGrowthOutside1X128: tuple[3],\n initialized: tuple[7],\n }));\n\n // Atomicity check.\n for (const t of ticks) {\n if (!t.initialized) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.ATOMICITY_VIOLATION,\n `fetchAllInitializedTicks: tick ${t.tick} bitmap-set but ` +\n `ticks().initialized=false at block ${blockNumber}. ` +\n `Snapshot is torn — RPC node likely served different blocks across batches.`,\n );\n }\n }\n\n return { blockNumber, tickSpacing, ticks };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { readPoolState, type PoolState } from \"./readPoolState\";\nimport {\n fetchAllInitializedTicks,\n type FetchAllInitializedTicksParams,\n} from \"./fetchAllInitializedTicks\";\nimport {\n buildLiquidityCurve,\n type InitializedTick,\n type LiquidityCurveSegment,\n} from \"./buildLiquidityCurve\";\n\nexport interface FetchLiquidityCurveParams {\n client: PublicClient;\n pool: Address;\n blockNumber?: bigint;\n /** Pre-fetched pool state. If provided, MUST have been observed at\n * `blockNumber` (caller's responsibility). When omitted, fetched here. */\n poolState?: PoolState;\n /** Forwarded to fetchAllInitializedTicks. */\n callsPerBatch?: FetchAllInitializedTicksParams[\"callsPerBatch\"];\n maxTicks?: FetchAllInitializedTicksParams[\"maxTicks\"];\n}\n\nexport interface FetchLiquidityCurveResult {\n blockNumber: bigint;\n poolState: PoolState;\n ticks: InitializedTick[];\n curve: LiquidityCurveSegment[];\n /** Index into `curve` of the segment containing `poolState.tick`.\n * Invariant: `curve[currentSegmentIndex].tickLower <= poolState.tick < curve[currentSegmentIndex].tickUpper`. */\n currentSegmentIndex: number;\n}\n\n/**\n * One-call convenience for the FE add-liquidity chart. Reads pool state,\n * fetches all initialized ticks, builds the curve — all pinned to the\n * same block.\n *\n * @throws {LiquidityCurveError} with `.code`:\n * - `TOO_MANY_TICKS` — pool has more than `maxTicks` initialized ticks\n * - `ATOMICITY_VIOLATION` — bitmap-vs-ticks() mismatch (rare; retry against latest)\n * - `CURVE_SUM_NONZERO` — tick set incomplete (caller passed a stale `poolState`)\n * - `CURVE_NEGATIVE_L` — cumulative liquidity went negative during walk\n * - `CURVE_EDGE_NONZERO` — `poolState` inconsistent with ticks (likely stale)\n */\nexport async function fetchLiquidityCurve(\n params: FetchLiquidityCurveParams,\n): Promise<FetchLiquidityCurveResult> {\n const blockNumber =\n params.blockNumber ?? (await params.client.getBlockNumber());\n\n const poolState =\n params.poolState ?? (await readPoolState(params.client, params.pool, blockNumber));\n\n const ticksResult = await fetchAllInitializedTicks({\n client: params.client,\n pool: params.pool,\n blockNumber,\n tickSpacing: poolState.tickSpacing,\n callsPerBatch: params.callsPerBatch,\n maxTicks: params.maxTicks,\n });\n\n const curve = buildLiquidityCurve({\n ticks: ticksResult.ticks,\n currentTick: poolState.tick,\n currentLiquidity: poolState.liquidity,\n tickSpacing: poolState.tickSpacing,\n });\n\n // Binary-search currentSegmentIndex.\n let lo = 0;\n let hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickUpper > poolState.tick) hi = mid;\n else lo = mid + 1;\n }\n const currentSegmentIndex = lo;\n\n return {\n blockNumber,\n poolState,\n ticks: ticksResult.ticks,\n curve,\n currentSegmentIndex,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildIncreaseLiquidity,\n readPosition,\n readPoolState,\n estimateLiquidityFromOneSide,\n applyMintSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface IncreaseLiquidityDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /** Existing position NFT id. SDK reads its range + token pair. */\n tokenId: bigint;\n\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface IncreaseLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** L added (estimated off-chain; receipt-parsed value would be authoritative). */\n liquidityAdded: bigint;\n deadline: bigint;\n}\n\n/**\n * Top up an existing V3 LP position via NPM.increaseLiquidity.\n *\n * Range comes from the existing position; user only specifies one side's\n * amount and the SDK computes the rest. Same 3-op batch as add (two\n * approvals + the NPM call), but range is read on-chain rather than\n * supplied by caller.\n */\nexport async function increaseLiquidityDirect(\n params: IncreaseLiquidityDirectParams,\n): Promise<IncreaseLiquidityDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `increaseLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(\n `increaseLiquidityDirect: no V3 factory for chainId ${params.chainId}`,\n );\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"increaseLiquidityDirect: tokenId must be positive\");\n }\n const has0 = params.amount0Desired !== undefined && params.amount0Desired > 0n;\n const has1 = params.amount1Desired !== undefined && params.amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"increaseLiquidityDirect: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `increaseLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"increaseLiquidityDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `increaseLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `increaseLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n // Read position + pool state in series — position first because we\n // need its tokens to compute the pool address.\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n const sqrtL = tickToSqrtPriceX96(position.tickLower);\n const sqrtU = tickToSqrtPriceX96(position.tickUpper);\n const { liquidity, amount0, amount1 } = estimateLiquidityFromOneSide({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: sqrtL,\n sqrtPriceX96Upper: sqrtU,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n });\n const { amount0Min, amount1Min } = applyMintSlippage({\n amount0Desired: amount0,\n amount1Desired: amount1,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = buildIncreaseLiquidity({\n npm,\n token0: position.token0,\n token1: position.token1,\n tokenId: params.tokenId,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `increaseLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n liquidityAdded: liquidity,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildDecreaseLiquidity,\n buildCollect,\n readPosition,\n readPoolState,\n getAmountsForLiquidity,\n applyRemoveSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface RemoveLiquidityDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n\n /** How much L to withdraw. Pass `liquidity` OR `liquidityBps`. Exactly one. */\n liquidity?: bigint;\n /** 0..10000 — percentage of current liquidity to remove. */\n liquidityBps?: number;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface RemoveLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n liquidityRemoved: bigint;\n amount0Expected: bigint;\n amount1Expected: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Partial withdraw from an existing V3 LP position.\n *\n * Batch shape:\n * 1. NPM.decreaseLiquidity({ tokenId, liquidity, amount0Min, amount1Min, deadline })\n * 2. NPM.collect({ tokenId, recipient: userAddress, amount0Max: MAX, amount1Max: MAX })\n *\n * No approvals — NPM doesn't pull tokens on remove. The collect leg is\n * mandatory because decrease only credits `tokensOwed*`; tokens stay in\n * the NPM until the user collects them.\n */\nexport async function removeLiquidityDirect(\n params: RemoveLiquidityDirectParams,\n): Promise<RemoveLiquidityDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `removeLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`removeLiquidityDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"removeLiquidityDirect: tokenId must be positive\");\n }\n const hasL = params.liquidity !== undefined && params.liquidity > 0n;\n const hasBps =\n params.liquidityBps !== undefined &&\n params.liquidityBps > 0 &&\n params.liquidityBps <= 10000;\n if (hasL === hasBps) {\n throw new Error(\n \"removeLiquidityDirect: exactly one of liquidity (>0) or liquidityBps (1..10000) must be set\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `removeLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"removeLiquidityDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `removeLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `removeLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n if (position.liquidity === 0n) {\n throw new Error(\n `removeLiquidityDirect: position ${params.tokenId} has zero liquidity — nothing to remove`,\n );\n }\n\n const liquidityToRemove = hasL\n ? params.liquidity!\n : (position.liquidity * BigInt(params.liquidityBps!)) / 10000n;\n if (liquidityToRemove === 0n) {\n throw new Error(\n \"removeLiquidityDirect: computed liquidity to remove is zero (bps too small for position size)\",\n );\n }\n if (liquidityToRemove > position.liquidity) {\n throw new Error(\n `removeLiquidityDirect: liquidity to remove (${liquidityToRemove}) exceeds position liquidity (${position.liquidity})`,\n );\n }\n\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n const { amount0: amount0Expected, amount1: amount1Expected } =\n getAmountsForLiquidity({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: tickToSqrtPriceX96(position.tickLower),\n sqrtPriceX96Upper: tickToSqrtPriceX96(position.tickUpper),\n liquidity: liquidityToRemove,\n });\n const { amount0Min, amount1Min } = applyRemoveSlippage({\n amount0Expected,\n amount1Expected,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = [\n buildDecreaseLiquidity({\n npm,\n tokenId: params.tokenId,\n liquidity: liquidityToRemove,\n amount0Min,\n amount1Min,\n deadline,\n }),\n buildCollect({\n npm,\n tokenId: params.tokenId,\n recipient: params.userAddress,\n }),\n ];\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `removeLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n liquidityRemoved: liquidityToRemove,\n amount0Expected,\n amount1Expected,\n amount0Min,\n amount1Min,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildClosePosition,\n readPosition,\n readPoolState,\n getAmountsForLiquidity,\n applyRemoveSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface ClosePositionDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface ClosePositionDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n liquidityRemoved: bigint;\n amount0Expected: bigint;\n amount1Expected: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Full close: decrease all liquidity (if any) + collect fees + burn the\n * position NFT. The SDK picks the batch shape from current position state:\n *\n * - liquidity > 0: decrease(all) → collect → burn (3 ops)\n * - liquidity == 0 + fees > 0: collect → burn (2 ops)\n * - liquidity == 0 + no fees: burn (1 op)\n *\n * Useful for cleaning up an LP NFT off the user's EOA after they're done.\n */\nexport async function closePositionDirect(\n params: ClosePositionDirectParams,\n): Promise<ClosePositionDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `closePositionDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`closePositionDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"closePositionDirect: tokenId must be positive\");\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `closePositionDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"closePositionDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `closePositionDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `closePositionDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n\n // Estimate expected amounts only if we still have liquidity to decrease.\n let amount0Expected = 0n;\n let amount1Expected = 0n;\n let amount0Min = 0n;\n let amount1Min = 0n;\n if (position.liquidity > 0n) {\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n const amounts = getAmountsForLiquidity({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: tickToSqrtPriceX96(position.tickLower),\n sqrtPriceX96Upper: tickToSqrtPriceX96(position.tickUpper),\n liquidity: position.liquidity,\n });\n amount0Expected = amounts.amount0;\n amount1Expected = amounts.amount1;\n const min = applyRemoveSlippage({\n amount0Expected,\n amount1Expected,\n slippageBps,\n });\n amount0Min = min.amount0Min;\n amount1Min = min.amount1Min;\n }\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = buildClosePosition({\n npm,\n tokenId: params.tokenId,\n liquidity: position.liquidity,\n hasOutstandingFees: position.tokensOwed0 + position.tokensOwed1 > 0n,\n recipient: params.userAddress,\n amount0Min,\n amount1Min,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `closePositionDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n liquidityRemoved: position.liquidity,\n amount0Expected,\n amount1Expected,\n amount0Min,\n amount1Min,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildCollect,\n readPosition,\n readPoolState,\n readTicksAt,\n readFeeGrowthGlobals,\n} from \"../liquidity\";\n\nexport interface CollectFeesDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n /** Recipient of the collected fees. Default `userAddress`. */\n recipient?: Address;\n\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface CollectFeesDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Pre-tx estimate (tokensOwed + pending). Actual transferred amount in the receipt's Collect log. */\n amount0Expected: bigint;\n amount1Expected: bigint;\n recipient: Address;\n}\n\n/**\n * Collect accrued fees from a position without changing its liquidity.\n *\n * Single-op batch (`NPM.collect`). NPM internally calls\n * `pool.burn(tickLower, tickUpper, 0)` when the position has active\n * liquidity, which flushes newly-accrued swap fees from the pool into\n * the position's `tokensOwed*` before transferring them out.\n *\n * The estimate combines `position.tokensOwed*` (already in NPM) with the\n * \"pending\" fees still in the pool (derived off-chain from feeGrowth\n * deltas). The actual transferred amount comes from the on-chain\n * `Collect` event in the receipt and may differ slightly if another\n * tx accrued more fees between the read and mine.\n */\nexport async function collectFeesDirect(\n params: CollectFeesDirectParams,\n): Promise<CollectFeesDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `collectFeesDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`collectFeesDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"collectFeesDirect: tokenId must be positive\");\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"collectFeesDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `collectFeesDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `collectFeesDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n\n // Compute pending-fee estimate. If the position has no liquidity, all\n // claimable amounts are already pinned in `tokensOwed*` and we can\n // skip the pool reads entirely.\n let amount0Expected = position.tokensOwed0;\n let amount1Expected = position.tokensOwed1;\n if (position.liquidity > 0n) {\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const [poolState, ticks, globals] = await Promise.all([\n readPoolState(params.publicClient, pool),\n readTicksAt(params.publicClient, pool, position.tickLower, position.tickUpper),\n readFeeGrowthGlobals(params.publicClient, pool),\n ]);\n\n const feeGrowthInside0 = computeFeeGrowthInside({\n currentTick: poolState.tick,\n tickLower: position.tickLower,\n tickUpper: position.tickUpper,\n feeGrowthGlobalX128: globals.feeGrowthGlobal0X128,\n feeGrowthOutsideLowerX128: ticks.lower.feeGrowthOutside0X128,\n feeGrowthOutsideUpperX128: ticks.upper.feeGrowthOutside0X128,\n });\n const feeGrowthInside1 = computeFeeGrowthInside({\n currentTick: poolState.tick,\n tickLower: position.tickLower,\n tickUpper: position.tickUpper,\n feeGrowthGlobalX128: globals.feeGrowthGlobal1X128,\n feeGrowthOutsideLowerX128: ticks.lower.feeGrowthOutside1X128,\n feeGrowthOutsideUpperX128: ticks.upper.feeGrowthOutside1X128,\n });\n\n const pending0 = wrappingDelta(\n feeGrowthInside0,\n position.feeGrowthInside0LastX128,\n ) * position.liquidity / (1n << 128n);\n const pending1 = wrappingDelta(\n feeGrowthInside1,\n position.feeGrowthInside1LastX128,\n ) * position.liquidity / (1n << 128n);\n\n amount0Expected += pending0;\n amount1Expected += pending1;\n }\n\n const recipient = params.recipient ?? params.userAddress;\n const operations = [buildCollect({ npm, tokenId: params.tokenId, recipient })];\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `collectFeesDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n amount0Expected,\n amount1Expected,\n recipient,\n };\n}\n\n/**\n * V3's canonical `feeGrowthInside` formula. Branches on whether the\n * current tick is below / inside / above the position's range.\n *\n * Bit-truncation to 256 is implicit in Solidity's `uint256`; we mirror\n * that with a `mod` to keep the math consistent with on-chain behavior\n * when the underflow happens.\n */\nfunction computeFeeGrowthInside(params: {\n currentTick: number;\n tickLower: number;\n tickUpper: number;\n feeGrowthGlobalX128: bigint;\n feeGrowthOutsideLowerX128: bigint;\n feeGrowthOutsideUpperX128: bigint;\n}): bigint {\n const {\n currentTick,\n tickLower,\n tickUpper,\n feeGrowthGlobalX128,\n feeGrowthOutsideLowerX128,\n feeGrowthOutsideUpperX128,\n } = params;\n\n let feeGrowthBelow: bigint;\n if (currentTick >= tickLower) {\n feeGrowthBelow = feeGrowthOutsideLowerX128;\n } else {\n feeGrowthBelow = wrappingDelta(feeGrowthGlobalX128, feeGrowthOutsideLowerX128);\n }\n\n let feeGrowthAbove: bigint;\n if (currentTick < tickUpper) {\n feeGrowthAbove = feeGrowthOutsideUpperX128;\n } else {\n feeGrowthAbove = wrappingDelta(feeGrowthGlobalX128, feeGrowthOutsideUpperX128);\n }\n\n return wrappingDelta(\n wrappingDelta(feeGrowthGlobalX128, feeGrowthBelow),\n feeGrowthAbove,\n );\n}\n\n/**\n * uint256 subtraction with Solidity's wrapping semantics. Used because\n * V3's feeGrowth deltas can \"underflow\" — that's intentional in the\n * protocol and the result still reads as a meaningful unsigned value\n * after the wrap.\n */\nfunction wrappingDelta(a: bigint, b: bigint): bigint {\n const TWO_256 = 1n << 256n;\n return (a - b + TWO_256) % TWO_256;\n}\n"],"mappings":"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","names":["COMMON_POOLS","COMMON_POOLS","encodeV3Path","encodeV3PathReversed","encodeFunctionData","universalRouterAbi","encodeFunctionData","universalRouterAbi","userOp","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","parseEip7702DelegatedAddress","detectDelegateImpl","SIMPLE_7702_IMPL_BASE_MAINNET","BATCH_EXECUTOR_7702_IMPL","UNIVERSAL_ROUTER_ADDRESSES","parseEip7702DelegatedAddress","detectDelegateImpl","SIMPLE_7702_IMPL_BASE_MAINNET","BATCH_EXECUTOR_7702_IMPL","getContractAddresses","BROKER_HASHES","ORDERLY_RELAY_ABI","ORDERLY_VAULT_ABI","ORDERLY_VAULT_ADDRESSES","TOKEN_HASHES","buildPerpDepositViaRelay","computeAccountId","detectDelegateImpl","getContractAddresses","parseEip7702DelegatedAddress","BATCH_EXECUTOR_7702_IMPL","SIMPLE_7702_IMPL_BASE_MAINNET","buildErc20TransferUserOp","getContractAddresses","parseEip7702DelegatedAddress","detectDelegateImpl","BATCH_EXECUTOR_7702_IMPL","SIMPLE_7702_IMPL_BASE_MAINNET","parseEip7702DelegatedAddress","buildPartialUserOperation","UINT128_MAX","liquidity","encodeFunctionData","erc20ApproveOp","erc20ApproveOp","encodeFunctionData","encodeFunctionData","erc20ApproveOp","erc20ApproveOp","encodeFunctionData","encodeFunctionData","encodeFunctionData","encodeFunctionData","encodeFunctionData","UINT128_MAX","encodeFunctionData","encodeFunctionData","LiquidityCurveErrorCode","parseEip7702DelegatedAddress","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation"]}
1
+ {"version":3,"sources":["../src/api/handlers.ts","../src/quoting/routes.ts","../src/quoting/quote.ts","../src/swap/approval.ts","../src/swap/universalRouter.ts","../src/swap/simulate.ts","../src/swap/buildSwap.ts","../src/swap/slippage.ts","../src/pools.ts","../src/direct/swapDirect.ts","../src/direct/swapDirectExactOut.ts","../src/direct/perpDepositDirect.ts","../src/direct/transferDirect.ts","../src/direct/addLiquidityDirect.ts","../src/liquidity/abi/nonfungiblePositionManager.ts","../src/liquidity/abi/v3Pool.ts","../src/liquidity/constants.ts","../src/liquidity/math.ts","../src/liquidity/readPosition.ts","../src/liquidity/readPoolState.ts","../src/liquidity/buildMint.ts","../src/liquidity/buildIncreaseLiquidity.ts","../src/liquidity/buildDecreaseLiquidity.ts","../src/liquidity/buildCollect.ts","../src/liquidity/buildBurn.ts","../src/liquidity/buildClosePosition.ts","../src/liquidity/readTickBitmap.ts","../src/liquidity/buildLiquidityCurve.ts","../src/liquidity/fetchAllInitializedTicks.ts","../src/liquidity/fetchLiquidityCurve.ts","../src/direct/increaseLiquidityDirect.ts","../src/direct/removeLiquidityDirect.ts","../src/direct/closePositionDirect.ts","../src/direct/collectFeesDirect.ts"],"sourcesContent":["import { getAddress } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport {\n buildPerpDepositWithGasDeduction,\n buildPerpDepositViaRelay,\n buildErc20TransferUserOp,\n ORDERLY_RELAY_ABI,\n getContractAddresses,\n UNIVERSAL_ROUTER_ADDRESSES,\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n BROKER_HASHES,\n TOKEN_HASHES,\n ValidationError,\n computeAccountId,\n quoteOperatorFeePt,\n quoteOperatorFeeUsdt,\n quoteOperatorFeeForTransfer,\n} from \"@pafi-dev/core\";\nimport { findBestQuote, findBestQuoteExactOut } from \"../quoting\";\nimport {\n MAX_SLIPPAGE_BPS,\n buildSwapUserOp,\n buildSwapUserOpExactOut,\n isValidSlippageBps,\n} from \"../swap\";\nimport type {\n ApiQuoteRequest,\n ApiQuoteResponse,\n ApiSwapRequest,\n ApiSwapResponse,\n ApiQuoteExactOutRequest,\n ApiQuoteExactOutResponse,\n ApiSwapExactOutRequest,\n ApiSwapExactOutResponse,\n ApiPerpDepositRequest,\n ApiPerpDepositResponse,\n ApiErc20TransferRequest,\n ApiErc20TransferResponse,\n} from \"./types\";\n\nexport interface TradingHandlersConfig {\n provider: PublicClient;\n chainId: number;\n}\n\n/**\n * Framework-agnostic handlers for on-chain trading actions.\n *\n * All handlers are stateless — they need only a PublicClient for RPC\n * calls. No ledger, no signer, no DB. Issuers wrap these in their own\n * HTTP controllers (Express / NestJS / Hono / etc.) the same way they\n * wrap `IssuerApiHandlers` from `@pafi-dev/issuer`.\n *\n * Example (NestJS):\n *\n * const trading = new TradingHandlers({ provider, chainId });\n *\n * // GET /quote\n * const quote = await trading.handleQuote({ chainId, pointTokenAddress, amount, pools });\n *\n * // POST /swap\n * const swap = await trading.handleSwap({ chainId, userAddress, pointTokenAddress, amount, aaNonce });\n *\n * // POST /perp-deposit\n * const deposit = await trading.handlePerpDeposit({ chainId, userAddress, amount, aaNonce, brokerId });\n */\nexport class TradingHandlers {\n private readonly provider: PublicClient;\n private readonly chainId: number;\n\n constructor(config: TradingHandlersConfig) {\n this.provider = config.provider;\n this.chainId = config.chainId;\n }\n\n // =========================================================================\n // GET /quote\n // =========================================================================\n\n /**\n * Quote exact-input PT → USDT via Uniswap V3 QuoterV2.\n *\n * Uses multicall to batch all candidate routes into a single RPC call.\n * Returns `quoteError: \"QUOTE_UNAVAILABLE\"` when no pool/path exists\n * rather than throwing, so callers can show a soft \"unavailable\" UI\n * state without 500-ing.\n */\n async handleQuote(request: ApiQuoteRequest): Promise<ApiQuoteResponse> {\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleQuote: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount === 0n) {\n return {\n inputAmount: 0n,\n estimatedOutputAmount: 0n,\n outputNet: 0n,\n feeAmountOutput: 0n,\n gasEstimate: 0n,\n };\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const pools = request.pools ?? [];\n\n try {\n const best = await findBestQuote(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n const feeAmountOutput = await quoteOperatorFeeOutput(\n this.provider,\n request.chainId,\n outputTokenAddress,\n ).catch(() => 0n);\n const outputNet =\n best.bestRoute.amountOut > feeAmountOutput\n ? best.bestRoute.amountOut - feeAmountOutput\n : 0n;\n return {\n inputAmount: request.amount,\n estimatedOutputAmount: best.bestRoute.amountOut,\n outputNet,\n feeAmountOutput,\n gasEstimate: best.bestRoute.gasEstimate,\n };\n } catch {\n return {\n inputAmount: request.amount,\n estimatedOutputAmount: 0n,\n outputNet: 0n,\n feeAmountOutput: 0n,\n gasEstimate: 0n,\n quoteError: \"QUOTE_UNAVAILABLE\",\n };\n }\n }\n\n // =========================================================================\n // POST /swap\n // =========================================================================\n\n /**\n * Build a swap UserOp (direction-agnostic).\n *\n * Quotes the best route, applies slippage, then encodes a 4-step\n * batch: input.approve → Permit2.approve → UniversalRouter.execute →\n * output.transfer (fee in OUTPUT token, omitted when fee = 0).\n *\n * v0.3 — Fee model is OUTPUT-side (token-availability rule). User\n * holds exactly `amountIn` of input; receives `outputGross - fee`\n * net. Quote response surfaces both `estimatedOutputAmount` (gross)\n * and `outputNet` so the FE can display reality.\n *\n * `authenticatedAddress` first param: caller (issuer controller / FE\n * proxy) MUST pass the address extracted from the verified\n * session/JWT. Handler asserts it equals `request.userAddress`.\n */\n async handleSwap(\n authenticatedAddress: Address,\n request: ApiSwapRequest,\n ): Promise<ApiSwapResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleSwap: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleSwap: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handleSwap: amount must be positive\",\n );\n }\n if (!isValidSlippageBps(request.slippageBps)) {\n throw new ValidationError(\n \"INVALID_SLIPPAGE\",\n `handleSwap: slippageBps (${request.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n { received: request.slippageBps, max: MAX_SLIPPAGE_BPS },\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(request.chainId);\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[request.chainId];\n if (!universalRouter) {\n throw new ValidationError(\n \"ROUTER_NOT_DEPLOYED\",\n `handleSwap: no UniversalRouter for chainId ${request.chainId}`,\n );\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const userAddress = getAddress(request.userAddress);\n const pools = request.pools ?? [];\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuote>>;\n try {\n quoteResult = await findBestQuote(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new ValidationError(\n \"NO_SWAP_PATH\",\n `handleSwap: no swap path found from ${inputTokenAddress} to ${outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n // Resolve the operator fee in OUTPUT token units. Auto-quote uses\n // the right underlying quoter based on output token (USDT vs PT).\n const gasFeeAmountOutput =\n request.gasFeeAmountOutput !== undefined\n ? request.gasFeeAmountOutput\n : await quoteOperatorFeeOutput(\n this.provider,\n request.chainId,\n outputTokenAddress,\n ).catch(() => 0n);\n\n const hops = quoteResult.bestRoute.path.fees.length;\n // Multi-hop routes compound slippage across legs — bias higher when\n // caller didn't override. 50 bps single-hop, 100 bps multi-hop.\n const slippageBps =\n request.slippageBps ?? (hops > 1 ? 100 : 50);\n\n const estimatedOutputAmount = quoteResult.bestRoute.amountOut;\n const minAmountOut = (estimatedOutputAmount * BigInt(10000 - slippageBps)) / 10000n;\n\n if (gasFeeAmountOutput > 0n && minAmountOut < gasFeeAmountOutput) {\n throw new ValidationError(\n \"AMOUNT_TOO_SMALL_FOR_FEE\",\n `handleSwap: minAmountOut (${minAmountOut}) below operator fee (${gasFeeAmountOutput}) — increase swap amount or accept tighter slippage`,\n {\n minAmountOut: minAmountOut.toString(),\n gasFeeAmountOutput: gasFeeAmountOutput.toString(),\n },\n );\n }\n\n const deadline = BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const userOp = buildSwapUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: request.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // Fee-stripped fallback for paymaster-refused path.\n const userOpFallback =\n gasFeeAmountOutput > 0n\n ? buildSwapUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: request.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput: 0n,\n feeRecipient: pafiFeeRecipient,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n estimatedOutputAmount,\n minAmountOut,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // GET /quote/exact-out — V3 exact-output quote\n // =========================================================================\n\n /**\n * Quote the input required to receive `request.amount` of the output\n * token via Uniswap V3 QuoterV2. Input-side operator fee is auto-quoted, so\n * `inputGross = estimatedInputAmount + feeAmountInput` is the total\n * the user must hold.\n *\n * Returns `quoteError: \"QUOTE_UNAVAILABLE\"` rather than throwing when\n * no path exists.\n */\n async handleQuoteExactOut(\n request: ApiQuoteExactOutRequest,\n ): Promise<ApiQuoteExactOutResponse> {\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleQuoteExactOut: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount === 0n) {\n return {\n outputAmount: 0n,\n estimatedInputAmount: 0n,\n inputGross: 0n,\n feeAmountInput: 0n,\n gasEstimate: 0n,\n };\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const pools = request.pools ?? [];\n\n try {\n const best = await findBestQuoteExactOut(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n const feeAmountInput = await quoteOperatorFeeInput(\n this.provider,\n request.chainId,\n inputTokenAddress,\n ).catch(() => 0n);\n const estimatedInputAmount = best.bestRoute.amountIn;\n return {\n outputAmount: request.amount,\n estimatedInputAmount,\n inputGross: estimatedInputAmount + feeAmountInput,\n feeAmountInput,\n gasEstimate: best.bestRoute.gasEstimate,\n };\n } catch {\n return {\n outputAmount: request.amount,\n estimatedInputAmount: 0n,\n inputGross: 0n,\n feeAmountInput: 0n,\n gasEstimate: 0n,\n quoteError: \"QUOTE_UNAVAILABLE\",\n };\n }\n }\n\n // =========================================================================\n // POST /swap/exact-out — V3 exact-output swap UserOp\n // =========================================================================\n\n /**\n * Build a V3 exact-output swap UserOp.\n *\n * Quotes the best exact-output route, applies slippage as a CEILING on\n * `maxAmountIn` (so the cap is never silently tightened by floor\n * division), then encodes a 4-step batch:\n *\n * inputToken.transfer(feeRecipient, gasFeeAmountInput) [if > 0]\n * → input.approve(Permit2, maxAmountIn)\n * → Permit2.approve(router, maxAmountIn)\n * → UniversalRouter.execute (V3_SWAP_EXACT_OUT)\n *\n * Operator fee is INPUT-token-side (charged before swap) so the user\n * receives exactly `request.amount` of output.\n *\n * `authenticatedAddress` first param: caller MUST pass the address\n * extracted from the verified session/JWT. Handler asserts equality\n * with `request.userAddress`.\n */\n async handleSwapExactOut(\n authenticatedAddress: Address,\n request: ApiSwapExactOutRequest,\n ): Promise<ApiSwapExactOutResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleSwapExactOut: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleSwapExactOut: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handleSwapExactOut: amount must be positive\",\n );\n }\n if (!isValidSlippageBps(request.slippageBps)) {\n throw new ValidationError(\n \"INVALID_SLIPPAGE\",\n `handleSwapExactOut: slippageBps (${request.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n { received: request.slippageBps, max: MAX_SLIPPAGE_BPS },\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(request.chainId);\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[request.chainId];\n if (!universalRouter) {\n throw new ValidationError(\n \"ROUTER_NOT_DEPLOYED\",\n `handleSwapExactOut: no UniversalRouter for chainId ${request.chainId}`,\n );\n }\n\n const inputTokenAddress = getAddress(request.inputTokenAddress);\n const outputTokenAddress = getAddress(request.outputTokenAddress);\n const userAddress = getAddress(request.userAddress);\n const pools = request.pools ?? [];\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuoteExactOut>>;\n try {\n quoteResult = await findBestQuoteExactOut(\n this.provider,\n request.chainId,\n inputTokenAddress,\n outputTokenAddress,\n request.amount,\n pools,\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new ValidationError(\n \"NO_SWAP_PATH\",\n `handleSwapExactOut: no swap path found from ${inputTokenAddress} to ${outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n // Auto-quote the operator fee in INPUT-token units when caller didn't\n // override. Uses the input-token-aware sibling of quoteOperatorFeeOutput.\n const gasFeeAmountInput =\n request.gasFeeAmountInput !== undefined\n ? request.gasFeeAmountInput\n : await quoteOperatorFeeInput(\n this.provider,\n request.chainId,\n inputTokenAddress,\n ).catch(() => 0n);\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = request.slippageBps ?? (hops > 1 ? 100 : 50);\n\n const estimatedInputAmount = quoteResult.bestRoute.amountIn;\n // Ceiling division: maxAmountIn = ceil(estimated * (10000 + slippageBps) / 10000)\n // — if we used floor, the cap would round DOWN and could silently\n // be tighter than the caller intended, causing edge-case reverts.\n const slippageNumerator =\n estimatedInputAmount * BigInt(10000 + slippageBps);\n const maxAmountIn = (slippageNumerator + 9999n) / 10000n;\n\n const deadline = BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const userOp = buildSwapUserOpExactOut({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: request.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // Fee-stripped fallback for paymaster-refused path.\n const userOpFallback =\n gasFeeAmountInput > 0n\n ? buildSwapUserOpExactOut({\n userAddress,\n aaNonce: request.aaNonce,\n inputTokenAddress,\n outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: request.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput: 0n,\n feeRecipient: pafiFeeRecipient,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n outputAmount: request.amount,\n estimatedInputAmount,\n maxAmountIn,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // POST /perp-deposit\n // =========================================================================\n\n /**\n * Build an Orderly perp deposit UserOp.\n *\n * Default path is the **PAFI Orderly Relay** (`viaRelay: true`):\n * USDC.approve(relay) + relay.deposit(req). The Relay holds an ETH\n * reserve and pays Orderly's LayerZero `msg.value` out of it; the\n * user pays a USDC fee (quoted via `Relay.quoteTokenFee`) instead.\n * No native ETH on the user wallet is required, so paymaster\n * sponsorship of the ERC-4337 gas is sufficient end-to-end.\n *\n * Fallback path (`viaRelay: false`): direct `Vault.deposit{value}`.\n * Reserved for chains where no Relay is deployed — the user wallet\n * **must** hold `layerZeroFee` as native ETH.\n *\n * The Relay path automatically falls back to Vault when\n * `getContractAddresses(chainId).orderlyRelay` is the placeholder\n * sentinel (Relay not deployed for that chain).\n */\n async handlePerpDeposit(\n authenticatedAddress: Address,\n request: ApiPerpDepositRequest,\n ): Promise<ApiPerpDepositResponse> {\n // Auth-context check — caller MUST pass the verified address.\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handlePerpDeposit: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handlePerpDeposit: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n \"handlePerpDeposit: amount must be positive\",\n );\n }\n\n const vault = ORDERLY_VAULT_ADDRESSES[request.chainId];\n if (!vault) {\n throw new ValidationError(\n \"VAULT_NOT_DEPLOYED\",\n `handlePerpDeposit: no Orderly Vault for chainId ${request.chainId}`,\n );\n }\n\n const brokerHash = BROKER_HASHES[request.brokerId as keyof typeof BROKER_HASHES];\n if (!brokerHash) {\n throw new ValidationError(\n \"UNKNOWN_BROKER_ID\",\n `handlePerpDeposit: unknown brokerId \"${request.brokerId}\"`,\n { brokerId: request.brokerId },\n );\n }\n const tokenHash = TOKEN_HASHES.USDC;\n const userAddress = getAddress(request.userAddress);\n\n const [usdcAddress, brokerAllowed] = await Promise.all([\n this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedToken\",\n args: [tokenHash],\n }) as Promise<Address>,\n this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedBroker\",\n args: [brokerHash],\n }) as Promise<boolean>,\n ]);\n\n if (!brokerAllowed) {\n throw new ValidationError(\n \"BROKER_NOT_WHITELISTED\",\n `handlePerpDeposit: broker \"${request.brokerId}\" is not whitelisted on Orderly Vault`,\n { brokerId: request.brokerId, brokerHash },\n );\n }\n\n const accountId = computeAccountId(userAddress, brokerHash);\n const depositData = {\n accountId,\n brokerHash,\n tokenHash,\n tokenAmount: request.amount,\n };\n\n // Always read layerZeroFee for response — even on the Relay path\n // it's useful informational output (lets the FE show \"Relay\n // covers ~X ETH for you\").\n const layerZeroFee = (await this.provider.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getDepositFee\",\n args: [userAddress, depositData],\n })) as bigint;\n\n const useRelay = request.viaRelay !== false;\n const { orderlyRelay: relayAddress, pafiFeeRecipient } =\n getContractAddresses(request.chainId);\n const relayDeployed = !isPlaceholderAddress(relayAddress);\n\n // Resolve operator fee in USDC (input-token). Only applied to the\n // Relay path; the legacy direct-Vault path skips operator fee\n // entirely (it's already gas-heavy due to the user-paid\n // LayerZero msg.value, and PAFI doesn't sponsor that path on Base\n // anyway).\n const gasFeeUsdc =\n request.gasFeeUsdc !== undefined\n ? request.gasFeeUsdc\n : useRelay && relayDeployed\n ? await quoteOperatorFeeUsdt({\n provider: this.provider,\n chainId: request.chainId,\n }).catch(() => 0n)\n : 0n;\n\n if (useRelay && relayDeployed) {\n // Cap = max(amount * 5%, 2 USDC). The Relay fee is a flat USDC\n // amount derived from the LayerZero ETH cost at oracle price —\n // it does NOT scale with deposit size. A pure percentage cap\n // breaks for small deposits (e.g. 0.01 USDC test deposit, 5%\n // cap = 500 wei < 14k wei real fee). The 2 USDC floor covers\n // normal LayerZero pricing on Base; the 5% slope still guards\n // against oracle spikes on large deposits.\n const RELAY_FEE_FLOOR_USDC = 2_000_000n; // 2 USDC (6 decimals)\n const percentCap = (request.amount * 500n) / 10_000n;\n const maxRelayFee =\n request.maxRelayFee ??\n (percentCap > RELAY_FEE_FLOOR_USDC ? percentCap : RELAY_FEE_FLOOR_USDC);\n\n const relayRequest = {\n token: usdcAddress,\n receiver: userAddress,\n brokerHash,\n totalAmount: request.amount,\n maxFee: maxRelayFee,\n };\n\n const relayTokenFee = (await this.provider.readContract({\n address: relayAddress,\n abi: ORDERLY_RELAY_ABI,\n functionName: \"quoteTokenFee\",\n args: [relayRequest],\n })) as bigint;\n\n if (relayTokenFee > maxRelayFee) {\n throw new ValidationError(\n \"RELAY_FEE_EXCEEDS_MAX\",\n `handlePerpDeposit: Relay tokenFee ${relayTokenFee} (≈ ${\n Number(relayTokenFee) / 1e6\n } USDC) exceeds maxRelayFee ${maxRelayFee} — pass a larger ` +\n `\\`maxRelayFee\\` or increase the deposit \\`amount\\` so the fee ` +\n `becomes a smaller share of the total.`,\n {\n relayTokenFee: relayTokenFee.toString(),\n maxRelayFee: maxRelayFee.toString(),\n },\n );\n }\n\n // Sanity-check: Relay forwards `(totalAmount − tokenFee)` to\n // Orderly Vault. When `tokenFee >= totalAmount` the forwarded\n // amount is zero / negative and the Relay reverts on-chain with\n // `FeeExceedsAmount(fee, totalAmount)` (selector 0x536766bf),\n // which propagates as an opaque `BatchExecutor.CallFailed(1, …)`\n // revert at simulation time. Catch this early on the client so\n // the UX shows an actionable message instead of an AA21/AA34\n // bundler error wrapped around the raw selector.\n if (relayTokenFee >= request.amount) {\n const feeUsdc = Number(relayTokenFee) / 1e6;\n const amountUsdc = Number(request.amount) / 1e6;\n throw new ValidationError(\n \"RELAY_FEE_EXCEEDS_AMOUNT\",\n `handlePerpDeposit: deposit amount ${amountUsdc} USDC is below the ` +\n `Relay fee ${feeUsdc} USDC — increase \\`amount\\` to at least ` +\n `${(feeUsdc * 2).toFixed(6)} USDC so a meaningful balance reaches ` +\n `your Orderly account after the Relay charge.`,\n {\n relayTokenFee: relayTokenFee.toString(),\n amount: request.amount.toString(),\n },\n );\n }\n\n // USDC fee transferred FIRST in the batch (input-token rule —\n // user holds USDC at start). Recipient = pafiFeeRecipient.\n const userOp = buildPerpDepositViaRelay({\n userAddress,\n aaNonce: request.aaNonce,\n relayAddress,\n request: relayRequest,\n gasFeeUsdc: gasFeeUsdc > 0n ? gasFeeUsdc : undefined,\n gasFeeUsdcRecipient: gasFeeUsdc > 0n ? pafiFeeRecipient : undefined,\n });\n\n // Same shape, no USDC fee transfer — for the paymaster-refused\n // fallback path. The Relay still charges its own USDC token-fee\n // (compensates LayerZero ETH spend, NOT PAFI's gas).\n const userOpFallback =\n gasFeeUsdc > 0n\n ? buildPerpDepositViaRelay({\n userAddress,\n aaNonce: request.aaNonce,\n relayAddress,\n request: relayRequest,\n })\n : undefined;\n\n return {\n userOp,\n userOpFallback,\n path: \"relay\",\n layerZeroFee,\n relayTokenFee,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress,\n feeAmountUsed: gasFeeUsdc,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // Fallback: direct Vault.deposit{value} — user wallet MUST hold\n // `layerZeroFee` as native ETH (paymaster does not sponsor msg.value).\n const userOp = buildPerpDepositWithGasDeduction({\n userAddress,\n aaNonce: request.aaNonce,\n chainId: request.chainId,\n usdcAddress,\n amount: request.amount,\n depositData,\n layerZeroFee,\n });\n\n return {\n userOp,\n path: \"vault\",\n layerZeroFee,\n relayTokenFee: 0n,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress: vault,\n // Vault path doesn't include the PT operator fee transfer (it's\n // an unsponsored path on chains without a Relay deployment, and\n // the user is paying msg.value in ETH already). Echo 0n + the\n // canonical recipient so the response shape stays consistent.\n feeAmountUsed: 0n,\n feeRecipient: pafiFeeRecipient,\n };\n }\n\n // =========================================================================\n // POST /erc20-transfer — gasless ERC-20 send (USDC/USDT/active-PT)\n // =========================================================================\n\n /**\n * Build a sponsored ERC-20 transfer UserOp pair (sponsored + fallback).\n *\n * Sponsored variant: `[token.transfer(PAFI, fee), token.transfer(recipient, amount)]`.\n * Fallback variant: `[token.transfer(recipient, amount)]` (user pays ETH).\n *\n * Both calls hit the SAME token contract — fee currency equals the\n * token being sent, so the user needs only ONE token (≥ `amount + fee`)\n * to complete a gasless send.\n *\n * Allowlist enforced HERE (client-side fail-fast) **and** server-side\n * by sponsor-relayer's IntentValidator:\n * - USDC (`getContractAddresses(chainId).usdc`)\n * - USDT (`getContractAddresses(chainId).usdt`)\n * - active PointToken (caller responsibility to check\n * `IssuerRegistry.isActiveByPointToken` if not stable)\n *\n * Recipient rejected when equal to `pafiFeeRecipient` (self-fee abuse)\n * or `0x0` (use the burn scenario for that).\n *\n * See `docs/SPONSORED_ERC20_TRANSFER_SPEC.md` for the full call\n * pattern, error codes, and edge cases.\n */\n async handleErc20Transfer(\n authenticatedAddress: Address,\n request: ApiErc20TransferRequest,\n ): Promise<ApiErc20TransferResponse> {\n if (\n getAddress(authenticatedAddress) !== getAddress(request.userAddress)\n ) {\n throw new ValidationError(\n \"USER_ADDRESS_MISMATCH\",\n `handleErc20Transfer: authenticatedAddress (${authenticatedAddress}) does not match request.userAddress (${request.userAddress})`,\n );\n }\n if (request.chainId !== this.chainId) {\n throw new ValidationError(\n \"UNSUPPORTED_CHAIN_ID\",\n `handleErc20Transfer: unsupported chainId ${request.chainId}`,\n { requested: request.chainId, supported: this.chainId },\n );\n }\n if (request.amount <= 0n) {\n throw new ValidationError(\n \"ZERO_AMOUNT\",\n \"handleErc20Transfer: amount must be positive\",\n );\n }\n\n const userAddress = getAddress(request.userAddress);\n const tokenAddress = getAddress(request.tokenAddress);\n const recipient = getAddress(request.recipient);\n\n const addrs = getContractAddresses(request.chainId);\n const pafiFeeRecipient = addrs.pafiFeeRecipient;\n\n // Recipient block list — surfaces fast in FE before the sponsor\n // relayer rejects the same payload server-side.\n if (recipient.toLowerCase() === pafiFeeRecipient.toLowerCase()) {\n throw new ValidationError(\n \"SELF_FEE_ABUSE\",\n \"handleErc20Transfer: recipient cannot be the PAFI fee recipient\",\n { recipient, pafiFeeRecipient },\n );\n }\n if (recipient === \"0x0000000000000000000000000000000000000000\") {\n throw new ValidationError(\n \"USE_BURN_SCENARIO\",\n \"handleErc20Transfer: recipient cannot be the zero address — use the burn scenario instead\",\n );\n }\n\n // Stable-coin fast path (USDC + USDT are unconditionally allowed).\n // For non-stables, the caller (issuer-backend or controller layer)\n // is responsible for verifying the token is an active PointToken\n // via IssuerRegistry. The sponsor-relayer re-checks server-side, so\n // an unchecked PT here just gets rejected at submit time — fail\n // closed, not open.\n const isStable =\n (addrs.usdc &&\n tokenAddress.toLowerCase() === addrs.usdc.toLowerCase()) ||\n tokenAddress.toLowerCase() === addrs.usdt.toLowerCase();\n\n // Auto-quote fee unless overridden. Pass-through stale-fallback opt-in\n // so dev/staging callers can survive oracle hiccups while production\n // defaults to fail-loud.\n let feeAmount: bigint;\n if (request.feeAmount !== undefined) {\n feeAmount = request.feeAmount > 0n ? request.feeAmount : 0n;\n } else {\n feeAmount = await quoteOperatorFeeForTransfer({\n provider: this.provider,\n chainId: request.chainId,\n tokenAddress,\n allowStaleFallback: request.allowStaleFallback,\n fallbackEthPriceUsd: request.fallbackEthPriceUsd,\n fallbackPtPriceUsdt: request.fallbackPtPriceUsdt,\n });\n }\n\n if (feeAmount > 0n && feeAmount >= request.amount) {\n throw new ValidationError(\n \"INVALID_AMOUNT\",\n `handleErc20Transfer: fee (${feeAmount}) must be strictly less than amount (${request.amount})`,\n { feeAmount, amount: request.amount },\n );\n }\n\n const userOp = buildErc20TransferUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n tokenAddress,\n recipient,\n amount: request.amount,\n feeAmount: feeAmount > 0n ? feeAmount : undefined,\n feeRecipient: feeAmount > 0n ? pafiFeeRecipient : undefined,\n });\n\n // Fallback variant emitted only when there IS a fee to strip —\n // matches the perp-deposit + swap response shape.\n const userOpFallback =\n feeAmount > 0n\n ? buildErc20TransferUserOp({\n userAddress,\n aaNonce: request.aaNonce,\n tokenAddress,\n recipient,\n amount: request.amount,\n // No feeAmount → 1-call variant (transfer only).\n })\n : undefined;\n\n // Quiet `isStable` \"unused\" warning while preserving the on-chain\n // semantic comment above — actual whitelist enforcement is\n // server-side (sponsor-relayer + issuer-backend).\n void isStable;\n\n return {\n userOp,\n userOpFallback,\n feeAmountUsed: feeAmount,\n feeRecipient: pafiFeeRecipient,\n tokenAddress,\n };\n }\n}\n\n/**\n * `addresses.ts` uses `0x000…<suffix>` sentinels for chains where a\n * given contract is not yet deployed. Detect them by upper-160-bits =\n * 0 so we route to the Vault fallback automatically.\n */\nfunction isPlaceholderAddress(addr: Address): boolean {\n return /^0x0{36}[0-9a-fA-F]{4}$/i.test(addr);\n}\n\n/**\n * Quote the operator gas fee in OUTPUT token raw units. Picks the right\n * underlying quoter:\n *\n * - Output is USDT (canonical address from `getContractAddresses`):\n * `quoteOperatorFeeUsdt` — pure Chainlink ETH/USD, no V4 hop.\n * - Output is anything else (PT0, PT1, ...): `quoteOperatorFeePt`\n * against the output token's V4 pool.\n *\n * Used by `handleQuote` (display the user-facing net output) and\n * `handleSwap` (auto-quote when caller didn't override\n * `gasFeeAmountOutput`).\n */\nasync function quoteOperatorFeeOutput(\n provider: PublicClient,\n chainId: number,\n outputTokenAddress: Address,\n): Promise<bigint> {\n const { usdt } = getContractAddresses(chainId);\n if (\n usdt &&\n getAddress(outputTokenAddress) === getAddress(usdt as Address)\n ) {\n return quoteOperatorFeeUsdt({ provider, chainId });\n }\n return quoteOperatorFeePt({\n provider,\n chainId,\n pointTokenAddress: outputTokenAddress,\n });\n}\n\n/**\n * Quote the operator gas fee in INPUT token raw units. Same dispatch\n * logic as `quoteOperatorFeeOutput` but reads `inputTokenAddress` —\n * used by the exact-output handlers, where the operator fee is charged\n * input-side (pre-swap) so the user receives a precise output amount.\n */\nasync function quoteOperatorFeeInput(\n provider: PublicClient,\n chainId: number,\n inputTokenAddress: Address,\n): Promise<bigint> {\n const { usdt } = getContractAddresses(chainId);\n if (\n usdt &&\n getAddress(inputTokenAddress) === getAddress(usdt as Address)\n ) {\n return quoteOperatorFeeUsdt({ provider, chainId });\n }\n return quoteOperatorFeePt({\n provider,\n chainId,\n pointTokenAddress: inputTokenAddress,\n });\n}\n","import type { Address } from \"viem\";\nimport type { PoolKey, V3Path } from \"@pafi-dev/core\";\nimport { COMMON_POOLS, POINT_TOKEN_POOLS } from \"@pafi-dev/core\";\n\n/**\n * Combine point-token-specific pools and common pools for a given chain.\n * Point token pools are listed first so callers can prioritise them.\n */\nexport function combineRoutes(\n chainId: number,\n pointTokenAddress: Address,\n): PoolKey[] {\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const pointPools = POINT_TOKEN_POOLS[chainId]?.[pointTokenAddress] ?? [];\n return [...pointPools, ...commonPools];\n}\n\n/**\n * Build all possible V3 swap paths from `tokenIn` to `tokenOut` using\n * the given pools. Returns an array of `V3Path` routes (each up to\n * `maxHops` hops, in canonical input→output orientation).\n *\n * Supports both direct single-hop routes and multi-hop routes through\n * intermediate tokens. Each pool is used at most once per path.\n *\n * @param pools - Available pools to route through\n * @param tokenIn - Input token address\n * @param tokenOut - Desired output token address\n * @param maxHops - Maximum number of hops (default 3)\n */\nexport function buildAllPaths(\n pools: PoolKey[],\n tokenIn: Address,\n tokenOut: Address,\n maxHops = 3,\n): V3Path[] {\n const results: V3Path[] = [];\n\n function dfs(\n currentToken: Address,\n tokens: Address[],\n fees: number[],\n usedPoolIndices: Set<number>,\n ) {\n // tokens.length - 1 is the number of hops accumulated so far.\n const hopsSoFar = tokens.length - 1;\n if (hopsSoFar > maxHops) return;\n\n if (\n hopsSoFar > 0 &&\n currentToken.toLowerCase() === tokenOut.toLowerCase()\n ) {\n results.push({ tokens: [...tokens], fees: [...fees] });\n return;\n }\n\n for (let i = 0; i < pools.length; i++) {\n if (usedPoolIndices.has(i)) continue;\n\n const pool = pools[i]!;\n const t0 = pool.token0.toLowerCase();\n const t1 = pool.token1.toLowerCase();\n const curr = currentToken.toLowerCase();\n\n let nextToken: Address | null = null;\n if (curr === t0) {\n nextToken = pool.token1 as Address;\n } else if (curr === t1) {\n nextToken = pool.token0 as Address;\n }\n\n if (!nextToken) continue;\n\n usedPoolIndices.add(i);\n tokens.push(nextToken);\n fees.push(pool.fee);\n dfs(nextToken, tokens, fees, usedPoolIndices);\n tokens.pop();\n fees.pop();\n usedPoolIndices.delete(i);\n }\n }\n\n dfs(tokenIn, [tokenIn], [], new Set());\n return results;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type {\n BestQuote,\n ExactOutputBestQuote,\n ExactOutputQuoteResult,\n PoolKey,\n QuoteResult,\n V3Path,\n} from \"@pafi-dev/core\";\nimport {\n COMMON_POOLS,\n QUOTER_V2_ADDRESSES,\n encodeV3Path,\n encodeV3PathReversed,\n v3QuoterV2Abi,\n} from \"@pafi-dev/core\";\nimport { buildAllPaths } from \"./routes\";\n\n// =========================================================================\n// V3 QuoterV2 wrappers\n// =========================================================================\n//\n// QuoterV2 returns a 4-tuple\n// `(amountOut, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate)`\n// for multi-hop and a 4-tuple\n// `(amountOut, sqrtPriceX96After, initializedTicksCrossed, gasEstimate)`\n// for single-hop. The wrappers below collapse to `{amountOut, gasEstimate}`\n// for API parity with the previous V4-Quoter shape. Callers needing the\n// sqrt-price / ticks-crossed signals must read the raw ABI directly.\n// =========================================================================\n\n/**\n * Quote exact-input for a multi-hop V3 path.\n *\n * `path` is in canonical input→output orientation; the encoder produces\n * `tokens[0] ‖ fees[0] ‖ tokens[1] ‖ ... ‖ tokens[N]` packed bytes.\n */\nexport async function quoteExactInput(\n client: PublicClient,\n quoterAddress: Address,\n path: V3Path,\n exactAmount: bigint,\n): Promise<QuoteResult> {\n const pathBytes = encodeV3Path(path);\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInput\",\n args: [pathBytes, exactAmount],\n })) as readonly [bigint, readonly bigint[], readonly number[], bigint];\n const [amountOut, , , gasEstimate] = result;\n\n return { amountOut, gasEstimate, path };\n}\n\n/**\n * Quote exact-input for a single-hop V3 swap, given an explicit pool\n * and direction. `sqrtPriceLimitX96 = 0n` disables the price-limit\n * guard (the on-chain \"no limit\" sentinel).\n */\nexport async function quoteExactInputSingle(\n client: PublicClient,\n quoterAddress: Address,\n tokenIn: Address,\n tokenOut: Address,\n fee: number,\n exactAmount: bigint,\n sqrtPriceLimitX96: bigint = 0n,\n): Promise<{ amountOut: bigint; gasEstimate: bigint }> {\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn,\n tokenOut,\n amountIn: exactAmount,\n fee,\n sqrtPriceLimitX96,\n },\n ],\n })) as readonly [bigint, bigint, number, bigint];\n const [amountOut, , , gasEstimate] = result;\n\n return { amountOut, gasEstimate };\n}\n\n/**\n * Try multiple V3Path routes and return the best quote plus all results.\n * Routes that fail (e.g. pool does not exist, insufficient liquidity)\n * are silently skipped. The first failure reason is included in the\n * error message when EVERY route fails.\n *\n * Uses viem multicall to batch all quotes into a single RPC call.\n */\nexport async function quoteBestRoute(\n client: PublicClient,\n quoterAddress: Address,\n routes: V3Path[],\n exactAmount: bigint,\n): Promise<BestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactInput\" as const,\n args: [encodeV3Path(path), exactAmount] as const,\n })),\n allowFailure: true,\n });\n\n const allRoutes: QuoteResult[] = [];\n let firstFailure: string | undefined;\n for (let i = 0; i < results.length; i++) {\n const r = results[i]!;\n if (r.status === \"success\") {\n const tuple = r.result as unknown as readonly [\n bigint,\n readonly bigint[],\n readonly number[],\n bigint,\n ];\n if (!Array.isArray(tuple) || tuple.length < 4) {\n if (firstFailure === undefined) {\n const len = Array.isArray(tuple) ? tuple.length : \"n/a\";\n firstFailure = `unexpected QuoterV2 return shape (length=${len})`;\n }\n continue;\n }\n const [amountOut, , , gasEstimate] = tuple;\n allRoutes.push({ amountOut, gasEstimate, path: routes[i]! });\n } else if (firstFailure === undefined) {\n const errMsg =\n r.error instanceof Error\n ? r.error.message\n : String((r as { error?: unknown }).error ?? \"unknown\");\n firstFailure = errMsg;\n }\n }\n\n if (allRoutes.length === 0) {\n throw new Error(\n `No valid routes found (${routes.length} candidates probed)` +\n (firstFailure ? `; first failure: ${firstFailure}` : \"\"),\n );\n }\n\n const bestRoute = allRoutes.reduce((best, current) =>\n current.amountOut > best.amountOut ? current : best,\n );\n\n return { bestRoute, allRoutes };\n}\n\n/**\n * Find and quote the best V3 swap route from `tokenIn` to `tokenOut`.\n *\n * Combines the caller's `pools` with `COMMON_POOLS[chainId]`, builds all\n * possible paths (up to `maxHops`), then quotes them all via a single\n * multicall and returns the best result.\n *\n * @param client - viem PublicClient\n * @param chainId - Chain ID (used to look up COMMON_POOLS and QUOTER_V2_ADDRESSES)\n * @param tokenIn - Input token address\n * @param tokenOut - Desired output token address\n * @param exactAmount - Exact input amount\n * @param pools - Additional pools to consider (e.g. point-token-specific)\n * @param quoterAddress - Override the default V3 QuoterV2 address for this chain\n * @param maxHops - Maximum number of hops per path (default 3)\n */\nexport async function findBestQuote(\n client: PublicClient,\n chainId: number,\n tokenIn: Address,\n tokenOut: Address,\n exactAmount: bigint,\n pools: PoolKey[] = [],\n quoterAddress?: Address,\n maxHops = 3,\n): Promise<BestQuote> {\n const quoter = quoterAddress ?? QUOTER_V2_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V3 QuoterV2 address configured for chain ${chainId}`);\n }\n\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const allPools = [...pools, ...commonPools];\n const paths = buildAllPaths(allPools, tokenIn, tokenOut, maxHops);\n\n if (paths.length === 0) {\n throw new Error(`No paths found from ${tokenIn} to ${tokenOut}`);\n }\n\n return quoteBestRoute(client, quoter, paths, exactAmount);\n}\n\n// =========================================================================\n// V3 exact-output quoting\n// =========================================================================\n//\n// CAUTION: the on-chain `quoteExactOutput` walks the path output→input.\n// Callers of this SDK should pass paths in canonical input→output\n// orientation; the encoder reverses internally.\n// =========================================================================\n\n/**\n * Quote V3 exact-output for a multi-hop path.\n *\n * @param path - V3Path in canonical input→output orientation.\n * The encoder reverses for the on-chain call.\n * @param exactAmount - Exact OUTPUT amount the user wants to receive.\n * @returns `{ amountIn, gasEstimate, path }` — the input amount required.\n */\nexport async function quoteExactOutput(\n client: PublicClient,\n quoterAddress: Address,\n path: V3Path,\n exactAmount: bigint,\n): Promise<ExactOutputQuoteResult> {\n const pathBytes = encodeV3PathReversed(path);\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutput\",\n args: [pathBytes, exactAmount],\n })) as readonly [bigint, readonly bigint[], readonly number[], bigint];\n const [amountIn, , , gasEstimate] = result;\n\n return { amountIn, gasEstimate, path };\n}\n\n/**\n * Quote V3 exact-output for a single-hop swap, given an explicit\n * `tokenIn`/`tokenOut`/`fee` triple.\n */\nexport async function quoteExactOutputSingle(\n client: PublicClient,\n quoterAddress: Address,\n tokenIn: Address,\n tokenOut: Address,\n fee: number,\n exactAmount: bigint,\n sqrtPriceLimitX96: bigint = 0n,\n): Promise<{ amountIn: bigint; gasEstimate: bigint }> {\n const result = (await client.readContract({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutputSingle\",\n args: [\n {\n tokenIn,\n tokenOut,\n amount: exactAmount,\n fee,\n sqrtPriceLimitX96,\n },\n ],\n })) as readonly [bigint, bigint, number, bigint];\n const [amountIn, , , gasEstimate] = result;\n\n return { amountIn, gasEstimate };\n}\n\n/**\n * Try multiple V3Path routes for an exact-output swap and return the\n * route requiring the **smallest** input amount, plus all results.\n * Routes that fail are silently skipped.\n */\nexport async function quoteBestRouteExactOut(\n client: PublicClient,\n quoterAddress: Address,\n routes: V3Path[],\n exactAmount: bigint,\n): Promise<ExactOutputBestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v3QuoterV2Abi,\n functionName: \"quoteExactOutput\" as const,\n args: [encodeV3PathReversed(path), exactAmount] as const,\n })),\n allowFailure: true,\n });\n\n const allRoutes: ExactOutputQuoteResult[] = [];\n let firstFailure: string | undefined;\n for (let i = 0; i < results.length; i++) {\n const r = results[i]!;\n if (r.status === \"success\") {\n const tuple = r.result as unknown as readonly [\n bigint,\n readonly bigint[],\n readonly number[],\n bigint,\n ];\n if (!Array.isArray(tuple) || tuple.length < 4) {\n if (firstFailure === undefined) {\n const len = Array.isArray(tuple) ? tuple.length : \"n/a\";\n firstFailure = `unexpected QuoterV2 return shape (length=${len})`;\n }\n continue;\n }\n const [amountIn, , , gasEstimate] = tuple;\n allRoutes.push({ amountIn, gasEstimate, path: routes[i]! });\n } else if (firstFailure === undefined) {\n const errMsg =\n r.error instanceof Error\n ? r.error.message\n : String((r as { error?: unknown }).error ?? \"unknown\");\n firstFailure = errMsg;\n }\n }\n\n if (allRoutes.length === 0) {\n throw new Error(\n `No valid exact-output routes found (${routes.length} candidates probed)` +\n (firstFailure ? `; first failure: ${firstFailure}` : \"\"),\n );\n }\n\n const bestRoute = allRoutes.reduce((best, current) =>\n current.amountIn < best.amountIn ? current : best,\n );\n\n return { bestRoute, allRoutes };\n}\n\n/**\n * Find and quote the best V3 exact-output route from `tokenIn` to\n * `tokenOut` for a desired output amount.\n *\n * Symmetric to `findBestQuote` but `exactAmount` is denominated in\n * `tokenOut` (the OUTPUT token). Paths are enumerated input→output (the\n * canonical SDK orientation) — the QuoterV2 wrapper reverses for the\n * on-chain call.\n *\n * @param client - viem PublicClient.\n * @param chainId - Chain ID (looks up COMMON_POOLS + QUOTER_V2_ADDRESSES).\n * @param tokenIn - Input token address (what user pays).\n * @param tokenOut - Output token address (what user wants exactly).\n * @param exactAmount - Exact OUTPUT amount.\n * @param pools - Additional pools (e.g. point-token-specific).\n * @param quoterAddress - Override the default V3 QuoterV2 address.\n * @param maxHops - Maximum number of hops per path (default 3).\n */\nexport async function findBestQuoteExactOut(\n client: PublicClient,\n chainId: number,\n tokenIn: Address,\n tokenOut: Address,\n exactAmount: bigint,\n pools: PoolKey[] = [],\n quoterAddress?: Address,\n maxHops = 3,\n): Promise<ExactOutputBestQuote> {\n const quoter = quoterAddress ?? QUOTER_V2_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V3 QuoterV2 address configured for chain ${chainId}`);\n }\n\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const allPools = [...pools, ...commonPools];\n\n const paths = buildAllPaths(allPools, tokenIn, tokenOut, maxHops);\n\n if (paths.length === 0) {\n throw new Error(\n `No exact-output paths found from ${tokenIn} to ${tokenOut}`,\n );\n }\n\n return quoteBestRouteExactOut(client, quoter, paths, exactAmount);\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex, PublicClient } from \"viem\";\nimport { erc20Abi } from \"@pafi-dev/core\";\nimport { permit2Abi } from \"@pafi-dev/core\";\n\nexport async function checkAllowance(\n client: PublicClient,\n token: Address,\n owner: Address,\n spender: Address,\n): Promise<bigint> {\n return client.readContract({\n address: token,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner, spender],\n });\n}\n\n/**\n * Encode an ERC-20 approve(spender, amount) call.\n */\nexport function buildErc20ApprovalCalldata(\n spender: Address,\n amount: bigint,\n): Hex {\n return encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n });\n}\n\n/**\n * Encode a Permit2 approve(token, spender, amount, expiration) call.\n */\nexport function buildPermit2ApprovalCalldata(\n token: Address,\n spender: Address,\n amount: bigint,\n expiration: number,\n): Hex {\n return encodeFunctionData({\n abi: permit2Abi,\n functionName: \"approve\",\n args: [token, spender, amount, expiration],\n });\n}\n","import { encodeAbiParameters, encodePacked } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { encodeV3Path, encodeV3PathReversed, type V3Path } from \"@pafi-dev/core\";\n\n// -------------------------------------------------------------------------\n// V3 UniversalRouter command constants\n// Reference: https://github.com/Uniswap/universal-router/blob/main/contracts/libraries/Commands.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V3 exact-input swap. */\nexport const V3_SWAP_EXACT_IN = 0x00 as const;\n\n/** UniversalRouter command byte for V3 exact-output swap. */\nexport const V3_SWAP_EXACT_OUT = 0x01 as const;\n\n/** Max value of a uint128 — used to guard exact-out `maxAmountIn` and `amountOut`. */\nconst UINT128_MAX = 2n ** 128n - 1n;\n\n// -------------------------------------------------------------------------\n// V3 swap input encoding (V3_SWAP_EXACT_IN / V3_SWAP_EXACT_OUT)\n//\n// Universal Router input layout for V3 swaps:\n// abi.encode(\n// address recipient,\n// uint256 amountIn / amountOut,\n// uint256 amountOutMinimum / amountInMaximum,\n// bytes path,\n// bool payerIsUser,\n// )\n//\n// `payerIsUser = true` instructs the router to pull tokens from the user\n// via Permit2 (the only path the SDK supports). Setting it to `false`\n// would make the router spend its own balance — relevant for chained\n// swaps and not applicable here.\n// -------------------------------------------------------------------------\n\nconst V3_EXACT_IN_INPUT_ABI = [\n { name: \"recipient\", type: \"address\" },\n { name: \"amountIn\", type: \"uint256\" },\n { name: \"amountOutMinimum\", type: \"uint256\" },\n { name: \"path\", type: \"bytes\" },\n { name: \"payerIsUser\", type: \"bool\" },\n] as const;\n\nconst V3_EXACT_OUT_INPUT_ABI = [\n { name: \"recipient\", type: \"address\" },\n { name: \"amountOut\", type: \"uint256\" },\n { name: \"amountInMaximum\", type: \"uint256\" },\n { name: \"path\", type: \"bytes\" },\n { name: \"payerIsUser\", type: \"bool\" },\n] as const;\n\n/**\n * Build the calldata `inputs[0]` payload for the `V3_SWAP_EXACT_IN`\n * command. Path bytes are packed input→output; the router walks the\n * same direction.\n */\nexport function buildV3SwapInputExactIn(\n recipient: Address,\n path: V3Path,\n amountIn: bigint,\n minAmountOut: bigint,\n): Hex {\n if (amountIn <= 0n || amountIn > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactIn: amountIn (${amountIn}) must be in (0, 2^128-1]`,\n );\n }\n if (minAmountOut < 0n) {\n throw new Error(\n `buildV3SwapInputExactIn: minAmountOut (${minAmountOut}) must be non-negative`,\n );\n }\n\n const pathBytes = encodeV3Path(path);\n\n return encodeAbiParameters(V3_EXACT_IN_INPUT_ABI, [\n recipient,\n amountIn,\n minAmountOut,\n pathBytes,\n true, // payerIsUser — router pulls via Permit2 (the SDK's only flow)\n ]);\n}\n\n/**\n * Build the calldata `inputs[0]` payload for the `V3_SWAP_EXACT_OUT`\n * command. Path bytes are packed output→input — the router walks the\n * desired output back to the input, taking only as much input as needed\n * (capped by `maxAmountIn`).\n *\n * The `path` argument is in canonical input→output orientation; the\n * encoder reverses internally so callers don't have to reason about\n * direction.\n */\nexport function buildV3SwapInputExactOut(\n recipient: Address,\n path: V3Path,\n amountOut: bigint,\n maxAmountIn: bigint,\n): Hex {\n if (amountOut <= 0n || amountOut > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactOut: amountOut (${amountOut}) must be in (0, 2^128-1]`,\n );\n }\n if (maxAmountIn <= 0n || maxAmountIn > UINT128_MAX) {\n throw new Error(\n `buildV3SwapInputExactOut: maxAmountIn (${maxAmountIn}) must be in (0, 2^128-1]`,\n );\n }\n\n const pathBytes = encodeV3PathReversed(path);\n\n return encodeAbiParameters(V3_EXACT_OUT_INPUT_ABI, [\n recipient,\n amountOut,\n maxAmountIn,\n pathBytes,\n true, // payerIsUser\n ]);\n}\n\n/**\n * Build the full `commands` + `inputs` args for `UniversalRouter.execute`\n * for an exact-input V3 swap.\n */\nexport function buildUniversalRouterExecuteArgs(\n recipient: Address,\n path: V3Path,\n amountIn: bigint,\n minAmountOut: bigint,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V3_SWAP_EXACT_IN]);\n const inputs: Hex[] = [\n buildV3SwapInputExactIn(recipient, path, amountIn, minAmountOut),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build the full `commands` + `inputs` args for `UniversalRouter.execute`\n * for an exact-output V3 swap.\n */\nexport function buildUniversalRouterExecuteArgsExactOut(\n recipient: Address,\n path: V3Path,\n amountOut: bigint,\n maxAmountIn: bigint,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V3_SWAP_EXACT_OUT]);\n const inputs: Hex[] = [\n buildV3SwapInputExactOut(recipient, path, amountOut, maxAmountIn),\n ];\n return { commands, inputs };\n}\n","import type { Address, Hex, PublicClient } from \"viem\";\nimport { universalRouterAbi } from \"@pafi-dev/core\";\nimport { SimulationError } from \"@pafi-dev/core\";\n\nexport interface SwapSimulationResult {\n success: boolean;\n gasEstimate: bigint;\n}\n\n/**\n * Simulate a UniversalRouter.execute swap call via eth_call (no gas spent).\n *\n * Runs the full V4 swap flow — token transfer via Permit2, swap via\n * PoolManager, output settlement — without submitting a transaction.\n * If the simulation reverts, throws a `SimulationError` with the reason.\n *\n * @param client - viem PublicClient\n * @param routerAddress - UniversalRouter contract address\n * @param commands - Packed command bytes (from buildSwapFromQuote)\n * @param inputs - Encoded inputs per command (from buildSwapFromQuote)\n * @param deadline - Unix timestamp after which the tx expires\n * @param from - Address that will execute the swap\n */\nexport async function simulateSwap(\n client: PublicClient,\n routerAddress: Address,\n commands: Hex,\n inputs: Hex[],\n deadline: bigint,\n from: Address,\n): Promise<SwapSimulationResult> {\n try {\n const gasEstimate = await client.estimateContractGas({\n address: routerAddress,\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, deadline],\n account: from,\n });\n\n return { success: true, gasEstimate };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Unknown simulation error\";\n throw new SimulationError(\"swap\", message);\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport {\n PERMIT2_ADDRESS,\n buildPartialUserOperation,\n erc20ApproveOp,\n erc20TransferOp,\n rawCallOp,\n universalRouterAbi,\n type Operation,\n type PartialUserOperation,\n type V3Path,\n} from \"@pafi-dev/core\";\nimport {\n buildUniversalRouterExecuteArgs,\n buildUniversalRouterExecuteArgsExactOut,\n} from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\n\n/**\n * v0.5 — Generalized swap UserOp builder. Direction-agnostic: works\n * for **any** ERC-20 → ERC-20 pair routable through PAFI's V3 pools:\n *\n * - PT → USDT (cashout)\n * - USDT → PT (buy PT with USDT)\n * - PT0 → PT1 (same-issuer multi-token swap; routes via USDT)\n *\n * UserOp shape (atomic batch via EIP-7702 BatchExecutor):\n *\n * 1. `inputToken.approve(Permit2, amountIn)` — exactly the swap amount.\n * 2. `Permit2.approve(inputToken, router, amountIn, deadline)` — Permit2\n * authorization to UniversalRouter.\n * 3. `UniversalRouter.execute(commands, inputs, deadline)` — V3 swap\n * `inputToken → outputToken`; user receives ≥ `minAmountOut`.\n * 4. `outputToken.transfer(feeRecipient, gasFeeAmountOutput)` —\n * operator gas reimbursement, paid in OUTPUT token (omitted when 0).\n *\n * ## Fee model — output-token strategy (token-availability rule)\n *\n * Fee is charged in the **output token** AFTER the swap, because the\n * user holds output token at that point in the batch. Three benefits:\n *\n * - User holds exactly `amountIn` of input token (FE quote = chain\n * reality). No \"you need 1010 to swap 1000\" UX surprise.\n * - Quote API returns `outputNet = outputGross - feeOutput` directly,\n * matching what user actually receives.\n * - PT → USDT: PAFI receives USDT (universally liquid, clean accounting).\n *\n * Caller MUST ensure `minAmountOut >= gasFeeAmountOutput` (fee transfer\n * reverts otherwise → whole batch reverts).\n *\n * ## Pool-level fees\n *\n * PAFI's PT pools are standard Uniswap V3 — no swap-time hooks. The\n * protocol's gas-recoupment fee lives in `MintFeeWrapper` on the mint\n * path; the only pool-level economics here are Uniswap's regular LP\n * fee tier (per the PoolKey's `fee` field), already baked into the\n * quote returned by `findBestQuote`. This builder doesn't apply or\n * model any additional swap-time fee on top.\n */\nexport interface BuildSwapUserOpParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Token being spent — approved to Permit2 + UniversalRouter. */\n inputTokenAddress: Address;\n /** Token user receives. */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** Input token units to swap. User must hold exactly this much input token. */\n amountIn: bigint;\n /**\n * Minimum output (gross) to accept from the swap. Caller applies\n * slippage against a fresh quote. MUST be ≥ `gasFeeAmountOutput` or\n * the post-swap fee transfer reverts.\n */\n minAmountOut: bigint;\n\n /**\n * V3 swap path. `tokens.length === fees.length + 1`. Get this from\n * `findBestQuote().bestRoute.path`. Single-hop has 2 tokens + 1 fee;\n * multi-hop has N+1 tokens + N fees.\n */\n swapPath: V3Path;\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /**\n * Operator gas-reimbursement fee — paid in OUTPUT token. Omitted\n * from the batch when 0n. Caller quotes this via `quoteOperatorFee*`\n * helpers (USDT/PT depending on output token).\n *\n * v0.3 — switched from input-side fee (v0.2 `gasFeeAmount`) to\n * output-side fee. See \"Fee model\" comment above.\n */\n gasFeeAmountOutput: bigint;\n /**\n * Where the gas fee lands — typically the canonical PAFI fee\n * recipient from `getContractAddresses(chainId).pafiFeeRecipient`.\n */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for the generalized swap flow.\n *\n * @throws when `amountIn` is non-positive, `gasFeeAmountOutput` is\n * negative, `swapPath` is empty, or `minAmountOut < gasFeeAmountOutput`.\n */\nexport function buildSwapUserOp(\n params: BuildSwapUserOpParams,\n): PartialUserOperation {\n if (params.amountIn <= 0n) {\n throw new Error(\"buildSwapUserOp: amountIn must be positive\");\n }\n if (params.minAmountOut < 0n) {\n throw new Error(\"buildSwapUserOp: minAmountOut must be non-negative\");\n }\n if (params.gasFeeAmountOutput < 0n) {\n throw new Error(\"buildSwapUserOp: gasFeeAmountOutput must be non-negative\");\n }\n if (\n params.gasFeeAmountOutput > 0n &&\n params.minAmountOut < params.gasFeeAmountOutput\n ) {\n throw new Error(\n \"buildSwapUserOp: minAmountOut must be >= gasFeeAmountOutput so the post-swap fee transfer cannot revert\",\n );\n }\n if (params.swapPath.tokens.length < 2 || params.swapPath.fees.length < 1) {\n throw new Error(\n \"buildSwapUserOp: swapPath must contain at least one hop (>=2 tokens, >=1 fee)\",\n );\n }\n if (params.swapPath.tokens.length !== params.swapPath.fees.length + 1) {\n throw new Error(\n \"buildSwapUserOp: swapPath.tokens.length must equal swapPath.fees.length + 1\",\n );\n }\n // Assert deadline fits Permit2's uint48 expiration field (max 2^48 - 1\n // ≈ year 8,921,478 in unix seconds). Catches the common bug where a\n // caller passes deadline in milliseconds; also guards against any\n // future caller passing > 2^53 (Number cast lossy).\n const PERMIT2_EXPIRATION_MAX = 2n ** 48n - 1n;\n if (params.deadline <= 0n || params.deadline > PERMIT2_EXPIRATION_MAX) {\n throw new Error(\n `buildSwapUserOp: deadline (${params.deadline}) must be unix seconds in (0, 2^48-1]. ` +\n `Did you accidentally pass milliseconds?`,\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgs(\n params.userAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n // Approve only the swap amount — fee comes out of swap proceeds.\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.inputTokenAddress,\n params.universalRouterAddress,\n params.amountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [\n erc20ApproveOp(params.inputTokenAddress, PERMIT2_ADDRESS, params.amountIn),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n ];\n\n // Fee transfer in OUTPUT token, AFTER swap, when user holds output.\n if (params.gasFeeAmountOutput > 0n) {\n operations.push(\n erc20TransferOp(\n params.outputTokenAddress,\n params.feeRecipient,\n params.gasFeeAmountOutput,\n ),\n );\n }\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 700_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n\n// =========================================================================\n// V3 exact-output swap UserOp builder\n// =========================================================================\n//\n// Symmetric to `buildSwapUserOp` but for the exact-output flow. Two\n// design choices that diverge:\n//\n// 1. Operation order — fee transfer goes FIRST (pre-swap, in INPUT\n// token). At post-swap time the user receives *exactly* `amountOut`\n// of output; charging an output-side fee would silently break the\n// \"exact output\" guarantee. Mirrors the v0.3 input-side fee pattern\n// used by perp-deposit (Relay path).\n//\n// 2. Permit2 + ERC-20 approvals cover `maxAmountIn` (cap), not the\n// exact pull. V3's exact-output router pulls only the amount the\n// swap actually consumed and reverts if it would exceed the cap.\n//\n// Caller pre-conditions (none enforced on chain — caller must arrange):\n//\n// - User holds at least `maxAmountIn + gasFeeAmountInput` of input token.\n// - `maxAmountIn` already includes the slippage cushion the caller\n// wants (recommended: `maxAmountIn = ceil(estimatedInputAmount *\n// (10000 + slippageBps) / 10000)`).\n//\n// =========================================================================\n\n/**\n * Parameters for `buildSwapUserOpExactOut`.\n *\n * @remarks\n * The user must hold **`maxAmountIn + gasFeeAmountInput`** of\n * `inputTokenAddress` before this UserOp executes — the operator-fee\n * transfer is pre-swap, so it cannot be paid from swap proceeds.\n */\nexport interface BuildSwapUserOpExactOutParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Token being spent — approved to Permit2 + UniversalRouter. */\n inputTokenAddress: Address;\n /** Token user receives (exactly `amountOut` of). */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** Exact OUTPUT token amount the user wants to receive. */\n amountOut: bigint;\n /**\n * Maximum INPUT token amount the user is willing to spend on the swap\n * (slippage cap). The Permit2 approval covers this amount; the swap\n * settles only the actual amount consumed.\n */\n maxAmountIn: bigint;\n\n /**\n * V3 swap path in canonical **input→output** orientation. The encoder\n * reverses internally for the on-chain exact-output Router call.\n * Get this from `findBestQuoteExactOut().bestRoute.path`.\n */\n swapPath: V3Path;\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /**\n * Operator gas-reimbursement fee — paid in INPUT token, transferred\n * BEFORE the swap. Omitted from the batch when 0n.\n *\n * Charged input-side rather than output-side because exact-output\n * promises the user a precise output amount; deducting from output\n * would silently break that promise. Mirrors the v0.3 input-side fee\n * pattern used by perp-deposit.\n */\n gasFeeAmountInput: bigint;\n /**\n * Where the gas fee lands — typically the canonical PAFI fee\n * recipient from `getContractAddresses(chainId).pafiFeeRecipient`.\n */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for the V3 exact-output swap flow.\n *\n * UserOp shape (atomic batch via EIP-7702 BatchExecutor):\n *\n * 1. `inputToken.transfer(feeRecipient, gasFeeAmountInput)` — operator\n * gas reimbursement, paid in INPUT token (omitted when 0).\n * 2. `inputToken.approve(Permit2, maxAmountIn)` — cap, not exact.\n * 3. `Permit2.approve(inputToken, router, maxAmountIn, deadline)` —\n * Permit2 authorization to UniversalRouter for up to `maxAmountIn`.\n * 4. `UniversalRouter.execute(commands, inputs, deadline)` — V3\n * exact-output swap; user receives exactly `amountOut`.\n *\n * @throws when `amountOut`/`maxAmountIn` are non-positive,\n * `gasFeeAmountInput` is negative, `swapPath` is malformed, or\n * `deadline` is out of Permit2's uint48 range.\n */\nexport function buildSwapUserOpExactOut(\n params: BuildSwapUserOpExactOutParams,\n): PartialUserOperation {\n if (params.amountOut <= 0n) {\n throw new Error(\"buildSwapUserOpExactOut: amountOut must be positive\");\n }\n if (params.maxAmountIn <= 0n) {\n throw new Error(\"buildSwapUserOpExactOut: maxAmountIn must be positive\");\n }\n if (params.gasFeeAmountInput < 0n) {\n throw new Error(\n \"buildSwapUserOpExactOut: gasFeeAmountInput must be non-negative\",\n );\n }\n if (params.swapPath.tokens.length < 2 || params.swapPath.fees.length < 1) {\n throw new Error(\n \"buildSwapUserOpExactOut: swapPath must contain at least one hop (>=2 tokens, >=1 fee)\",\n );\n }\n if (params.swapPath.tokens.length !== params.swapPath.fees.length + 1) {\n throw new Error(\n \"buildSwapUserOpExactOut: swapPath.tokens.length must equal swapPath.fees.length + 1\",\n );\n }\n // Same Permit2-uint48 deadline check as buildSwapUserOp.\n const PERMIT2_EXPIRATION_MAX = 2n ** 48n - 1n;\n if (params.deadline <= 0n || params.deadline > PERMIT2_EXPIRATION_MAX) {\n throw new Error(\n `buildSwapUserOpExactOut: deadline (${params.deadline}) must be unix seconds in (0, 2^48-1]. ` +\n `Did you accidentally pass milliseconds?`,\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgsExactOut(\n params.userAddress,\n params.swapPath,\n params.amountOut,\n params.maxAmountIn,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n // Approve up to maxAmountIn — swap settles only the actual amount used.\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.inputTokenAddress,\n params.universalRouterAddress,\n params.maxAmountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [];\n\n // Op 0 (optional): pre-swap input-token fee transfer to PAFI fee recipient.\n if (params.gasFeeAmountInput > 0n) {\n operations.push(\n erc20TransferOp(\n params.inputTokenAddress,\n params.feeRecipient,\n params.gasFeeAmountInput,\n ),\n );\n }\n\n // Ops 1-3 (or 0-2 when fee is skipped): approval chain + swap.\n operations.push(\n erc20ApproveOp(params.inputTokenAddress, PERMIT2_ADDRESS, params.maxAmountIn),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n );\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n // +50k headroom for the additional pre-swap ERC-20 transfer when\n // the input-side fee is non-zero. Keeps margin even when fee=0n.\n callGasLimit: params.gasLimits?.callGasLimit ?? 750_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","/**\n * Slippage tolerance bounds shared by every swap call site (exact-in\n * + exact-out, handler + FE-direct).\n *\n * - Lower bound `0` — caller asks for zero slippage tolerance. Legal,\n * but the swap is virtually guaranteed to revert on any pool\n * movement; we let it through so callers can opt into strict mode.\n * - Upper bound `5000` (50%) — catches obvious caller bugs (passing\n * a percentage instead of basis points: `50` → ✓, `0.5` → ✗ via\n * the integer check; `50_00_00` → ✗ via this cap). Larger values\n * would let a misconfigured caller authorize a `maxAmountIn` (or\n * accept a `minAmountOut`) wildly outside the quoted band.\n *\n * The cap is intentionally generous — even pathological PT pools\n * post-incident shouldn't need >50% slippage. A caller that genuinely\n * needs more should split the trade.\n */\nexport const MAX_SLIPPAGE_BPS = 5000 as const;\n\n/**\n * Validate a caller-supplied `slippageBps` value. Returns `true` for\n * `undefined` (means \"use the default\") and any integer in\n * `[0, MAX_SLIPPAGE_BPS]`. Returns `false` otherwise — callers should\n * surface a typed error appropriate for their layer (handler →\n * `ValidationError(\"INVALID_SLIPPAGE\", ...)`; direct path → plain\n * `Error`).\n *\n * Rejects:\n * - non-finite numbers (`NaN`, `Infinity`)\n * - non-integers (`0.5`, `50.5`)\n * - negative values (would invert the slippage formula)\n * - values exceeding `MAX_SLIPPAGE_BPS`\n */\nexport function isValidSlippageBps(value: number | undefined): boolean {\n if (value === undefined) return true;\n return (\n Number.isInteger(value) &&\n value >= 0 &&\n value <= MAX_SLIPPAGE_BPS\n );\n}\n","// Re-export from @pafi-dev/core — fetchPafiPools lives in core so all\n// SDK packages share one implementation.\nexport { fetchPafiPools, PAFI_SUBGRAPH_URL } from \"@pafi-dev/core\";\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n UNIVERSAL_ROUTER_ADDRESSES,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n BATCH_EXECUTOR_7702_IMPL,\n type PoolKey,\n} from \"@pafi-dev/core\";\nimport { findBestQuote } from \"../quoting\";\nimport { MAX_SLIPPAGE_BPS, buildSwapUserOp, isValidSlippageBps } from \"../swap\";\n\nexport interface SwapDirectParams {\n /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */\n userAddress: Address;\n chainId: number;\n inputTokenAddress: Address;\n outputTokenAddress: Address;\n /** Input amount (raw token decimals). */\n amount: bigint;\n /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */\n pools?: PoolKey[];\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Slippage tolerance in basis points. Default 50 single-hop / 100\n * multi-hop (handler picks based on `bestRoute.path.length`).\n */\n slippageBps?: number;\n /** Swap deadline (unix seconds). Default = now + 5 minutes. */\n deadline?: bigint;\n /**\n * Operator fee in OUTPUT token, paid to PAFI fee recipient.\n *\n * - `undefined` (default for direct path): **skip the fee transfer\n * entirely** — PAFI is not sponsoring this swap, no reimbursement\n * owed. Most callers want this.\n * - `0n` — same as above, explicit.\n * - explicit `bigint` — include the fee transfer (rare; only when\n * issuer dev/test wants to mirror sponsored behaviour).\n */\n gasFeeAmountOutput?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface SwapDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n estimatedOutputAmount: bigint;\n minAmountOut: bigint;\n hops: number;\n deadline: bigint;\n feeAmountUsed: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct swap** path — no AA, no bundler,\n * no PAFI sponsor-relayer. The user EOA pays gas in ETH and broadcasts\n * a single type-2 transaction calling its own EIP-7702 delegated\n * bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl\n * (canonically Pimlico's `Simple7702Account`; the legacy Coinbase\n * Smart Wallet v2 BatchExecutor is still accepted by\n * `detectDelegateImpl` for EOAs delegated earlier). Throw with a\n * clear hint pointing at `delegateDirect()` if not delegated at\n * all.\n * 2. `findBestQuote` → best route + gross output.\n * 3. `buildSwapUserOp` → encoded `executeBatch(calls)` calldata.\n * 4. `walletClient.sendTransaction({ to: userAddress, data: callData })`\n * — self-call into the delegated bytecode, which dispatches the\n * batch (input.approve → Permit2.approve → UR.execute → optional\n * fee transfer).\n * 5. Wait for receipt (optional).\n *\n * Use when:\n * - The FE doesn't have a Pimlico API key + doesn't want to depend on\n * PAFI sponsor-relayer.\n * - The user already has a small ETH balance.\n * - You need a deterministic, single-tx swap (vs. AA UserOp's longer\n * bundler round-trip).\n *\n * Throws when the user is NOT yet delegated — caller should run\n * `delegateDirect` first or use the AA path (`TradingHandlers.handleSwap`\n * + `permissionless`).\n *\n * @example\n * ```ts\n * import { swapDirect, fetchPafiPools } from \"@pafi-dev/trading\";\n *\n * const pools = await fetchPafiPools(8453, POINT_TOKEN);\n * const result = await swapDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * inputTokenAddress: POINT_TOKEN,\n * outputTokenAddress: USDT,\n * amount: parseUnits(\"100\", 18),\n * pools,\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Swap tx:\", result.txHash);\n * ```\n */\nexport async function swapDirect(\n params: SwapDirectParams,\n): Promise<SwapDirectResult> {\n // 1. Cheap, sync input validation — runs first so a malformed call\n // fails immediately without burning an RPC quota on getCode.\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[params.chainId];\n if (!universalRouter) {\n throw new Error(`swapDirect: no UniversalRouter for chainId ${params.chainId}`);\n }\n if (params.amount <= 0n) {\n throw new Error(\"swapDirect: amount must be positive\");\n }\n if (!isValidSlippageBps(params.slippageBps)) {\n throw new Error(\n `swapDirect: slippageBps (${params.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n );\n }\n\n // Wallet's account MUST be the user EOA — the native tx is sent from\n // `account.address`, and BatchExecutor's executeBatch reverts unless\n // `msg.sender == address(this)` (i.e. the EOA itself executes its\n // delegated bytecode). Catching the mismatch here saves a wasted gas\n // attempt and produces a clear, immediate error.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"swapDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `swapDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress}) — ` +\n `the native tx must be sent from the same EOA whose 7702-delegated bytecode is being executed`,\n );\n }\n\n // 2. Delegation precondition — `executeBatch` only works when the\n // EOA has 7702 bytecode pointing at a known impl.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `swapDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first (user pays a one-time delegation tx) ` +\n `or use the AA path via \\`TradingHandlers.handleSwap()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `swapDirect: user delegated to ${delegate} which is not a PAFI-recognised impl ` +\n `(expected ${SIMPLE_7702_IMPL_BASE_MAINNET} or ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuote>>;\n try {\n quoteResult = await findBestQuote(\n params.publicClient,\n params.chainId,\n params.inputTokenAddress,\n params.outputTokenAddress,\n params.amount,\n params.pools ?? [],\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new Error(\n `swapDirect: no swap path found from ${params.inputTokenAddress} to ${params.outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = params.slippageBps ?? (hops > 1 ? 100 : 50);\n const estimatedOutputAmount = quoteResult.bestRoute.amountOut;\n const minAmountOut =\n (estimatedOutputAmount * BigInt(10000 - slippageBps)) / 10000n;\n const gasFeeAmountOutput = params.gasFeeAmountOutput ?? 0n;\n if (gasFeeAmountOutput > 0n && minAmountOut < gasFeeAmountOutput) {\n throw new Error(\n `swapDirect: minAmountOut (${minAmountOut}) below operator fee (${gasFeeAmountOutput})`,\n );\n }\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 3. Build the UserOp purely to extract its callData (encoded\n // `executeBatch(calls)`). We send that as a native tx instead.\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const userOp = buildSwapUserOp({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path; nonce comes from EOA tx count\n inputTokenAddress: params.inputTokenAddress,\n outputTokenAddress: params.outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountIn: params.amount,\n minAmountOut,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountOutput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // 4. Send native tx — to: userAddress, data: encoded executeBatch.\n // (`account` validated up-front against `userAddress`.)\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: userOp.callData,\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `swapDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n estimatedOutputAmount,\n minAmountOut,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountOutput,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n UNIVERSAL_ROUTER_ADDRESSES,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n BATCH_EXECUTOR_7702_IMPL,\n type PoolKey,\n} from \"@pafi-dev/core\";\nimport { findBestQuoteExactOut } from \"../quoting\";\nimport {\n MAX_SLIPPAGE_BPS,\n buildSwapUserOpExactOut,\n isValidSlippageBps,\n} from \"../swap\";\n\nexport interface SwapDirectExactOutParams {\n /** User EOA — must be delegated via EIP-7702 to a PAFI-supported impl. */\n userAddress: Address;\n chainId: number;\n inputTokenAddress: Address;\n outputTokenAddress: Address;\n /** Exact OUTPUT amount the user wants to receive (raw token decimals). */\n amount: bigint;\n /** Pools to route through. Caller pre-fetches via `fetchPafiPools`. */\n pools?: PoolKey[];\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Slippage tolerance in basis points. Default 50 single-hop / 100\n * multi-hop. Slippage is applied as a CEILING on `maxAmountIn`.\n */\n slippageBps?: number;\n /** Swap deadline (unix seconds). Default = now + 5 minutes. */\n deadline?: bigint;\n /**\n * Operator fee in INPUT token, paid to PAFI fee recipient.\n *\n * - `undefined` (default for direct path): **skip the fee transfer\n * entirely** — PAFI is not sponsoring this swap, no reimbursement\n * owed. Most callers want this.\n * - `0n` — same as above, explicit.\n * - explicit `bigint` — include the fee transfer (rare; only when\n * issuer dev/test wants to mirror sponsored behaviour).\n */\n gasFeeAmountInput?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface SwapDirectExactOutResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Echoes `params.amount` — the exact output. */\n outputAmount: bigint;\n /** Raw input amount from the V3 quoter, before slippage. */\n estimatedInputAmount: bigint;\n /** Slippage-bumped cap on input — encoded in the swap calldata. */\n maxAmountIn: bigint;\n hops: number;\n deadline: bigint;\n feeAmountUsed: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct exact-output swap** path — no AA,\n * no bundler, no PAFI sponsor-relayer. Symmetric to `swapDirect` but\n * specifies the OUTPUT amount and bumps slippage UPWARD on `maxAmountIn`.\n *\n * Caller pre-conditions:\n *\n * - User EOA already has EIP-7702 delegation (`delegateDirect` first).\n * - User EOA holds **`maxAmountIn + gasFeeAmountInput`** of\n * `inputTokenAddress` (not just `amount` — that's output).\n *\n * Flow:\n * 1. Verify the EOA has EIP-7702 delegation to a PAFI-supported impl.\n * 2. `findBestQuoteExactOut` → best route + required input.\n * 3. Slippage ceiling → `maxAmountIn`.\n * 4. `buildSwapUserOpExactOut` → encoded `executeBatch(calls)` calldata.\n * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.\n * 6. Wait for receipt (optional).\n *\n * @example\n * ```ts\n * import { swapDirectExactOut, fetchPafiPools } from \"@pafi-dev/trading\";\n *\n * const pools = await fetchPafiPools(8453, POINT_TOKEN);\n * const result = await swapDirectExactOut({\n * userAddress: wallet.address,\n * chainId: 8453,\n * inputTokenAddress: POINT_TOKEN,\n * outputTokenAddress: USDT,\n * amount: parseUnits(\"50\", 6), // exactly 50 USDT\n * pools,\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Swap tx:\", result.txHash);\n * ```\n */\nexport async function swapDirectExactOut(\n params: SwapDirectExactOutParams,\n): Promise<SwapDirectExactOutResult> {\n // 1. Cheap, sync input validation — runs first so a malformed call\n // fails immediately without burning an RPC quota on getCode.\n const universalRouter = UNIVERSAL_ROUTER_ADDRESSES[params.chainId];\n if (!universalRouter) {\n throw new Error(\n `swapDirectExactOut: no UniversalRouter for chainId ${params.chainId}`,\n );\n }\n if (params.amount <= 0n) {\n throw new Error(\"swapDirectExactOut: amount must be positive\");\n }\n if (!isValidSlippageBps(params.slippageBps)) {\n throw new Error(\n `swapDirectExactOut: slippageBps (${params.slippageBps}) must be an integer in [0, ${MAX_SLIPPAGE_BPS}]`,\n );\n }\n\n // Wallet's account MUST be the user EOA — same rationale as `swapDirect`.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"swapDirectExactOut: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `swapDirectExactOut: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress}) — ` +\n `the native tx must be sent from the same EOA whose 7702-delegated bytecode is being executed`,\n );\n }\n\n // 2. Delegation precondition — same as exact-in.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `swapDirectExactOut: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handleSwapExactOut()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `swapDirectExactOut: user delegated to ${delegate} which is not a PAFI-recognised impl ` +\n `(expected ${SIMPLE_7702_IMPL_BASE_MAINNET} or ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n let quoteResult: Awaited<ReturnType<typeof findBestQuoteExactOut>>;\n try {\n quoteResult = await findBestQuoteExactOut(\n params.publicClient,\n params.chainId,\n params.inputTokenAddress,\n params.outputTokenAddress,\n params.amount,\n params.pools ?? [],\n );\n } catch (err) {\n const cause = err instanceof Error ? err.message : String(err);\n throw new Error(\n `swapDirectExactOut: no swap path found from ${params.inputTokenAddress} to ${params.outputTokenAddress} (cause: ${cause})`,\n );\n }\n\n const hops = quoteResult.bestRoute.path.fees.length;\n const slippageBps = params.slippageBps ?? (hops > 1 ? 100 : 50);\n const estimatedInputAmount = quoteResult.bestRoute.amountIn;\n // Ceiling division — see `handleSwapExactOut` for the rationale.\n const slippageNumerator =\n estimatedInputAmount * BigInt(10000 + slippageBps);\n const maxAmountIn = (slippageNumerator + 9999n) / 10000n;\n const gasFeeAmountInput = params.gasFeeAmountInput ?? 0n;\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 3. Build the UserOp purely to extract its callData (encoded\n // `executeBatch(calls)`). We send that as a native tx instead.\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const userOp = buildSwapUserOpExactOut({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path; nonce comes from EOA tx count\n inputTokenAddress: params.inputTokenAddress,\n outputTokenAddress: params.outputTokenAddress,\n universalRouterAddress: universalRouter,\n amountOut: params.amount,\n maxAmountIn,\n swapPath: quoteResult.bestRoute.path,\n deadline,\n gasFeeAmountInput,\n feeRecipient: pafiFeeRecipient,\n });\n\n // 4. Send native tx — to: userAddress, data: encoded executeBatch.\n // (`account` validated up-front against `userAddress`.)\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: userOp.callData,\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `swapDirectExactOut: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n outputAmount: params.amount,\n estimatedInputAmount,\n maxAmountIn,\n hops,\n deadline,\n feeAmountUsed: gasFeeAmountInput,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n BROKER_HASHES,\n ORDERLY_RELAY_ABI,\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n TOKEN_HASHES,\n buildPerpDepositViaRelay,\n computeAccountId,\n detectDelegateImpl,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n BATCH_EXECUTOR_7702_IMPL,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n} from \"@pafi-dev/core\";\n\nexport interface PerpDepositDirectParams {\n /** User EOA — must be EIP-7702 delegated. */\n userAddress: Address;\n chainId: number;\n /** USDC amount to deposit (6-decimal raw units). */\n amount: bigint;\n /** Orderly broker — `'orderly' | 'woofi_pro' | 'logx'`. */\n brokerId: keyof typeof BROKER_HASHES;\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Max acceptable USDC fee charged by the Relay (slippage cap on its\n * USD-pricing of `msg.value`). Default `max(amount * 5%, 2 USDC)` —\n * matches `TradingHandlers.handlePerpDeposit`.\n */\n maxRelayFee?: bigint;\n /**\n * Operator fee in USDC (input-token, BEFORE deposit). Same semantics\n * as `swapDirect.gasFeeAmountOutput`:\n *\n * - `undefined` (default for direct path): **skip the fee transfer**\n * — PAFI is not sponsoring this deposit.\n * - explicit `bigint` — include the fee transfer.\n */\n gasFeeUsdc?: bigint;\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface PerpDepositDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Resolved USDC fee charged by the Relay. */\n relayTokenFee: bigint;\n /** Cap applied to the Relay fee (slippage allowance). */\n maxFee: bigint;\n /** USDC reaching Orderly Vault after Relay's fee = amount - relayTokenFee. */\n netDeposit: bigint;\n /** Operator fee actually included (0n on default direct path). */\n feeAmountUsed: bigint;\n accountId: Hex;\n brokerHash: Hex;\n usdcAddress: Address;\n relayAddress: Address;\n}\n\n/**\n * One-shot helper for the **FE-direct perp deposit** path — no AA, no\n * bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and\n * broadcasts a single type-2 transaction calling its own EIP-7702\n * delegated bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Verify EIP-7702 delegation (same precondition as `swapDirect`).\n * 2. Resolve USDC + verify broker is whitelisted on Orderly Vault.\n * 3. Quote `Relay.tokenFee` for the deposit; compute `netDeposit`.\n * 4. `buildPerpDepositViaRelay` → encoded `executeBatch(calls)`\n * (USDC.approve(relay) + Relay.deposit + optional fee transfer).\n * 5. `walletClient.sendTransaction({ to: userAddress, data: callData })`.\n * 6. Wait for receipt (optional).\n *\n * Use when: same conditions as `swapDirect` — FE doesn't have Pimlico\n * key, doesn't want sponsor-relayer dependency, user has small ETH.\n *\n * Throws when the user is NOT yet delegated.\n *\n * @example\n * ```ts\n * import { perpDepositDirect } from \"@pafi-dev/trading\";\n *\n * const result = await perpDepositDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * amount: parseUnits(\"10\", 6), // 10 USDC\n * brokerId: \"orderly\",\n * publicClient,\n * walletClient,\n * });\n * console.log(\"Deposit tx:\", result.txHash);\n * console.log(\"Net deposit to Orderly:\", result.netDeposit, \"USDC raw\");\n * ```\n */\nexport async function perpDepositDirect(\n params: PerpDepositDirectParams,\n): Promise<PerpDepositDirectResult> {\n if (params.amount <= 0n) {\n throw new Error(\"perpDepositDirect: amount must be positive\");\n }\n\n // 1. Delegation precondition.\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `perpDepositDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handlePerpDeposit()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `perpDepositDirect: user delegated to ${delegate} (not a PAFI-recognised impl ` +\n `${SIMPLE_7702_IMPL_BASE_MAINNET} / ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n // 2. Resolve USDC + verify broker.\n const vault = ORDERLY_VAULT_ADDRESSES[params.chainId];\n if (!vault) {\n throw new Error(\n `perpDepositDirect: no Orderly Vault for chainId ${params.chainId}`,\n );\n }\n const brokerHash = BROKER_HASHES[params.brokerId];\n if (!brokerHash) {\n throw new Error(\n `perpDepositDirect: unknown brokerId \"${params.brokerId}\"`,\n );\n }\n const tokenHash = TOKEN_HASHES.USDC;\n\n const [usdcAddress, brokerAllowed] = await Promise.all([\n params.publicClient.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedToken\",\n args: [tokenHash],\n }) as Promise<Address>,\n params.publicClient.readContract({\n address: vault,\n abi: ORDERLY_VAULT_ABI,\n functionName: \"getAllowedBroker\",\n args: [brokerHash],\n }) as Promise<boolean>,\n ]);\n if (!brokerAllowed) {\n throw new Error(\n `perpDepositDirect: broker \"${params.brokerId}\" is not whitelisted on Orderly Vault`,\n );\n }\n\n // 3. Quote Relay fee.\n const { orderlyRelay: relayAddress, pafiFeeRecipient } = getContractAddresses(\n params.chainId,\n );\n // Cap = max(amount * 5%, 2 USDC) — same heuristic as TradingHandlers.\n const RELAY_FEE_FLOOR_USDC = 2_000_000n;\n const percentCap = (params.amount * 500n) / 10_000n;\n const maxFee =\n params.maxRelayFee ??\n (percentCap > RELAY_FEE_FLOOR_USDC ? percentCap : RELAY_FEE_FLOOR_USDC);\n\n const relayRequest = {\n token: usdcAddress,\n receiver: params.userAddress,\n brokerHash,\n totalAmount: params.amount,\n maxFee,\n };\n\n const relayTokenFee = (await params.publicClient.readContract({\n address: relayAddress,\n abi: ORDERLY_RELAY_ABI,\n functionName: \"quoteTokenFee\",\n args: [relayRequest],\n })) as bigint;\n\n if (relayTokenFee > maxFee) {\n throw new Error(\n `perpDepositDirect: Relay tokenFee ${relayTokenFee} exceeds maxFee ${maxFee} — ` +\n `pass a larger \\`maxRelayFee\\` or increase \\`amount\\`.`,\n );\n }\n if (relayTokenFee >= params.amount) {\n throw new Error(\n `perpDepositDirect: deposit amount ${params.amount} below Relay fee ${relayTokenFee} — increase \\`amount\\`.`,\n );\n }\n\n // 4. Build calldata via core helper.\n const gasFeeUsdc = params.gasFeeUsdc ?? 0n;\n const partial = buildPerpDepositViaRelay({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path\n relayAddress,\n request: relayRequest,\n gasFeeUsdc: gasFeeUsdc > 0n ? gasFeeUsdc : undefined,\n gasFeeUsdcRecipient: gasFeeUsdc > 0n ? pafiFeeRecipient : undefined,\n });\n\n // 5. Send native tx — self-call into delegated bytecode.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"perpDepositDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 6. Wait for receipt (optional).\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `perpDepositDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n const accountId = computeAccountId(params.userAddress, brokerHash);\n\n return {\n txHash,\n receipt,\n relayTokenFee,\n maxFee,\n netDeposit: params.amount - relayTokenFee,\n feeAmountUsed: gasFeeUsdc,\n accountId,\n brokerHash,\n usdcAddress,\n relayAddress,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n buildErc20TransferUserOp,\n getContractAddresses,\n parseEip7702DelegatedAddress,\n detectDelegateImpl,\n BATCH_EXECUTOR_7702_IMPL,\n SIMPLE_7702_IMPL_BASE_MAINNET,\n} from \"@pafi-dev/core\";\n\n/**\n * Direct (non-AA) gasless ERC-20 transfer — for users who already hold\n * native ETH and want to skip the paymaster/bundler round-trip. Same\n * sponsored-shape calls but submitted as a self-call to the EOA's\n * EIP-7702 delegated bytecode.\n *\n * Mirrors `perpDepositDirect`: requires 7702 delegation, builds the\n * batch via the core helper, sends via `walletClient.sendTransaction`.\n *\n * For the AA / paymaster-sponsored path (zero ETH on user wallet), use\n * `TradingHandlers.handleErc20Transfer` and submit the returned UserOp.\n */\nexport interface TransferDirectParams {\n userAddress: Address;\n chainId: number;\n tokenAddress: Address;\n recipient: Address;\n amount: bigint;\n\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /**\n * Operator fee. Same semantics as `perpDepositDirect.gasFeeUsdc`:\n * - `undefined` (default for direct path): NO fee transfer. PAFI\n * is not sponsoring; treating as a regular wallet send.\n * - explicit `bigint`: include the fee transfer (rare for the\n * direct path, but supported for symmetry).\n */\n feeAmount?: bigint;\n\n /** Wait for receipt before returning. Default `true`. */\n waitForReceipt?: boolean;\n /** Optional non-fatal warning sink (e.g. unexpected impl on delegation). */\n onWarning?: (msg: string) => void;\n}\n\nexport interface TransferDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Echo of the fee actually included in the batch. `0n` when omitted. */\n feeAmountUsed: bigint;\n feeRecipient: Address;\n tokenAddress: Address;\n}\n\nexport async function transferDirect(\n params: TransferDirectParams,\n): Promise<TransferDirectResult> {\n if (params.amount <= 0n) {\n throw new Error(\"transferDirect: amount must be positive\");\n }\n if (\n params.recipient ===\n \"0x0000000000000000000000000000000000000000\"\n ) {\n throw new Error(\n \"transferDirect: recipient cannot be the zero address\",\n );\n }\n\n // 1. Delegation precondition (matches perpDepositDirect).\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `transferDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path via ` +\n `\\`TradingHandlers.handleErc20Transfer()\\` + sponsor-relayer.`,\n );\n }\n const impl = detectDelegateImpl(delegate);\n if (impl === \"unknown\") {\n params.onWarning?.(\n `transferDirect: user delegated to ${delegate} (not a PAFI-recognised impl ` +\n `${SIMPLE_7702_IMPL_BASE_MAINNET} / ${BATCH_EXECUTOR_7702_IMPL}). ` +\n `Continuing — execute will revert if the impl doesn't expose executeBatch.`,\n );\n }\n\n const { pafiFeeRecipient } = getContractAddresses(params.chainId);\n const feeAmount = params.feeAmount ?? 0n;\n\n // 2. Build calldata via core helper — same shape as the sponsored\n // path, just sent natively instead of through the bundler.\n const partial = buildErc20TransferUserOp({\n userAddress: params.userAddress,\n aaNonce: 0n, // ignored on the native-tx path\n tokenAddress: params.tokenAddress,\n recipient: params.recipient,\n amount: params.amount,\n feeAmount: feeAmount > 0n ? feeAmount : undefined,\n feeRecipient: feeAmount > 0n ? pafiFeeRecipient : undefined,\n });\n\n // 3. Send native tx — self-call into delegated bytecode.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"transferDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 4. Optional receipt wait.\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `transferDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n feeAmountUsed: feeAmount,\n feeRecipient: pafiFeeRecipient,\n tokenAddress: params.tokenAddress,\n };\n}\n","import {\n decodeEventLog,\n type Address,\n type Hex,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildMint,\n readPoolState,\n estimateLiquidityFromOneSide,\n applyMintSlippage,\n tickToSqrtPriceX96,\n tickSpacingForFee,\n nonfungiblePositionManagerAbi,\n} from \"../liquidity\";\n\nexport interface AddLiquidityDirectParams {\n /** User EOA — must be EIP-7702 delegated. */\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /** Pool token0 (must be sorted < token1). */\n token0: Address;\n /** Pool token1. */\n token1: Address;\n /** V3 fee tier (e.g. 500, 3000, 10000). */\n fee: number;\n\n /** Position range — both ticks must be multiples of the pool's tickSpacing. */\n tickLower: number;\n tickUpper: number;\n\n /** Caller pins ONE side; the other is computed by the SDK. */\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n\n /** bps, default 50. Capped at 10000. */\n slippageBps?: number;\n /** Unix seconds. Default `now + 5min`. */\n deadline?: bigint;\n\n /** Wait for receipt + parse tokenId. Default `true`. */\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface AddLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Newly-minted position NFT id. Available when `waitForReceipt !== false`. */\n tokenId?: bigint;\n /** Amount0 baked into the calldata (after estimation). */\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** L value computed off-chain from amounts + range. Informational. */\n liquidity: bigint;\n deadline: bigint;\n}\n\n/**\n * One-shot helper for the **FE-direct add-liquidity** path — no AA, no\n * bundler, no PAFI sponsor-relayer. The user EOA pays gas in ETH and\n * broadcasts a single type-2 transaction calling its own EIP-7702\n * delegated bytecode (`Simple7702Account.executeBatch`).\n *\n * Flow:\n * 1. Validate inputs (tick range, single-amount guard, slippage).\n * 2. Verify the EOA is EIP-7702 delegated.\n * 3. Read pool state (sqrtPriceX96).\n * 4. Estimate the other side's amount + liquidity from one pinned side.\n * 5. Apply slippage → (amount0Min, amount1Min).\n * 6. Build 3-op batch: approve token0, approve token1, NPM.mint.\n * 7. Send native tx.\n * 8. Wait receipt + parse `Transfer(0x0 → user, tokenId)` → return tokenId.\n *\n * @example\n * ```ts\n * const result = await addLiquidityDirect({\n * userAddress: wallet.address,\n * chainId: 8453,\n * publicClient,\n * walletClient,\n * token0: PT,\n * token1: USDC,\n * fee: 3000,\n * tickLower: -60000,\n * tickUpper: -54000,\n * amount0Desired: parseUnits(\"100\", 18),\n * });\n * console.log(\"Minted position:\", result.tokenId);\n * ```\n */\nexport async function addLiquidityDirect(\n params: AddLiquidityDirectParams,\n): Promise<AddLiquidityDirectResult> {\n // 1. Sync input validation.\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `addLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(\n `addLiquidityDirect: no V3 factory for chainId ${params.chainId}`,\n );\n }\n if (params.tickLower >= params.tickUpper) {\n throw new Error(\n `addLiquidityDirect: tickLower (${params.tickLower}) must be strictly less than tickUpper (${params.tickUpper})`,\n );\n }\n const ts = tickSpacingForFee(params.fee);\n if (ts !== undefined) {\n if (params.tickLower % ts !== 0 || params.tickUpper % ts !== 0) {\n throw new Error(\n `addLiquidityDirect: ticks must be multiples of tickSpacing ${ts} for fee ${params.fee}`,\n );\n }\n }\n const has0 = params.amount0Desired !== undefined && params.amount0Desired > 0n;\n const has1 = params.amount1Desired !== undefined && params.amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"addLiquidityDirect: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `addLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"addLiquidityDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `addLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n // 2. Delegation precondition.\n const code = await params.publicClient.getCode({ address: params.userAddress });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `addLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated. ` +\n `Run \\`delegateDirect()\\` first or use the AA path.`,\n );\n }\n\n // 3. Read pool state.\n const pool = computeV3PoolAddress({\n factory,\n tokenA: params.token0,\n tokenB: params.token1,\n fee: params.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n // 4. Estimate from one pinned side.\n const sqrtL = tickToSqrtPriceX96(params.tickLower);\n const sqrtU = tickToSqrtPriceX96(params.tickUpper);\n const { liquidity, amount0, amount1 } = estimateLiquidityFromOneSide({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: sqrtL,\n sqrtPriceX96Upper: sqrtU,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n });\n\n // 5. Slippage.\n const { amount0Min, amount1Min } = applyMintSlippage({\n amount0Desired: amount0,\n amount1Desired: amount1,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n // 6. Build batch.\n const operations = buildMint({\n npm,\n token0: params.token0,\n token1: params.token1,\n fee: params.fee,\n tickLower: params.tickLower,\n tickUpper: params.tickUpper,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n recipient: params.userAddress,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n // 7. Send native tx.\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n // 8. Optional receipt + tokenId parse.\n let receipt: TransactionReceipt | undefined;\n let tokenId: bigint | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n tokenId = parseMintedTokenId(receipt, npm, params.userAddress);\n } catch (err) {\n params.onWarning?.(\n `addLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n tokenId,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n liquidity,\n deadline,\n };\n}\n\n/**\n * Find the `Transfer(from=0x0, to=userAddress, tokenId)` log in a mint\n * receipt and return the tokenId.\n *\n * The NPM emits a standard ERC-721 `Transfer` event for every mint; the\n * `from` field is the zero address for newly-minted tokens. We scan the\n * receipt logs for the matching event from the NPM contract address.\n */\nfunction parseMintedTokenId(\n receipt: TransactionReceipt,\n npm: Address,\n user: Address,\n): bigint | undefined {\n const userLower = user.toLowerCase();\n const zero = \"0x0000000000000000000000000000000000000000\";\n for (const log of receipt.logs) {\n if (log.address.toLowerCase() !== npm.toLowerCase()) continue;\n try {\n const decoded = decodeEventLog({\n abi: nonfungiblePositionManagerAbi,\n data: log.data,\n topics: log.topics,\n });\n if (decoded.eventName !== \"Transfer\") continue;\n const args = decoded.args as { from: Address; to: Address; tokenId: bigint };\n if (\n args.from.toLowerCase() === zero &&\n args.to.toLowerCase() === userLower\n ) {\n return args.tokenId;\n }\n } catch {\n // Not a Transfer log we can decode — skip.\n }\n }\n return undefined;\n}\n","/**\n * Uniswap V3 NonfungiblePositionManager (NPM) ABI — subset used by the\n * `@pafi-dev/trading` liquidity flows. PAFI deployment lives at\n * `V3_NPM_ADDRESSES[chainId]`.\n *\n * Hand-authored (not generated) — same convention as `v3QuoterV2Abi` in\n * `@pafi-dev/core`. Only the methods + events the SDK actually uses are\n * declared, to keep the surface small and the type narrowing precise.\n *\n * Intentionally omitted: `multicall`, `WETH9`, `refundETH`, `sweepToken`,\n * `unwrapWETH9` (ETH wrap helpers — out of v1 scope), `tokenURI`, `name`,\n * `symbol`, `tokenOfOwnerByIndex` (ERC-721 metadata + enumerable — position\n * listing is the consumer backend's job), `permit`, `safeTransferFrom`.\n */\nexport const nonfungiblePositionManagerAbi = [\n // ─── Write methods ───────────────────────────────────────────────────────\n\n {\n type: \"function\",\n name: \"mint\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\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: \"amount0Desired\", type: \"uint256\" },\n { name: \"amount1Desired\", type: \"uint256\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"recipient\", type: \"address\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"increaseLiquidity\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"amount0Desired\", type: \"uint256\" },\n { name: \"amount1Desired\", type: \"uint256\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"decreaseLiquidity\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"params\",\n type: \"tuple\",\n components: [\n { name: \"tokenId\", type: \"uint256\" },\n { name: \"liquidity\", type: \"uint128\" },\n { name: \"amount0Min\", type: \"uint256\" },\n { name: \"amount1Min\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n },\n ],\n outputs: [\n { name: \"amount0\", type: \"uint256\" },\n { name: \"amount1\", type: \"uint256\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"collect\",\n stateMutability: \"payable\",\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 },\n\n {\n type: \"function\",\n name: \"burn\",\n stateMutability: \"payable\",\n inputs: [{ name: \"tokenId\", type: \"uint256\" }],\n outputs: [],\n },\n\n // ─── Read methods ────────────────────────────────────────────────────────\n\n // Returns the legacy V3 12-tuple. `readPosition` wraps this into a struct.\n {\n type: \"function\",\n name: \"positions\",\n stateMutability: \"view\",\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 },\n\n // Used by the ABI smoke test to verify NPM is wired to the expected\n // PafiV3Factory.\n {\n type: \"function\",\n name: \"factory\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n\n // ─── Events (for receipt parsing) ────────────────────────────────────────\n\n // Emitted from address(0) on mint; addLiquidityDirect parses this to\n // extract the newly-minted tokenId.\n {\n type: \"event\",\n name: \"Transfer\",\n inputs: [\n { name: \"from\", type: \"address\", indexed: true },\n { name: \"to\", type: \"address\", indexed: true },\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n ],\n },\n\n {\n type: \"event\",\n name: \"IncreaseLiquidity\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"liquidity\", type: \"uint128\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n\n {\n type: \"event\",\n name: \"DecreaseLiquidity\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"liquidity\", type: \"uint128\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n\n {\n type: \"event\",\n name: \"Collect\",\n inputs: [\n { name: \"tokenId\", type: \"uint256\", indexed: true },\n { name: \"recipient\", type: \"address\", indexed: false },\n { name: \"amount0\", type: \"uint256\", indexed: false },\n { name: \"amount1\", type: \"uint256\", indexed: false },\n ],\n },\n] as const;\n","/**\n * Uniswap V3 Pool ABI — read-only subset used by the\n * `@pafi-dev/trading` liquidity flows to estimate amounts off-chain.\n *\n * Pool addresses are derived from `V3_FACTORY_ADDRESSES` +\n * `V3_POOL_INIT_CODE_HASH` (both in `@pafi-dev/core`) via\n * `computeV3PoolAddress()`.\n *\n * Intentionally omitted: pool-direct write methods (`swap`, `flash`,\n * `mint`, `burn`, `collect`) — every write call goes through NPM, never\n * the pool. Also omitted: `positions(bytes32)` (NPM-side is the canonical\n * read), `protocolFees`, `observe`, `snapshotCumulativesInside`.\n */\nexport const v3PoolAbi = [\n // Pool's underlying tokens. Read on-chain to verify the\n // `computeV3PoolAddress(factory, token0, token1, fee)` derivation matches\n // an already-deployed pool — and useful generally for consumers that\n // discovered a pool by address (e.g. from a Transfer log) and need the\n // tokens.\n {\n type: \"function\",\n name: \"token0\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n {\n type: \"function\",\n name: \"token1\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n\n // (sqrtPriceX96, tick, observationIndex, observationCardinality,\n // observationCardinalityNext, feeProtocol, unlocked)\n {\n type: \"function\",\n name: \"slot0\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n { name: \"sqrtPriceX96\", type: \"uint160\" },\n { name: \"tick\", type: \"int24\" },\n { name: \"observationIndex\", type: \"uint16\" },\n { name: \"observationCardinality\", type: \"uint16\" },\n { name: \"observationCardinalityNext\", type: \"uint16\" },\n { name: \"feeProtocol\", type: \"uint8\" },\n { name: \"unlocked\", type: \"bool\" },\n ],\n },\n\n {\n type: \"function\",\n name: \"liquidity\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint128\" }],\n },\n\n {\n type: \"function\",\n name: \"tickSpacing\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"int24\" }],\n },\n\n {\n type: \"function\",\n name: \"fee\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint24\" }],\n },\n\n // (Token-0 / token-1 cumulative fee growth per unit of liquidity, in\n // Q128.128.) Used with `ticks(...)` to derive the pending-fee estimate\n // for collectFeesDirect.\n {\n type: \"function\",\n name: \"feeGrowthGlobal0X128\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n\n {\n type: \"function\",\n name: \"feeGrowthGlobal1X128\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n\n // Per-tick state. The SDK reads `ticks(tickLower)` + `ticks(tickUpper)`\n // for a position to compute its `feeGrowthInside0/1` in the canonical\n // V3 formula (current global - outside lower - outside upper, branched\n // on whether `slot0.tick` is below / inside / above the range).\n {\n type: \"function\",\n name: \"ticks\",\n stateMutability: \"view\",\n inputs: [{ name: \"tick\", type: \"int24\" }],\n outputs: [\n { name: \"liquidityGross\", type: \"uint128\" },\n { name: \"liquidityNet\", type: \"int128\" },\n { name: \"feeGrowthOutside0X128\", type: \"uint256\" },\n { name: \"feeGrowthOutside1X128\", type: \"uint256\" },\n { name: \"tickCumulativeOutside\", type: \"int56\" },\n { name: \"secondsPerLiquidityOutsideX128\", type: \"uint160\" },\n { name: \"secondsOutside\", type: \"uint56\" },\n { name: \"initialized\", type: \"bool\" },\n ],\n },\n\n // Per-word initialized-tick bitset. Each uint256 word covers 256\n // compressed tick positions (compressed = tick / tickSpacing). The\n // off-chain liquidity-curve scanner reads every word in\n // `[wordOf(minUsableTick), wordOf(maxUsableTick)]` then decodes set\n // bits into absolute tick indices via `(wordPos * 256 + bit) * spacing`.\n // See `fetchAllInitializedTicks.ts`.\n {\n type: \"function\",\n name: \"tickBitmap\",\n stateMutability: \"view\",\n inputs: [{ name: \"wordPosition\", type: \"int16\" }],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n] as const;\n","import type { Address } from \"viem\";\n\n/**\n * PAFI's V3 NonfungiblePositionManager (NPM) per chain. All LP flows\n * encode calls against this address.\n *\n * Source of truth: `contracts.md` at the repo root.\n */\nexport const V3_NPM_ADDRESSES: Record<number, Address> = {\n // Base mainnet — PAFI's V3 NPM deployment.\n 8453: \"0xD7db6931B5EbeaE033605db0781DE6C91F05CCdf\",\n};\n\n/**\n * uint128 ceiling. Used as `amount0Max` / `amount1Max` on\n * `NPM.collect(...)` to mean \"transfer everything owed.\"\n */\nexport const UINT128_MAX: bigint = (1n << 128n) - 1n;\n","/**\n * Uniswap V3 liquidity math — hand-rolled bigint primitives.\n *\n * Mirrors the algorithms in `@uniswap/v3-sdk` (TickMath, SqrtPriceMath,\n * LiquidityAmounts) without taking the package as a runtime dependency.\n * Unit tests cross-check golden values against the upstream SDK; the\n * runtime trades a ~200 LoC implementation for zero new dependencies.\n *\n * All functions are pure and side-effect-free.\n */\n\n// ─── Constants ──────────────────────────────────────────────────────────────\n\n/** Minimum tick allowed by the V3 tick range. */\nexport const MIN_TICK = -887272;\n\n/** Maximum tick allowed by the V3 tick range. */\nexport const MAX_TICK = 887272;\n\n/** sqrtPriceX96 at MIN_TICK. */\nexport const MIN_SQRT_RATIO: bigint = 4295128739n;\n\n/** sqrtPriceX96 at MAX_TICK. */\nexport const MAX_SQRT_RATIO: bigint =\n 1461446703485210103287273052203988822378723970342n;\n\n/** 2^96 — the X96 scaling factor. */\nexport const Q96: bigint = 1n << 96n;\n\n/** 2^192 — used in sqrt² → ratio conversions. */\nexport const Q192: bigint = 1n << 192n;\n\n// ─── Internal helpers (not exported) ────────────────────────────────────────\n\nfunction mulShift(val: bigint, mulBy: bigint): bigint {\n return (val * mulBy) >> 128n;\n}\n\nfunction mulDivFloor(a: bigint, b: bigint, denominator: bigint): bigint {\n return (a * b) / denominator;\n}\n\nfunction mulDivCeil(a: bigint, b: bigint, denominator: bigint): bigint {\n const product = a * b;\n return product % denominator === 0n\n ? product / denominator\n : product / denominator + 1n;\n}\n\n// ─── Tick ↔ sqrtPriceX96 ────────────────────────────────────────────────────\n\n/**\n * Convert a tick to its sqrtPriceX96, using V3's exact lookup-table\n * algorithm. Equivalent to `TickMath.getSqrtRatioAtTick(tick)`.\n *\n * @throws if `tick` is outside `[MIN_TICK, MAX_TICK]`\n */\nexport function tickToSqrtPriceX96(tick: number): bigint {\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToSqrtPriceX96: tick must be an integer, got ${tick}`);\n }\n if (tick < MIN_TICK || tick > MAX_TICK) {\n throw new Error(\n `tickToSqrtPriceX96: tick ${tick} out of range [${MIN_TICK}, ${MAX_TICK}]`,\n );\n }\n\n const absTick = BigInt(tick < 0 ? -tick : tick);\n\n let ratio: bigint =\n (absTick & 0x1n) !== 0n\n ? 0xfffcb933bd6fad37aa2d162d1a594001n\n : 0x100000000000000000000000000000000n;\n\n if ((absTick & 0x2n) !== 0n)\n ratio = mulShift(ratio, 0xfff97272373d413259a46990580e213an);\n if ((absTick & 0x4n) !== 0n)\n ratio = mulShift(ratio, 0xfff2e50f5f656932ef12357cf3c7fdccn);\n if ((absTick & 0x8n) !== 0n)\n ratio = mulShift(ratio, 0xffe5caca7e10e4e61c3624eaa0941cd0n);\n if ((absTick & 0x10n) !== 0n)\n ratio = mulShift(ratio, 0xffcb9843d60f6159c9db58835c926644n);\n if ((absTick & 0x20n) !== 0n)\n ratio = mulShift(ratio, 0xff973b41fa98c081472e6896dfb254c0n);\n if ((absTick & 0x40n) !== 0n)\n ratio = mulShift(ratio, 0xff2ea16466c96a3843ec78b326b52861n);\n if ((absTick & 0x80n) !== 0n)\n ratio = mulShift(ratio, 0xfe5dee046a99a2a811c461f1969c3053n);\n if ((absTick & 0x100n) !== 0n)\n ratio = mulShift(ratio, 0xfcbe86c7900a88aedcffc83b479aa3a4n);\n if ((absTick & 0x200n) !== 0n)\n ratio = mulShift(ratio, 0xf987a7253ac413176f2b074cf7815e54n);\n if ((absTick & 0x400n) !== 0n)\n ratio = mulShift(ratio, 0xf3392b0822b70005940c7a398e4b70f3n);\n if ((absTick & 0x800n) !== 0n)\n ratio = mulShift(ratio, 0xe7159475a2c29b7443b29c7fa6e889d9n);\n if ((absTick & 0x1000n) !== 0n)\n ratio = mulShift(ratio, 0xd097f3bdfd2022b8845ad8f792aa5825n);\n if ((absTick & 0x2000n) !== 0n)\n ratio = mulShift(ratio, 0xa9f746462d870fdf8a65dc1f90e061e5n);\n if ((absTick & 0x4000n) !== 0n)\n ratio = mulShift(ratio, 0x70d869a156d2a1b890bb3df62baf32f7n);\n if ((absTick & 0x8000n) !== 0n)\n ratio = mulShift(ratio, 0x31be135f97d08fd981231505542fcfa6n);\n if ((absTick & 0x10000n) !== 0n)\n ratio = mulShift(ratio, 0x9aa508b5b7a84e1c677de54f3e99bc9n);\n if ((absTick & 0x20000n) !== 0n)\n ratio = mulShift(ratio, 0x5d6af8dedb81196699c329225ee604n);\n if ((absTick & 0x40000n) !== 0n)\n ratio = mulShift(ratio, 0x2216e584f5fa1ea926041bedfe98n);\n if ((absTick & 0x80000n) !== 0n)\n ratio = mulShift(ratio, 0x48a170391f7dc42444e8fa2n);\n\n if (tick > 0) {\n const max256 = (1n << 256n) - 1n;\n ratio = max256 / ratio;\n }\n\n // Shift from Q128.128 → Q64.96 with ceiling rounding (matches the\n // reference Solidity behavior).\n return (ratio >> 32n) + (ratio % (1n << 32n) === 0n ? 0n : 1n);\n}\n\n/**\n * Convert a sqrtPriceX96 back to the largest tick whose\n * `tickToSqrtPriceX96(tick)` is <= the input. Inverse of\n * `tickToSqrtPriceX96`, equivalent to\n * `TickMath.getTickAtSqrtRatio(sqrtPriceX96)`.\n *\n * Uses a most-significant-bit (MSB) search + iterative refinement.\n *\n * @throws if `sqrtPriceX96` is outside `[MIN_SQRT_RATIO, MAX_SQRT_RATIO)`\n */\nexport function sqrtPriceX96ToTick(sqrtPriceX96: bigint): number {\n if (sqrtPriceX96 < MIN_SQRT_RATIO || sqrtPriceX96 >= MAX_SQRT_RATIO) {\n throw new Error(\n `sqrtPriceX96ToTick: sqrtPriceX96 ${sqrtPriceX96} out of range ` +\n `[${MIN_SQRT_RATIO}, ${MAX_SQRT_RATIO})`,\n );\n }\n\n const ratio = sqrtPriceX96 << 32n;\n\n // Find the most significant bit (MSB) of `ratio`.\n let r = ratio;\n let msb = 0n;\n for (const [shift, value] of [\n [128n, 0xffffffffffffffffffffffffffffffffn],\n [64n, 0xffffffffffffffffn],\n [32n, 0xffffffffn],\n [16n, 0xffffn],\n [8n, 0xffn],\n [4n, 0xfn],\n [2n, 0x3n],\n [1n, 0x1n],\n ] as const) {\n const f = r > value ? shift : 0n;\n msb |= f;\n r >>= f;\n }\n\n // Normalize to Q128.128 fixed point.\n r = msb >= 128n ? ratio >> (msb - 127n) : ratio << (127n - msb);\n\n let log2: bigint = (msb - 128n) << 64n;\n\n for (let i = 0; i < 14; i++) {\n r = (r * r) >> 127n;\n const f = r >> 128n;\n log2 |= f << BigInt(63 - i);\n r >>= f;\n }\n\n const logSqrt10001 = log2 * 255738958999603826347141n;\n\n const tickLow = Number(\n (logSqrt10001 - 3402992956809132418596140100660247210n) >> 128n,\n );\n const tickHigh = Number(\n (logSqrt10001 + 291339464771989622907027621153398088495n) >> 128n,\n );\n\n if (tickLow === tickHigh) return tickLow;\n return tickToSqrtPriceX96(tickHigh) <= sqrtPriceX96 ? tickHigh : tickLow;\n}\n\n// ─── Tick spacing helpers ───────────────────────────────────────────────────\n\n/**\n * Snap a tick to the nearest multiple of `tickSpacing` (rounds toward\n * zero). Use to convert a user-entered tick to one the pool will accept.\n */\nexport function nearestUsableTick(tick: number, tickSpacing: number): number {\n if (!Number.isInteger(tick) || !Number.isInteger(tickSpacing)) {\n throw new Error(\"nearestUsableTick: both arguments must be integers\");\n }\n if (tickSpacing <= 0) {\n throw new Error(\n `nearestUsableTick: tickSpacing must be positive, got ${tickSpacing}`,\n );\n }\n const rounded = Math.round(tick / tickSpacing) * tickSpacing;\n if (rounded < MIN_TICK) return rounded + tickSpacing;\n if (rounded > MAX_TICK) return rounded - tickSpacing;\n return rounded;\n}\n\n/** Minimum tick aligned to `tickSpacing`, clipped to `MIN_TICK`. */\nexport function minUsableTick(tickSpacing: number): number {\n return Math.ceil(MIN_TICK / tickSpacing) * tickSpacing;\n}\n\n/** Maximum tick aligned to `tickSpacing`, clipped to `MAX_TICK`. */\nexport function maxUsableTick(tickSpacing: number): number {\n return Math.floor(MAX_TICK / tickSpacing) * tickSpacing;\n}\n\n/**\n * Standard fee-tier → tickSpacing mapping. Matches Uniswap V3 mainnet\n * conventions and is verified on-chain for PAFI's V3-fork deployment.\n * Returns `undefined` for non-standard fees; the caller should then read\n * `factory.feeAmountTickSpacing(fee)` to be safe.\n */\nexport function tickSpacingForFee(fee: number): number | undefined {\n switch (fee) {\n case 100:\n return 1;\n case 500:\n return 10;\n case 3000:\n return 60;\n case 10000:\n return 200;\n default:\n return undefined;\n }\n}\n\n// ─── Price ↔ tick (decimals-aware) ─────────────────────────────────────────\n\n/**\n * Convert a human-readable price (`token1` per `token0`) to a tick.\n * Decimals are factored in so callers can pass real-world quantities.\n *\n * Returned tick may need `nearestUsableTick()` to be pool-valid.\n */\nexport function priceToTick(params: {\n price: number;\n token0Decimals: number;\n token1Decimals: number;\n}): number {\n const { price, token0Decimals, token1Decimals } = params;\n if (price <= 0 || !Number.isFinite(price)) {\n throw new Error(`priceToTick: price must be a positive finite number, got ${price}`);\n }\n // Raw-amount price = human_price * 10^(decimals1 - decimals0).\n const rawPrice = price * 10 ** (token1Decimals - token0Decimals);\n // tick = log_{1.0001}(price) = ln(price) / ln(1.0001)\n return Math.floor(Math.log(rawPrice) / Math.log(1.0001));\n}\n\n/**\n * Convert a tick back to a human-readable price (`token1` per `token0`).\n * Inverse of `priceToTick`.\n */\nexport function tickToPrice(params: {\n tick: number;\n token0Decimals: number;\n token1Decimals: number;\n}): number {\n const { tick, token0Decimals, token1Decimals } = params;\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToPrice: tick must be an integer, got ${tick}`);\n }\n const rawPrice = Math.pow(1.0001, tick);\n return rawPrice / 10 ** (token1Decimals - token0Decimals);\n}\n\n// ─── Amount ↔ liquidity ─────────────────────────────────────────────────────\n\n/**\n * Token0 amount required to provide `liquidity` over [sqrtL, sqrtU].\n * Matches `SqrtPriceMath.getAmount0Delta(..., roundUp=true)` from V3.\n */\nexport function getAmount0ForLiquidity(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n liquidity: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (liquidity <= 0n) return 0n;\n const numerator = liquidity << 96n;\n const diff = sqrtPriceX96Upper - sqrtPriceX96Lower;\n return mulDivCeil(numerator * diff, 1n, sqrtPriceX96Upper * sqrtPriceX96Lower);\n}\n\n/**\n * Token1 amount required to provide `liquidity` over [sqrtL, sqrtU].\n * Matches `SqrtPriceMath.getAmount1Delta(..., roundUp=true)` from V3.\n */\nexport function getAmount1ForLiquidity(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n liquidity: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (liquidity <= 0n) return 0n;\n return mulDivCeil(liquidity, sqrtPriceX96Upper - sqrtPriceX96Lower, Q96);\n}\n\n/**\n * Canonical \"given liquidity + range + current price, compute amounts\"\n * helper. Handles the three V3 cases (current below, in, or above range).\n */\nexport function getAmountsForLiquidity(params: {\n sqrtPriceX96Current: bigint;\n sqrtPriceX96Lower: bigint;\n sqrtPriceX96Upper: bigint;\n liquidity: bigint;\n}): { amount0: bigint; amount1: bigint } {\n let { sqrtPriceX96Lower, sqrtPriceX96Upper } = params;\n const { sqrtPriceX96Current, liquidity } = params;\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n\n if (sqrtPriceX96Current <= sqrtPriceX96Lower) {\n // Current price below range — position is all token0.\n return {\n amount0: getAmount0ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n ),\n amount1: 0n,\n };\n } else if (sqrtPriceX96Current < sqrtPriceX96Upper) {\n // Current price in range — position straddles both sides.\n return {\n amount0: getAmount0ForLiquidity(\n sqrtPriceX96Current,\n sqrtPriceX96Upper,\n liquidity,\n ),\n amount1: getAmount1ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Current,\n liquidity,\n ),\n };\n } else {\n // Current price above range — position is all token1.\n return {\n amount0: 0n,\n amount1: getAmount1ForLiquidity(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n ),\n };\n }\n}\n\n/**\n * Liquidity that `amount0` of token0 would buy over [sqrtL, sqrtU].\n * Used when the user pins `amount0Desired` and the range is at-or-below\n * current price.\n */\nexport function getLiquidityForAmount0(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n amount0: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (amount0 <= 0n) return 0n;\n const intermediate = mulDivFloor(sqrtPriceX96Lower, sqrtPriceX96Upper, Q96);\n return mulDivFloor(amount0, intermediate, sqrtPriceX96Upper - sqrtPriceX96Lower);\n}\n\n/**\n * Liquidity that `amount1` of token1 would buy over [sqrtL, sqrtU].\n * Used when the user pins `amount1Desired` and the range is at-or-above\n * current price.\n */\nexport function getLiquidityForAmount1(\n sqrtPriceX96Lower: bigint,\n sqrtPriceX96Upper: bigint,\n amount1: bigint,\n): bigint {\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n if (amount1 <= 0n) return 0n;\n return mulDivFloor(amount1, Q96, sqrtPriceX96Upper - sqrtPriceX96Lower);\n}\n\n/**\n * High-level estimator. Caller has current spot + range + ONE side's\n * amount; returns the liquidity and the matching amounts.\n *\n * Branches:\n * - Current spot below range → amount0 drives, amount1 = 0.\n * - Current spot above range → amount1 drives, amount0 = 0.\n * - Current spot in range → caller's pinned side drives liquidity;\n * the other side is recomputed from that\n * liquidity at the current price.\n *\n * @throws if neither or both of amount0Desired / amount1Desired are set,\n * or if the pinned side is incompatible with the position\n * (e.g. amount1 pinned but spot < range).\n */\nexport function estimateLiquidityFromOneSide(params: {\n sqrtPriceX96Current: bigint;\n sqrtPriceX96Lower: bigint;\n sqrtPriceX96Upper: bigint;\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n}): { liquidity: bigint; amount0: bigint; amount1: bigint } {\n let { sqrtPriceX96Lower, sqrtPriceX96Upper } = params;\n const {\n sqrtPriceX96Current,\n amount0Desired,\n amount1Desired,\n } = params;\n\n if (sqrtPriceX96Lower > sqrtPriceX96Upper) {\n [sqrtPriceX96Lower, sqrtPriceX96Upper] = [\n sqrtPriceX96Upper,\n sqrtPriceX96Lower,\n ];\n }\n\n const has0 = amount0Desired !== undefined && amount0Desired > 0n;\n const has1 = amount1Desired !== undefined && amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"estimateLiquidityFromOneSide: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n\n if (sqrtPriceX96Current <= sqrtPriceX96Lower) {\n // Current price below range — token0-only position.\n if (!has0) {\n throw new Error(\n \"estimateLiquidityFromOneSide: spot is below range; pin amount0Desired (token1 isn't required)\",\n );\n }\n const liquidity = getLiquidityForAmount0(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n amount0Desired!,\n );\n return { liquidity, amount0: amount0Desired!, amount1: 0n };\n }\n\n if (sqrtPriceX96Current >= sqrtPriceX96Upper) {\n // Current price above range — token1-only position.\n if (!has1) {\n throw new Error(\n \"estimateLiquidityFromOneSide: spot is above range; pin amount1Desired (token0 isn't required)\",\n );\n }\n const liquidity = getLiquidityForAmount1(\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n amount1Desired!,\n );\n return { liquidity, amount0: 0n, amount1: amount1Desired! };\n }\n\n // Current price in range — both sides active. Pinned side drives L.\n let liquidity: bigint;\n if (has0) {\n liquidity = getLiquidityForAmount0(\n sqrtPriceX96Current,\n sqrtPriceX96Upper,\n amount0Desired!,\n );\n } else {\n liquidity = getLiquidityForAmount1(\n sqrtPriceX96Lower,\n sqrtPriceX96Current,\n amount1Desired!,\n );\n }\n const amounts = getAmountsForLiquidity({\n sqrtPriceX96Current,\n sqrtPriceX96Lower,\n sqrtPriceX96Upper,\n liquidity,\n });\n return {\n liquidity,\n amount0: has0 ? amount0Desired! : amounts.amount0,\n amount1: has1 ? amount1Desired! : amounts.amount1,\n };\n}\n\n// ─── Slippage helpers ───────────────────────────────────────────────────────\n\n/**\n * Apply slippage to `(amount0Desired, amount1Desired)` for an add or\n * increase, returning the `(amount0Min, amount1Min)` tuple to send to\n * NPM. Floor div — the on-chain minimum must round DOWN for safety.\n */\nexport function applyMintSlippage(params: {\n amount0Desired: bigint;\n amount1Desired: bigint;\n slippageBps: number;\n}): { amount0Min: bigint; amount1Min: bigint } {\n const { amount0Desired, amount1Desired, slippageBps } = params;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `applyMintSlippage: slippageBps must be integer in [0, 10000], got ${slippageBps}`,\n );\n }\n const num = BigInt(10000 - slippageBps);\n return {\n amount0Min: (amount0Desired * num) / 10000n,\n amount1Min: (amount1Desired * num) / 10000n,\n };\n}\n\n/**\n * Apply slippage to expected `(amount0, amount1)` for a decrease/close,\n * returning `(amount0Min, amount1Min)` to send to NPM. Floor div, same\n * rationale as `applyMintSlippage`.\n */\nexport function applyRemoveSlippage(params: {\n amount0Expected: bigint;\n amount1Expected: bigint;\n slippageBps: number;\n}): { amount0Min: bigint; amount1Min: bigint } {\n const { amount0Expected, amount1Expected, slippageBps } = params;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `applyRemoveSlippage: slippageBps must be integer in [0, 10000], got ${slippageBps}`,\n );\n }\n const num = BigInt(10000 - slippageBps);\n return {\n amount0Min: (amount0Expected * num) / 10000n,\n amount1Min: (amount1Expected * num) / 10000n,\n };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\n/**\n * Decoded `NPM.positions(tokenId)` row.\n *\n * Fields mirror the 12-tuple returned by the contract, named for\n * readability. `feeGrowthInside*LastX128` are Q128.128 fixed-point —\n * used together with `pool.feeGrowthGlobal*X128()` and `pool.ticks(...)`\n * to derive pending fees in `collectFeesDirect`.\n */\nexport interface PositionInfo {\n nonce: bigint;\n operator: Address;\n token0: Address;\n token1: Address;\n fee: number;\n tickLower: number;\n tickUpper: number;\n liquidity: bigint;\n feeGrowthInside0LastX128: bigint;\n feeGrowthInside1LastX128: bigint;\n tokensOwed0: bigint;\n tokensOwed1: bigint;\n}\n\n/**\n * Read an NFT position's state by tokenId.\n *\n * @param client viem PublicClient\n * @param npm NonfungiblePositionManager address (`V3_NPM_ADDRESSES[chainId]`)\n * @param tokenId The NFT id\n */\nexport async function readPosition(\n client: PublicClient,\n npm: Address,\n tokenId: bigint,\n): Promise<PositionInfo> {\n const result = (await client.readContract({\n address: npm,\n abi: nonfungiblePositionManagerAbi,\n functionName: \"positions\",\n args: [tokenId],\n })) as readonly [\n bigint, // nonce\n Address, // operator\n Address, // token0\n Address, // token1\n number, // fee\n number, // tickLower\n number, // tickUpper\n bigint, // liquidity\n bigint, // feeGrowthInside0LastX128\n bigint, // feeGrowthInside1LastX128\n bigint, // tokensOwed0\n bigint, // tokensOwed1\n ];\n\n return {\n nonce: result[0],\n operator: result[1],\n token0: result[2],\n token1: result[3],\n fee: result[4],\n tickLower: result[5],\n tickUpper: result[6],\n liquidity: result[7],\n feeGrowthInside0LastX128: result[8],\n feeGrowthInside1LastX128: result[9],\n tokensOwed0: result[10],\n tokensOwed1: result[11],\n };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { v3PoolAbi } from \"./abi\";\n\n/**\n * Distilled V3 pool state — the fields LP flows need to estimate amounts\n * and validate ticks.\n */\nexport interface PoolState {\n sqrtPriceX96: bigint;\n /** Current tick (`int24` from slot0). */\n tick: number;\n /** In-range liquidity at the current tick. */\n liquidity: bigint;\n tickSpacing: number;\n /** Fee tier in hundredths of a basis point (e.g. `3000` = 0.3%). */\n fee: number;\n}\n\n/**\n * Per-tick state read from `pool.ticks(tick)`. Only the fields LP flows\n * use are kept; the rest of the tuple is dropped.\n */\nexport interface TickInfo {\n liquidityGross: bigint;\n liquidityNet: bigint;\n feeGrowthOutside0X128: bigint;\n feeGrowthOutside1X128: bigint;\n initialized: boolean;\n}\n\n/**\n * Pool fee-growth globals — used together with `TickInfo` and the\n * position's `feeGrowthInside*LastX128` to compute pending fees.\n */\nexport interface PoolFeeGrowthGlobals {\n feeGrowthGlobal0X128: bigint;\n feeGrowthGlobal1X128: bigint;\n}\n\n/**\n * Read a pool's current state in a single multicall.\n *\n * @param client viem PublicClient\n * @param pool Pool address (use `computeV3PoolAddress` to derive)\n */\nexport async function readPoolState(\n client: PublicClient,\n pool: Address,\n /** Pin reads to this block. Default: latest (matches prior behavior). */\n blockNumber?: bigint,\n): Promise<PoolState> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"slot0\" },\n { address: pool, abi: v3PoolAbi, functionName: \"liquidity\" },\n { address: pool, abi: v3PoolAbi, functionName: \"tickSpacing\" },\n { address: pool, abi: v3PoolAbi, functionName: \"fee\" },\n ],\n allowFailure: false,\n blockNumber,\n });\n\n const slot0 = results[0] as readonly [\n bigint, // sqrtPriceX96\n number, // tick\n number,\n number,\n number,\n number,\n boolean,\n ];\n\n return {\n sqrtPriceX96: slot0[0],\n tick: slot0[1],\n liquidity: results[1] as bigint,\n tickSpacing: results[2] as number,\n fee: results[3] as number,\n };\n}\n\n/**\n * Read tick info for `tickLower` and `tickUpper` in a single multicall.\n *\n * Used by `collectFeesDirect` to compute `feeGrowthInside*` (and from\n * that, the pending-fee estimate).\n */\nexport async function readTicksAt(\n client: PublicClient,\n pool: Address,\n tickLower: number,\n tickUpper: number,\n): Promise<{ lower: TickInfo; upper: TickInfo }> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"ticks\", args: [tickLower] },\n { address: pool, abi: v3PoolAbi, functionName: \"ticks\", args: [tickUpper] },\n ],\n allowFailure: false,\n });\n\n const toTickInfo = (r: unknown): TickInfo => {\n const tuple = r as readonly [\n bigint, // liquidityGross\n bigint, // liquidityNet\n bigint, // feeGrowthOutside0X128\n bigint, // feeGrowthOutside1X128\n bigint, // tickCumulativeOutside\n bigint, // secondsPerLiquidityOutsideX128\n bigint, // secondsOutside\n boolean,\n ];\n return {\n liquidityGross: tuple[0],\n liquidityNet: tuple[1],\n feeGrowthOutside0X128: tuple[2],\n feeGrowthOutside1X128: tuple[3],\n initialized: tuple[7],\n };\n };\n\n return {\n lower: toTickInfo(results[0]),\n upper: toTickInfo(results[1]),\n };\n}\n\n/**\n * Read pool fee-growth globals.\n *\n * Could be folded into `readPoolState` but kept separate so that flows\n * which don't need fee tracking (mint, decrease) don't waste an RPC on\n * the extra two reads.\n */\nexport async function readFeeGrowthGlobals(\n client: PublicClient,\n pool: Address,\n): Promise<PoolFeeGrowthGlobals> {\n const results = await client.multicall({\n contracts: [\n { address: pool, abi: v3PoolAbi, functionName: \"feeGrowthGlobal0X128\" },\n { address: pool, abi: v3PoolAbi, functionName: \"feeGrowthGlobal1X128\" },\n ],\n allowFailure: false,\n });\n\n return {\n feeGrowthGlobal0X128: results[0] as bigint,\n feeGrowthGlobal1X128: results[1] as bigint,\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { erc20ApproveOp } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildMintParams {\n /** NonfungiblePositionManager address (`V3_NPM_ADDRESSES[chainId]`). */\n npm: Address;\n token0: Address;\n token1: Address;\n fee: number;\n tickLower: number;\n tickUpper: number;\n /** Exact amount0 caller is approving + sending. */\n amount0Desired: bigint;\n /** Exact amount1 caller is approving + sending. */\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** Position NFT recipient — typically the user's EOA. */\n recipient: Address;\n /** Unix seconds. NPM reverts if `block.timestamp > deadline`. */\n deadline: bigint;\n}\n\n/**\n * Build the 3-op batch for `addLiquidityDirect`:\n *\n * 1. token0.approve(NPM, amount0Desired)\n * 2. token1.approve(NPM, amount1Desired)\n * 3. NPM.mint({ ... })\n *\n * Approvals are per-call exact (not `max`) — leaves zero residual\n * allowance after the batch, preventing a stale approve from being\n * front-run on a later mint.\n *\n * Caller is responsible for ordering `token0 < token1` (V3 invariant);\n * this builder doesn't sort, since the desired/min amounts are\n * positional and re-sorting would break them.\n */\nexport function buildMint(params: BuildMintParams): Operation[] {\n return [\n erc20ApproveOp(params.token0, params.npm, params.amount0Desired),\n erc20ApproveOp(params.token1, params.npm, params.amount1Desired),\n {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"mint\",\n args: [\n {\n token0: params.token0,\n token1: params.token1,\n fee: params.fee,\n tickLower: params.tickLower,\n tickUpper: params.tickUpper,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n recipient: params.recipient,\n deadline: params.deadline,\n },\n ],\n }),\n },\n ];\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { erc20ApproveOp } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildIncreaseLiquidityParams {\n npm: Address;\n token0: Address;\n token1: Address;\n tokenId: bigint;\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Build the 3-op batch for `increaseLiquidityDirect`:\n *\n * 1. token0.approve(NPM, amount0Desired)\n * 2. token1.approve(NPM, amount1Desired)\n * 3. NPM.increaseLiquidity({ tokenId, ... })\n *\n * Range comes from the existing position — caller resolves it via\n * `readPosition(tokenId)` before calling this builder.\n */\nexport function buildIncreaseLiquidity(\n params: BuildIncreaseLiquidityParams,\n): Operation[] {\n return [\n erc20ApproveOp(params.token0, params.npm, params.amount0Desired),\n erc20ApproveOp(params.token1, params.npm, params.amount1Desired),\n {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"increaseLiquidity\",\n args: [\n {\n tokenId: params.tokenId,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n },\n ],\n }),\n },\n ];\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildDecreaseLiquidityParams {\n npm: Address;\n tokenId: bigint;\n liquidity: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Build a single `NPM.decreaseLiquidity({ ... })` Operation.\n *\n * No approvals needed — NPM doesn't pull tokens on decrease (it credits\n * the position's `tokensOwed0/1`, which a subsequent `collect()` flushes\n * to the recipient).\n */\nexport function buildDecreaseLiquidity(\n params: BuildDecreaseLiquidityParams,\n): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"decreaseLiquidity\",\n args: [\n {\n tokenId: params.tokenId,\n liquidity: params.liquidity,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n },\n ],\n }),\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\nimport { UINT128_MAX } from \"./constants\";\n\nexport interface BuildCollectParams {\n npm: Address;\n tokenId: bigint;\n /** Where the collected fees + principal go. Typically the user's EOA. */\n recipient: Address;\n /** Caps on the transfer. Default `UINT128_MAX` → take everything owed. */\n amount0Max?: bigint;\n amount1Max?: bigint;\n}\n\n/**\n * Build a single `NPM.collect({ ... })` Operation.\n *\n * When the position still has `liquidity > 0`, NPM internally calls\n * `pool.burn(tickLower, tickUpper, 0)` to flush newly-accrued fees into\n * `tokensOwed*` before transferring. So a standalone collect on an\n * active position both accrues AND claims in one tx.\n *\n * For collect-everything use the default `UINT128_MAX` caps.\n */\nexport function buildCollect(params: BuildCollectParams): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"collect\",\n args: [\n {\n tokenId: params.tokenId,\n recipient: params.recipient,\n amount0Max: params.amount0Max ?? UINT128_MAX,\n amount1Max: params.amount1Max ?? UINT128_MAX,\n },\n ],\n }),\n };\n}\n","import { encodeFunctionData, type Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { nonfungiblePositionManagerAbi } from \"./abi\";\n\nexport interface BuildBurnParams {\n npm: Address;\n tokenId: bigint;\n}\n\n/**\n * Build a single `NPM.burn(tokenId)` Operation.\n *\n * NPM enforces three preconditions on burn:\n * - `position.liquidity == 0`\n * - `position.tokensOwed0 == 0`\n * - `position.tokensOwed1 == 0`\n *\n * For a full close, batch `decreaseLiquidity(all) → collect → burn`. The\n * `buildClosePosition` orchestrator wires that for you; this builder is\n * exposed for callers that already know the preconditions hold (e.g.\n * burning an already-emptied position).\n */\nexport function buildBurn(params: BuildBurnParams): Operation {\n return {\n target: params.npm,\n value: 0n,\n data: encodeFunctionData({\n abi: nonfungiblePositionManagerAbi,\n functionName: \"burn\",\n args: [params.tokenId],\n }),\n };\n}\n","import type { Address } from \"viem\";\nimport type { Operation } from \"@pafi-dev/core\";\nimport { buildDecreaseLiquidity } from \"./buildDecreaseLiquidity\";\nimport { buildCollect } from \"./buildCollect\";\nimport { buildBurn } from \"./buildBurn\";\n\nexport interface BuildClosePositionParams {\n npm: Address;\n tokenId: bigint;\n /** Current `position.liquidity`. Determines batch shape. */\n liquidity: bigint;\n /** `tokensOwed0 + tokensOwed1 > 0` → still need a collect leg. */\n hasOutstandingFees: boolean;\n /** Recipient of the collected tokens. Typically the user's EOA. */\n recipient: Address;\n /** Slippage-applied minimums for the decrease leg. */\n amount0Min: bigint;\n amount1Min: bigint;\n /** Unix seconds. Required for the decrease leg if liquidity > 0. */\n deadline: bigint;\n}\n\n/**\n * Build the full-close batch:\n *\n * - `liquidity > 0`: decreaseLiquidity(all) → collect → burn\n * - `liquidity == 0` + fees: collect → burn\n * - `liquidity == 0` + no fees: burn (only)\n *\n * The shape selection avoids unnecessary calls — burning an empty\n * position with no fees is a 1-op batch. Callers don't need to think\n * about the cases; pass the snapshot and the builder picks.\n */\nexport function buildClosePosition(\n params: BuildClosePositionParams,\n): Operation[] {\n const ops: Operation[] = [];\n\n if (params.liquidity > 0n) {\n ops.push(\n buildDecreaseLiquidity({\n npm: params.npm,\n tokenId: params.tokenId,\n liquidity: params.liquidity,\n amount0Min: params.amount0Min,\n amount1Min: params.amount1Min,\n deadline: params.deadline,\n }),\n );\n }\n\n if (params.liquidity > 0n || params.hasOutstandingFees) {\n ops.push(\n buildCollect({\n npm: params.npm,\n tokenId: params.tokenId,\n recipient: params.recipient,\n }),\n );\n }\n\n ops.push(buildBurn({ npm: params.npm, tokenId: params.tokenId }));\n\n return ops;\n}\n","import { minUsableTick, maxUsableTick } from \"./math\";\n\n/**\n * Compute the (word, bit) position of a tick in V3's bitmap layout.\n *\n * Mirrors Solidity `TickBitmap.position(int24)`:\n * compressed = tick / tickSpacing (floor div, not trunc)\n * word = compressed >> 8 (JS arithmetic shift on int32)\n * bit = ((compressed % 256) + 256) % 256 (JS `%` is sign-preserving — normalize)\n *\n * Throws if `tick` or `tickSpacing` is not an integer, if `tickSpacing <= 0`,\n * or if `tick` is not aligned to `tickSpacing`.\n */\nexport function tickToBitmapPosition(\n tick: number,\n tickSpacing: number,\n): { word: number; bit: number } {\n if (!Number.isInteger(tick)) {\n throw new Error(`tickToBitmapPosition: tick (${tick}) must be an integer`);\n }\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) {\n throw new Error(\n `tickToBitmapPosition: tickSpacing (${tickSpacing}) must be a positive integer`,\n );\n }\n if (tick % tickSpacing !== 0) {\n throw new Error(\n `tickToBitmapPosition: tick (${tick}) must be a multiple of tickSpacing ${tickSpacing}`,\n );\n }\n const compressed = Math.floor(tick / tickSpacing);\n const word = compressed >> 8;\n const bit = ((compressed % 256) + 256) % 256;\n return { word, bit };\n}\n\n/**\n * Decode set bits of a single bitmap word into absolute tick indices.\n * Returns sorted ascending. O(1) when `bitmap === 0n`.\n *\n * Bitmap is uint256 → scans bit positions 0..255 inclusive. Decoded with\n * bigint primitives — `Number` would lose bits past position 53.\n */\nexport function decodeBitmapWord(\n bitmap: bigint,\n wordPos: number,\n tickSpacing: number,\n): number[] {\n if (bitmap === 0n) return [];\n const out: number[] = [];\n for (let bit = 0; bit < 256; bit++) {\n if ((bitmap & (1n << BigInt(bit))) !== 0n) {\n out.push((wordPos * 256 + bit) * tickSpacing);\n }\n }\n return out;\n}\n\n/**\n * Min/max wordPos required to scan an entire V3 pool's bitmap for the\n * given tickSpacing. Derived from `minUsableTick(spacing)` /\n * `maxUsableTick(spacing)`, not raw MIN/MAX_TICK.\n */\nexport function bitmapWordRange(tickSpacing: number): { min: number; max: number } {\n const lo = minUsableTick(tickSpacing);\n const hi = maxUsableTick(tickSpacing);\n return {\n min: Math.floor(lo / tickSpacing) >> 8,\n max: Math.floor(hi / tickSpacing) >> 8,\n };\n}\n","import {\n minUsableTick,\n maxUsableTick,\n tickToSqrtPriceX96,\n} from \"./math\";\nimport type { TickInfo } from \"./readPoolState\";\n\n/**\n * Discriminated error codes for the liquidity-curve subsystem. Use with\n * `LiquidityCurveError`: callers `instanceof LiquidityCurveError` then\n * branch on `code` to decide retry / Sentry / user-copy behavior.\n */\nexport enum LiquidityCurveErrorCode {\n /** fetchAllInitializedTicks: initTicks.length > maxTicks. Recovery: raise maxTicks. */\n TOO_MANY_TICKS = \"TOO_MANY_TICKS\",\n /** fetchAllInitializedTicks: bitmap-vs-ticks() mismatch. Recovery: retry against latest. */\n ATOMICITY_VIOLATION = \"ATOMICITY_VIOLATION\",\n /** buildLiquidityCurve: sum(liquidityNet) !== 0. Tick set incomplete or stale. */\n CURVE_SUM_NONZERO = \"CURVE_SUM_NONZERO\",\n /** buildLiquidityCurve: cumulative L went negative during walk. */\n CURVE_NEGATIVE_L = \"CURVE_NEGATIVE_L\",\n /** buildLiquidityCurve: edge L !== 0. currentLiquidity inconsistent with ticks. */\n CURVE_EDGE_NONZERO = \"CURVE_EDGE_NONZERO\",\n}\n\nexport class LiquidityCurveError extends Error {\n readonly code: LiquidityCurveErrorCode;\n constructor(code: LiquidityCurveErrorCode, message: string) {\n super(message);\n this.name = \"LiquidityCurveError\";\n this.code = code;\n }\n}\n\nexport interface InitializedTick extends TickInfo {\n /** Absolute tick index — integer, divisible by `tickSpacing`. */\n tick: number;\n}\n\nexport interface LiquidityCurveSegment {\n /** Inclusive lower bound. For the leftmost segment, equals `minUsableTick(spacing)`. */\n tickLower: number;\n /** Exclusive upper bound. For the rightmost segment, equals `maxUsableTick(spacing)`. */\n tickUpper: number;\n /** `tickToSqrtPriceX96(tickLower)`. */\n sqrtPriceLowerX96: bigint;\n /** `tickToSqrtPriceX96(tickUpper)`. */\n sqrtPriceUpperX96: bigint;\n /** Active liquidity (`L`) constant across `[tickLower, tickUpper)`. */\n liquidityActive: bigint;\n}\n\nexport interface BuildLiquidityCurveParams {\n /** From `fetchAllInitializedTicks`. Must be the COMPLETE set, sorted asc. */\n ticks: InitializedTick[];\n /** From `poolState.tick`. */\n currentTick: number;\n /** From `poolState.liquidity`. */\n currentLiquidity: bigint;\n /** From `poolState.tickSpacing`. Drives edge-clamp + sqrt-price boundaries. */\n tickSpacing: number;\n}\n\n/**\n * Pure transformer. Produces N+1 half-open segments covering\n * `[minUsableTick(spacing), maxUsableTick(spacing))`, each with the\n * active liquidity that holds across it.\n *\n * Throws `LiquidityCurveError` on inconsistent input (see error codes).\n */\nexport function buildLiquidityCurve(\n params: BuildLiquidityCurveParams,\n): LiquidityCurveSegment[] {\n const { ticks, currentTick, currentLiquidity, tickSpacing } = params;\n const TICK_LO = minUsableTick(tickSpacing);\n const TICK_HI = maxUsableTick(tickSpacing);\n const N = ticks.length;\n\n // Consistency check 1: complete tick set sums to zero net.\n const sumNet = ticks.reduce((acc, t) => acc + t.liquidityNet, 0n);\n if (sumNet !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_SUM_NONZERO,\n `buildLiquidityCurve: sum(liquidityNet) = ${sumNet}, expected 0. ` +\n `Tick set is incomplete or fetched at a different block.`,\n );\n }\n\n // Empty pool: single segment spanning the full usable range.\n if (N === 0) {\n return [\n {\n tickLower: TICK_LO,\n tickUpper: TICK_HI,\n sqrtPriceLowerX96: tickToSqrtPriceX96(TICK_LO),\n sqrtPriceUpperX96: tickToSqrtPriceX96(TICK_HI),\n liquidityActive: currentLiquidity,\n },\n ];\n }\n\n // Binary search: i_above = first index with tick > currentTick.\n let lo = 0;\n let hi = N;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (ticks[mid]!.tick > currentTick) hi = mid;\n else lo = mid + 1;\n }\n const i_above = lo;\n const i_below = i_above - 1;\n\n // Invariant: segments[i] covers [low_i, high_i) where\n // low_i = (i === 0 ? TICK_LO : ticks[i-1].tick)\n // high_i = (i === N ? TICK_HI : ticks[i].tick)\n // Write-sets {i_above}, {0..i_below}, {i_above+1..N} partition [0,N].\n const segments: LiquidityCurveSegment[] = new Array(N + 1);\n\n const anchorLower = i_below >= 0 ? ticks[i_below]!.tick : TICK_LO;\n const anchorUpper = i_above < N ? ticks[i_above]!.tick : TICK_HI;\n segments[i_above] = {\n tickLower: anchorLower,\n tickUpper: anchorUpper,\n sqrtPriceLowerX96: 0n, // filled below\n sqrtPriceUpperX96: 0n,\n liquidityActive: currentLiquidity,\n };\n\n // Walk LEFT.\n let L = currentLiquidity;\n for (let k = i_below; k >= 0; k--) {\n L = L - ticks[k]!.liquidityNet;\n if (L < 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_NEGATIVE_L,\n `buildLiquidityCurve: active liquidity went negative at tick ${ticks[k]!.tick} ` +\n `during left walk. Indicates inconsistent input.`,\n );\n }\n const lower = k - 1 >= 0 ? ticks[k - 1]!.tick : TICK_LO;\n segments[k] = {\n tickLower: lower,\n tickUpper: ticks[k]!.tick,\n sqrtPriceLowerX96: 0n,\n sqrtPriceUpperX96: 0n,\n liquidityActive: L,\n };\n }\n\n // Walk RIGHT.\n L = currentLiquidity;\n for (let j = i_above; j < N; j++) {\n L = L + ticks[j]!.liquidityNet;\n if (L < 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_NEGATIVE_L,\n `buildLiquidityCurve: active liquidity went negative at tick ${ticks[j]!.tick} ` +\n `during right walk.`,\n );\n }\n const upper = j + 1 < N ? ticks[j + 1]!.tick : TICK_HI;\n segments[j + 1] = {\n tickLower: ticks[j]!.tick,\n tickUpper: upper,\n sqrtPriceLowerX96: 0n,\n sqrtPriceUpperX96: 0n,\n liquidityActive: L,\n };\n }\n\n // Consistency check 2: outside any LP range, L must be 0.\n if (segments[0]!.liquidityActive !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_EDGE_NONZERO,\n `buildLiquidityCurve: leftmost L = ${segments[0]!.liquidityActive}, expected 0. ` +\n `currentLiquidity inconsistent with tick set.`,\n );\n }\n if (segments[N]!.liquidityActive !== 0n) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.CURVE_EDGE_NONZERO,\n `buildLiquidityCurve: rightmost L = ${segments[N]!.liquidityActive}, expected 0.`,\n );\n }\n\n // Fill sqrt-price boundaries.\n for (const seg of segments) {\n seg.sqrtPriceLowerX96 = tickToSqrtPriceX96(seg.tickLower);\n seg.sqrtPriceUpperX96 = tickToSqrtPriceX96(seg.tickUpper);\n }\n\n return segments;\n}\n\n/**\n * Clip a curve to a tick viewport. Returns a new sub-range of `curve`\n * covering `[tickLo, tickHi]`, splitting segments that straddle the\n * viewport edges. Pure. O(log N) via binary search on `tickLower`.\n *\n * Returns `[]` if the viewport is entirely outside the curve's coverage.\n */\nexport function clipCurveToTickRange(\n curve: LiquidityCurveSegment[],\n tickLo: number,\n tickHi: number,\n): LiquidityCurveSegment[] {\n if (curve.length === 0 || tickHi <= tickLo) return [];\n\n // Binary search: first index with tickUpper > tickLo.\n let lo = 0;\n let hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickUpper > tickLo) hi = mid;\n else lo = mid + 1;\n }\n const startIdx = lo;\n\n // First index with tickLower >= tickHi.\n lo = 0;\n hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickLower >= tickHi) hi = mid;\n else lo = mid + 1;\n }\n const endIdx = lo; // exclusive\n\n if (startIdx >= endIdx) return [];\n\n const out: LiquidityCurveSegment[] = [];\n for (let i = startIdx; i < endIdx; i++) {\n const seg = curve[i]!;\n const newLower = Math.max(seg.tickLower, tickLo);\n const newUpper = Math.min(seg.tickUpper, tickHi);\n if (newLower === seg.tickLower && newUpper === seg.tickUpper) {\n out.push(seg);\n } else {\n out.push({\n tickLower: newLower,\n tickUpper: newUpper,\n sqrtPriceLowerX96: tickToSqrtPriceX96(newLower),\n sqrtPriceUpperX96: tickToSqrtPriceX96(newUpper),\n liquidityActive: seg.liquidityActive,\n });\n }\n }\n return out;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { v3PoolAbi } from \"./abi\";\nimport { bitmapWordRange, decodeBitmapWord } from \"./readTickBitmap\";\nimport {\n LiquidityCurveError,\n LiquidityCurveErrorCode,\n type InitializedTick,\n} from \"./buildLiquidityCurve\";\n\n/** Bytes of calldata per Phase 1 / Phase 2 call:\n * 4 (selector) + 32 (single int16 or int24 arg, ABI-padded) = 36 bytes.\n * Update this constant if a wider arg is ever added. */\nexport const CALLDATA_BYTES_PER_CALL = 36;\n\nconst DEFAULT_CALLS_PER_BATCH = 250;\nconst DEFAULT_MAX_TICKS = 50_000;\n\nexport interface FetchAllInitializedTicksParams {\n client: PublicClient;\n pool: Address;\n /** Pin reads to this block. Default: latest at fetch start. */\n blockNumber?: bigint;\n /** Override pool.tickSpacing read. Saves 1 RPC if caller has it. */\n tickSpacing?: number;\n /** Maximum *calls* per HTTP eth_call sub-batch. Default 250.\n * Translated to viem's byte-oriented batchSize via `* CALLDATA_BYTES_PER_CALL`. */\n callsPerBatch?: number;\n /** Hard cap on returned tick count. Default 50_000. */\n maxTicks?: number;\n}\n\nexport interface FetchAllInitializedTicksResult {\n blockNumber: bigint;\n tickSpacing: number;\n /** Sorted ascending by `tick`. */\n ticks: InitializedTick[];\n}\n\n/**\n * Fetch every initialized tick of a V3 pool atomically via two-phase\n * multicall (`tickBitmap` → `ticks`), pinned to a single `blockNumber`.\n */\nexport async function fetchAllInitializedTicks(\n params: FetchAllInitializedTicksParams,\n): Promise<FetchAllInitializedTicksResult> {\n const callsPerBatch = params.callsPerBatch ?? DEFAULT_CALLS_PER_BATCH;\n const maxTicks = params.maxTicks ?? DEFAULT_MAX_TICKS;\n const batchSizeBytes = callsPerBatch * CALLDATA_BYTES_PER_CALL;\n\n // Pin a block.\n const blockNumber =\n params.blockNumber ?? (await params.client.getBlockNumber());\n\n // Resolve tickSpacing.\n let tickSpacing = params.tickSpacing;\n if (tickSpacing === undefined) {\n const [resolved] = await params.client.multicall({\n contracts: [\n {\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"tickSpacing\",\n },\n ],\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n });\n tickSpacing = Number(resolved);\n }\n\n // ── Phase 1: bitmap multicall over the full word range ──────────────────\n const { min: wordLo, max: wordHi } = bitmapWordRange(tickSpacing);\n const bitmapContracts = [];\n for (let w = wordLo; w <= wordHi; w++) {\n bitmapContracts.push({\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"tickBitmap\" as const,\n args: [w] as const,\n });\n }\n\n const bitmaps = (await params.client.multicall({\n contracts: bitmapContracts,\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n })) as bigint[];\n\n // Decode set bits into a flat sorted list of tick indices.\n const initTicks: number[] = [];\n for (let i = 0; i < bitmaps.length; i++) {\n const word = bitmaps[i]!;\n if (word === 0n) continue;\n const wordPos = wordLo + i;\n const decoded = decodeBitmapWord(word, wordPos, tickSpacing);\n for (const t of decoded) initTicks.push(t);\n }\n\n if (initTicks.length > maxTicks) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.TOO_MANY_TICKS,\n `fetchAllInitializedTicks: pool ${params.pool} has ${initTicks.length} ` +\n `initialized ticks, exceeds maxTicks=${maxTicks}. ` +\n `Pass maxTicks explicitly if you want the full set.`,\n );\n }\n\n // Short-circuit empty pool.\n if (initTicks.length === 0) {\n return { blockNumber, tickSpacing, ticks: [] };\n }\n\n // ── Phase 2: ticks multicall ────────────────────────────────────────────\n const ticksContracts = initTicks.map(\n (tick) =>\n ({\n address: params.pool,\n abi: v3PoolAbi,\n functionName: \"ticks\" as const,\n args: [tick] as const,\n } as const),\n );\n\n const ticksTuples = (await params.client.multicall({\n contracts: ticksContracts,\n allowFailure: false,\n blockNumber,\n batchSize: batchSizeBytes,\n })) as readonly (readonly [\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n bigint,\n boolean,\n ])[];\n\n const ticks: InitializedTick[] = ticksTuples.map((tuple, i) => ({\n tick: initTicks[i]!,\n liquidityGross: tuple[0],\n liquidityNet: tuple[1],\n feeGrowthOutside0X128: tuple[2],\n feeGrowthOutside1X128: tuple[3],\n initialized: tuple[7],\n }));\n\n // Atomicity check.\n for (const t of ticks) {\n if (!t.initialized) {\n throw new LiquidityCurveError(\n LiquidityCurveErrorCode.ATOMICITY_VIOLATION,\n `fetchAllInitializedTicks: tick ${t.tick} bitmap-set but ` +\n `ticks().initialized=false at block ${blockNumber}. ` +\n `Snapshot is torn — RPC node likely served different blocks across batches.`,\n );\n }\n }\n\n return { blockNumber, tickSpacing, ticks };\n}\n","import type { Address, PublicClient } from \"viem\";\nimport { readPoolState, type PoolState } from \"./readPoolState\";\nimport {\n fetchAllInitializedTicks,\n type FetchAllInitializedTicksParams,\n} from \"./fetchAllInitializedTicks\";\nimport {\n buildLiquidityCurve,\n type InitializedTick,\n type LiquidityCurveSegment,\n} from \"./buildLiquidityCurve\";\n\nexport interface FetchLiquidityCurveParams {\n client: PublicClient;\n pool: Address;\n blockNumber?: bigint;\n /** Pre-fetched pool state. If provided, MUST have been observed at\n * `blockNumber` (caller's responsibility). When omitted, fetched here. */\n poolState?: PoolState;\n /** Forwarded to fetchAllInitializedTicks. */\n callsPerBatch?: FetchAllInitializedTicksParams[\"callsPerBatch\"];\n maxTicks?: FetchAllInitializedTicksParams[\"maxTicks\"];\n}\n\nexport interface FetchLiquidityCurveResult {\n blockNumber: bigint;\n poolState: PoolState;\n ticks: InitializedTick[];\n curve: LiquidityCurveSegment[];\n /** Index into `curve` of the segment containing `poolState.tick`.\n * Invariant: `curve[currentSegmentIndex].tickLower <= poolState.tick < curve[currentSegmentIndex].tickUpper`. */\n currentSegmentIndex: number;\n}\n\n/**\n * One-call convenience for the FE add-liquidity chart. Reads pool state,\n * fetches all initialized ticks, builds the curve — all pinned to the\n * same block.\n *\n * @throws {LiquidityCurveError} with `.code`:\n * - `TOO_MANY_TICKS` — pool has more than `maxTicks` initialized ticks\n * - `ATOMICITY_VIOLATION` — bitmap-vs-ticks() mismatch (rare; retry against latest)\n * - `CURVE_SUM_NONZERO` — tick set incomplete (caller passed a stale `poolState`)\n * - `CURVE_NEGATIVE_L` — cumulative liquidity went negative during walk\n * - `CURVE_EDGE_NONZERO` — `poolState` inconsistent with ticks (likely stale)\n */\nexport async function fetchLiquidityCurve(\n params: FetchLiquidityCurveParams,\n): Promise<FetchLiquidityCurveResult> {\n const blockNumber =\n params.blockNumber ?? (await params.client.getBlockNumber());\n\n const poolState =\n params.poolState ?? (await readPoolState(params.client, params.pool, blockNumber));\n\n const ticksResult = await fetchAllInitializedTicks({\n client: params.client,\n pool: params.pool,\n blockNumber,\n tickSpacing: poolState.tickSpacing,\n callsPerBatch: params.callsPerBatch,\n maxTicks: params.maxTicks,\n });\n\n const curve = buildLiquidityCurve({\n ticks: ticksResult.ticks,\n currentTick: poolState.tick,\n currentLiquidity: poolState.liquidity,\n tickSpacing: poolState.tickSpacing,\n });\n\n // Binary-search currentSegmentIndex.\n let lo = 0;\n let hi = curve.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (curve[mid]!.tickUpper > poolState.tick) hi = mid;\n else lo = mid + 1;\n }\n const currentSegmentIndex = lo;\n\n return {\n blockNumber,\n poolState,\n ticks: ticksResult.ticks,\n curve,\n currentSegmentIndex,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildIncreaseLiquidity,\n readPosition,\n readPoolState,\n estimateLiquidityFromOneSide,\n applyMintSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface IncreaseLiquidityDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n /** Existing position NFT id. SDK reads its range + token pair. */\n tokenId: bigint;\n\n amount0Desired?: bigint;\n amount1Desired?: bigint;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface IncreaseLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n amount0Desired: bigint;\n amount1Desired: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n /** L added (estimated off-chain; receipt-parsed value would be authoritative). */\n liquidityAdded: bigint;\n deadline: bigint;\n}\n\n/**\n * Top up an existing V3 LP position via NPM.increaseLiquidity.\n *\n * Range comes from the existing position; user only specifies one side's\n * amount and the SDK computes the rest. Same 3-op batch as add (two\n * approvals + the NPM call), but range is read on-chain rather than\n * supplied by caller.\n */\nexport async function increaseLiquidityDirect(\n params: IncreaseLiquidityDirectParams,\n): Promise<IncreaseLiquidityDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `increaseLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(\n `increaseLiquidityDirect: no V3 factory for chainId ${params.chainId}`,\n );\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"increaseLiquidityDirect: tokenId must be positive\");\n }\n const has0 = params.amount0Desired !== undefined && params.amount0Desired > 0n;\n const has1 = params.amount1Desired !== undefined && params.amount1Desired > 0n;\n if (has0 === has1) {\n throw new Error(\n \"increaseLiquidityDirect: exactly one of amount0Desired / amount1Desired must be a positive bigint\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `increaseLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"increaseLiquidityDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `increaseLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n const delegate = parseEip7702DelegatedAddress(code);\n if (!delegate) {\n throw new Error(\n `increaseLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n // Read position + pool state in series — position first because we\n // need its tokens to compute the pool address.\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n const sqrtL = tickToSqrtPriceX96(position.tickLower);\n const sqrtU = tickToSqrtPriceX96(position.tickUpper);\n const { liquidity, amount0, amount1 } = estimateLiquidityFromOneSide({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: sqrtL,\n sqrtPriceX96Upper: sqrtU,\n amount0Desired: params.amount0Desired,\n amount1Desired: params.amount1Desired,\n });\n const { amount0Min, amount1Min } = applyMintSlippage({\n amount0Desired: amount0,\n amount1Desired: amount1,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = buildIncreaseLiquidity({\n npm,\n token0: position.token0,\n token1: position.token1,\n tokenId: params.tokenId,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `increaseLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n amount0Desired: amount0,\n amount1Desired: amount1,\n amount0Min,\n amount1Min,\n liquidityAdded: liquidity,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildDecreaseLiquidity,\n buildCollect,\n readPosition,\n readPoolState,\n getAmountsForLiquidity,\n applyRemoveSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface RemoveLiquidityDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n\n /** How much L to withdraw. Pass `liquidity` OR `liquidityBps`. Exactly one. */\n liquidity?: bigint;\n /** 0..10000 — percentage of current liquidity to remove. */\n liquidityBps?: number;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface RemoveLiquidityDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n liquidityRemoved: bigint;\n amount0Expected: bigint;\n amount1Expected: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Partial withdraw from an existing V3 LP position.\n *\n * Batch shape:\n * 1. NPM.decreaseLiquidity({ tokenId, liquidity, amount0Min, amount1Min, deadline })\n * 2. NPM.collect({ tokenId, recipient: userAddress, amount0Max: MAX, amount1Max: MAX })\n *\n * No approvals — NPM doesn't pull tokens on remove. The collect leg is\n * mandatory because decrease only credits `tokensOwed*`; tokens stay in\n * the NPM until the user collects them.\n */\nexport async function removeLiquidityDirect(\n params: RemoveLiquidityDirectParams,\n): Promise<RemoveLiquidityDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `removeLiquidityDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`removeLiquidityDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"removeLiquidityDirect: tokenId must be positive\");\n }\n const hasL = params.liquidity !== undefined && params.liquidity > 0n;\n const hasBps =\n params.liquidityBps !== undefined &&\n params.liquidityBps > 0 &&\n params.liquidityBps <= 10000;\n if (hasL === hasBps) {\n throw new Error(\n \"removeLiquidityDirect: exactly one of liquidity (>0) or liquidityBps (1..10000) must be set\",\n );\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `removeLiquidityDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"removeLiquidityDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `removeLiquidityDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `removeLiquidityDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n if (position.liquidity === 0n) {\n throw new Error(\n `removeLiquidityDirect: position ${params.tokenId} has zero liquidity — nothing to remove`,\n );\n }\n\n const liquidityToRemove = hasL\n ? params.liquidity!\n : (position.liquidity * BigInt(params.liquidityBps!)) / 10000n;\n if (liquidityToRemove === 0n) {\n throw new Error(\n \"removeLiquidityDirect: computed liquidity to remove is zero (bps too small for position size)\",\n );\n }\n if (liquidityToRemove > position.liquidity) {\n throw new Error(\n `removeLiquidityDirect: liquidity to remove (${liquidityToRemove}) exceeds position liquidity (${position.liquidity})`,\n );\n }\n\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n\n const { amount0: amount0Expected, amount1: amount1Expected } =\n getAmountsForLiquidity({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: tickToSqrtPriceX96(position.tickLower),\n sqrtPriceX96Upper: tickToSqrtPriceX96(position.tickUpper),\n liquidity: liquidityToRemove,\n });\n const { amount0Min, amount1Min } = applyRemoveSlippage({\n amount0Expected,\n amount1Expected,\n slippageBps,\n });\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = [\n buildDecreaseLiquidity({\n npm,\n tokenId: params.tokenId,\n liquidity: liquidityToRemove,\n amount0Min,\n amount1Min,\n deadline,\n }),\n buildCollect({\n npm,\n tokenId: params.tokenId,\n recipient: params.userAddress,\n }),\n ];\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `removeLiquidityDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n liquidityRemoved: liquidityToRemove,\n amount0Expected,\n amount1Expected,\n amount0Min,\n amount1Min,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildClosePosition,\n readPosition,\n readPoolState,\n getAmountsForLiquidity,\n applyRemoveSlippage,\n tickToSqrtPriceX96,\n} from \"../liquidity\";\n\nexport interface ClosePositionDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n\n slippageBps?: number;\n deadline?: bigint;\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface ClosePositionDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n liquidityRemoved: bigint;\n amount0Expected: bigint;\n amount1Expected: bigint;\n amount0Min: bigint;\n amount1Min: bigint;\n deadline: bigint;\n}\n\n/**\n * Full close: decrease all liquidity (if any) + collect fees + burn the\n * position NFT. The SDK picks the batch shape from current position state:\n *\n * - liquidity > 0: decrease(all) → collect → burn (3 ops)\n * - liquidity == 0 + fees > 0: collect → burn (2 ops)\n * - liquidity == 0 + no fees: burn (1 op)\n *\n * Useful for cleaning up an LP NFT off the user's EOA after they're done.\n */\nexport async function closePositionDirect(\n params: ClosePositionDirectParams,\n): Promise<ClosePositionDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `closePositionDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`closePositionDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"closePositionDirect: tokenId must be positive\");\n }\n const slippageBps = params.slippageBps ?? 50;\n if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > 10000) {\n throw new Error(\n `closePositionDirect: slippageBps (${slippageBps}) must be an integer in [0, 10000]`,\n );\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"closePositionDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `closePositionDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `closePositionDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n\n // Estimate expected amounts only if we still have liquidity to decrease.\n let amount0Expected = 0n;\n let amount1Expected = 0n;\n let amount0Min = 0n;\n let amount1Min = 0n;\n if (position.liquidity > 0n) {\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const poolState = await readPoolState(params.publicClient, pool);\n const amounts = getAmountsForLiquidity({\n sqrtPriceX96Current: poolState.sqrtPriceX96,\n sqrtPriceX96Lower: tickToSqrtPriceX96(position.tickLower),\n sqrtPriceX96Upper: tickToSqrtPriceX96(position.tickUpper),\n liquidity: position.liquidity,\n });\n amount0Expected = amounts.amount0;\n amount1Expected = amounts.amount1;\n const min = applyRemoveSlippage({\n amount0Expected,\n amount1Expected,\n slippageBps,\n });\n amount0Min = min.amount0Min;\n amount1Min = min.amount1Min;\n }\n\n const deadline =\n params.deadline ?? BigInt(Math.floor(Date.now() / 1000) + 5 * 60);\n\n const operations = buildClosePosition({\n npm,\n tokenId: params.tokenId,\n liquidity: position.liquidity,\n hasOutstandingFees: position.tokensOwed0 + position.tokensOwed1 > 0n,\n recipient: params.userAddress,\n amount0Min,\n amount1Min,\n deadline,\n });\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `closePositionDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n liquidityRemoved: position.liquidity,\n amount0Expected,\n amount1Expected,\n amount0Min,\n amount1Min,\n deadline,\n };\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n TransactionReceipt,\n WalletClient,\n} from \"viem\";\nimport {\n parseEip7702DelegatedAddress,\n buildPartialUserOperation,\n computeV3PoolAddress,\n V3_FACTORY_ADDRESSES,\n V3_POOL_INIT_CODE_HASH,\n} from \"@pafi-dev/core\";\n\nimport {\n V3_NPM_ADDRESSES,\n buildCollect,\n readPosition,\n readPoolState,\n readTicksAt,\n readFeeGrowthGlobals,\n} from \"../liquidity\";\n\nexport interface CollectFeesDirectParams {\n userAddress: Address;\n chainId: number;\n publicClient: PublicClient;\n walletClient: WalletClient;\n\n tokenId: bigint;\n /** Recipient of the collected fees. Default `userAddress`. */\n recipient?: Address;\n\n waitForReceipt?: boolean;\n onWarning?: (msg: string) => void;\n}\n\nexport interface CollectFeesDirectResult {\n txHash: Hex;\n receipt?: TransactionReceipt;\n /** Pre-tx estimate (tokensOwed + pending). Actual transferred amount in the receipt's Collect log. */\n amount0Expected: bigint;\n amount1Expected: bigint;\n recipient: Address;\n}\n\n/**\n * Collect accrued fees from a position without changing its liquidity.\n *\n * Single-op batch (`NPM.collect`). NPM internally calls\n * `pool.burn(tickLower, tickUpper, 0)` when the position has active\n * liquidity, which flushes newly-accrued swap fees from the pool into\n * the position's `tokensOwed*` before transferring them out.\n *\n * The estimate combines `position.tokensOwed*` (already in NPM) with the\n * \"pending\" fees still in the pool (derived off-chain from feeGrowth\n * deltas). The actual transferred amount comes from the on-chain\n * `Collect` event in the receipt and may differ slightly if another\n * tx accrued more fees between the read and mine.\n */\nexport async function collectFeesDirect(\n params: CollectFeesDirectParams,\n): Promise<CollectFeesDirectResult> {\n const npm = V3_NPM_ADDRESSES[params.chainId];\n if (!npm) {\n throw new Error(\n `collectFeesDirect: no NonfungiblePositionManager for chainId ${params.chainId}`,\n );\n }\n const factory = V3_FACTORY_ADDRESSES[params.chainId];\n if (!factory) {\n throw new Error(`collectFeesDirect: no V3 factory for chainId ${params.chainId}`);\n }\n if (params.tokenId <= 0n) {\n throw new Error(\"collectFeesDirect: tokenId must be positive\");\n }\n\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\"collectFeesDirect: walletClient has no account attached\");\n }\n if (account.address.toLowerCase() !== params.userAddress.toLowerCase()) {\n throw new Error(\n `collectFeesDirect: walletClient.account.address (${account.address}) must equal userAddress (${params.userAddress})`,\n );\n }\n\n const code = await params.publicClient.getCode({ address: params.userAddress });\n if (!parseEip7702DelegatedAddress(code)) {\n throw new Error(\n `collectFeesDirect: user ${params.userAddress} is not EIP-7702 delegated.`,\n );\n }\n\n const position = await readPosition(params.publicClient, npm, params.tokenId);\n\n // Compute pending-fee estimate. If the position has no liquidity, all\n // claimable amounts are already pinned in `tokensOwed*` and we can\n // skip the pool reads entirely.\n let amount0Expected = position.tokensOwed0;\n let amount1Expected = position.tokensOwed1;\n if (position.liquidity > 0n) {\n const pool = computeV3PoolAddress({\n factory,\n tokenA: position.token0,\n tokenB: position.token1,\n fee: position.fee,\n initCodeHash: V3_POOL_INIT_CODE_HASH,\n });\n const [poolState, ticks, globals] = await Promise.all([\n readPoolState(params.publicClient, pool),\n readTicksAt(params.publicClient, pool, position.tickLower, position.tickUpper),\n readFeeGrowthGlobals(params.publicClient, pool),\n ]);\n\n const feeGrowthInside0 = computeFeeGrowthInside({\n currentTick: poolState.tick,\n tickLower: position.tickLower,\n tickUpper: position.tickUpper,\n feeGrowthGlobalX128: globals.feeGrowthGlobal0X128,\n feeGrowthOutsideLowerX128: ticks.lower.feeGrowthOutside0X128,\n feeGrowthOutsideUpperX128: ticks.upper.feeGrowthOutside0X128,\n });\n const feeGrowthInside1 = computeFeeGrowthInside({\n currentTick: poolState.tick,\n tickLower: position.tickLower,\n tickUpper: position.tickUpper,\n feeGrowthGlobalX128: globals.feeGrowthGlobal1X128,\n feeGrowthOutsideLowerX128: ticks.lower.feeGrowthOutside1X128,\n feeGrowthOutsideUpperX128: ticks.upper.feeGrowthOutside1X128,\n });\n\n const pending0 = wrappingDelta(\n feeGrowthInside0,\n position.feeGrowthInside0LastX128,\n ) * position.liquidity / (1n << 128n);\n const pending1 = wrappingDelta(\n feeGrowthInside1,\n position.feeGrowthInside1LastX128,\n ) * position.liquidity / (1n << 128n);\n\n amount0Expected += pending0;\n amount1Expected += pending1;\n }\n\n const recipient = params.recipient ?? params.userAddress;\n const operations = [buildCollect({ npm, tokenId: params.tokenId, recipient })];\n\n const partial = buildPartialUserOperation({\n sender: params.userAddress,\n nonce: 0n,\n operations,\n });\n\n const txHash = (await (\n params.walletClient as WalletClient & {\n sendTransaction: (args: unknown) => Promise<Hex>;\n }\n ).sendTransaction({\n account,\n chain: params.walletClient.chain,\n to: params.userAddress,\n value: 0n,\n data: partial.callData,\n })) as Hex;\n\n let receipt: TransactionReceipt | undefined;\n if (params.waitForReceipt !== false) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({ hash: txHash });\n } catch (err) {\n params.onWarning?.(\n `collectFeesDirect: tx ${txHash} sent but receipt fetch failed: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return {\n txHash,\n receipt,\n amount0Expected,\n amount1Expected,\n recipient,\n };\n}\n\n/**\n * V3's canonical `feeGrowthInside` formula. Branches on whether the\n * current tick is below / inside / above the position's range.\n *\n * Bit-truncation to 256 is implicit in Solidity's `uint256`; we mirror\n * that with a `mod` to keep the math consistent with on-chain behavior\n * when the underflow happens.\n */\nfunction computeFeeGrowthInside(params: {\n currentTick: number;\n tickLower: number;\n tickUpper: number;\n feeGrowthGlobalX128: bigint;\n feeGrowthOutsideLowerX128: bigint;\n feeGrowthOutsideUpperX128: bigint;\n}): bigint {\n const {\n currentTick,\n tickLower,\n tickUpper,\n feeGrowthGlobalX128,\n feeGrowthOutsideLowerX128,\n feeGrowthOutsideUpperX128,\n } = params;\n\n let feeGrowthBelow: bigint;\n if (currentTick >= tickLower) {\n feeGrowthBelow = feeGrowthOutsideLowerX128;\n } else {\n feeGrowthBelow = wrappingDelta(feeGrowthGlobalX128, feeGrowthOutsideLowerX128);\n }\n\n let feeGrowthAbove: bigint;\n if (currentTick < tickUpper) {\n feeGrowthAbove = feeGrowthOutsideUpperX128;\n } else {\n feeGrowthAbove = wrappingDelta(feeGrowthGlobalX128, feeGrowthOutsideUpperX128);\n }\n\n return wrappingDelta(\n wrappingDelta(feeGrowthGlobalX128, feeGrowthBelow),\n feeGrowthAbove,\n );\n}\n\n/**\n * uint256 subtraction with Solidity's wrapping semantics. Used because\n * V3's feeGrowth deltas can \"underflow\" — that's intentional in the\n * protocol and the result still reads as a meaningful unsigned value\n * after the wrap.\n */\nfunction wrappingDelta(a: bigint, b: bigint): bigint {\n const TWO_256 = 1n << 256n;\n return (a - b + TWO_256) % TWO_256;\n}\n"],"mappings":"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","names":["COMMON_POOLS","COMMON_POOLS","encodeV3Path","encodeV3PathReversed","encodeFunctionData","universalRouterAbi","encodeFunctionData","universalRouterAbi","userOp","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","UNIVERSAL_ROUTER_ADDRESSES","getContractAddresses","parseEip7702DelegatedAddress","detectDelegateImpl","SIMPLE_7702_IMPL_BASE_MAINNET","BATCH_EXECUTOR_7702_IMPL","UNIVERSAL_ROUTER_ADDRESSES","parseEip7702DelegatedAddress","detectDelegateImpl","SIMPLE_7702_IMPL_BASE_MAINNET","BATCH_EXECUTOR_7702_IMPL","getContractAddresses","BROKER_HASHES","ORDERLY_RELAY_ABI","ORDERLY_VAULT_ABI","ORDERLY_VAULT_ADDRESSES","TOKEN_HASHES","buildPerpDepositViaRelay","computeAccountId","detectDelegateImpl","getContractAddresses","parseEip7702DelegatedAddress","BATCH_EXECUTOR_7702_IMPL","SIMPLE_7702_IMPL_BASE_MAINNET","buildErc20TransferUserOp","getContractAddresses","parseEip7702DelegatedAddress","detectDelegateImpl","BATCH_EXECUTOR_7702_IMPL","SIMPLE_7702_IMPL_BASE_MAINNET","parseEip7702DelegatedAddress","buildPartialUserOperation","UINT128_MAX","liquidity","encodeFunctionData","erc20ApproveOp","erc20ApproveOp","encodeFunctionData","encodeFunctionData","erc20ApproveOp","erc20ApproveOp","encodeFunctionData","encodeFunctionData","encodeFunctionData","encodeFunctionData","encodeFunctionData","UINT128_MAX","encodeFunctionData","encodeFunctionData","LiquidityCurveErrorCode","parseEip7702DelegatedAddress","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation","parseEip7702DelegatedAddress","buildPartialUserOperation","computeV3PoolAddress","V3_FACTORY_ADDRESSES","V3_POOL_INIT_CODE_HASH","V3_FACTORY_ADDRESSES","parseEip7702DelegatedAddress","computeV3PoolAddress","V3_POOL_INIT_CODE_HASH","buildPartialUserOperation"]}