@pafi-dev/trading 0.4.0 → 0.4.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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/pools.ts","../src/direct/swapDirect.ts","../src/direct/perpDepositDirect.ts"],"sourcesContent":["export { TradingHandlers } from \"./api/handlers\";\nexport type { TradingHandlersConfig } from \"./api/handlers\";\n\nexport type {\n ApiQuoteRequest,\n ApiQuoteResponse,\n ApiQuoteError,\n ApiSwapRequest,\n ApiSwapResponse,\n ApiPerpDepositRequest,\n ApiPerpDepositResponse,\n} from \"./api/types\";\n\nexport { fetchPafiPools, PAFI_SUBGRAPH_URL } from \"./pools\";\n\n// v1.6 — Generalized swap UserOp builder + V4 quoting (moved from\n// @pafi-dev/core 2026-04-27). Exposed as building blocks for callers\n// that compose swap flows beyond what `TradingHandlers` provides.\nexport {\n buildSwapUserOp,\n type BuildSwapUserOpParams,\n buildUniversalRouterExecuteArgs,\n buildV4SwapInput,\n buildSwapFromQuote,\n buildPermit2ApprovalCalldata,\n buildErc20ApprovalCalldata,\n checkAllowance,\n simulateSwap,\n type SwapSimulationResult,\n} from \"./swap\";\n\nexport {\n findBestQuote,\n quoteBestRoute,\n quoteExactInput,\n quoteExactInputSingle,\n buildAllPaths,\n combineRoutes,\n} from \"./quoting\";\n\n// v0.4.0 — FE-direct flows (no AA, no bundler, no sponsor-relayer).\n// User EOA pays gas in ETH and broadcasts a single type-2 tx calling\n// its own EIP-7702 delegated bytecode. Requires the user to have run\n// `delegateDirect()` (from @pafi-dev/core) first.\nexport {\n swapDirect,\n perpDepositDirect,\n type SwapDirectParams,\n type SwapDirectResult,\n type PerpDepositDirectParams,\n type PerpDepositDirectResult,\n} from \"./direct\";\n","import { getAddress } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport {\n buildPerpDepositWithGasDeduction,\n buildPerpDepositViaRelay,\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} from \"@pafi-dev/core\";\nimport { findBestQuote } from \"../quoting\";\nimport { buildSwapUserOp } from \"../swap\";\nimport type {\n ApiQuoteRequest,\n ApiQuoteResponse,\n ApiSwapRequest,\n ApiSwapResponse,\n ApiPerpDepositRequest,\n ApiPerpDepositResponse,\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 V4 on-chain Quoter.\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 * v0.3.1 — `authenticatedAddress` first param. Caller (issuer\n * controller / FE proxy) MUST pass the address extracted from the\n * verified session/JWT. Handler asserts it equals\n * `request.userAddress`. See SDK_CORE_TRADING_AUDIT.md C6.\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\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.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 // 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 // v0.3.1 — auth-context check. See SDK_CORE_TRADING_AUDIT.md C6.\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/**\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","import type { Address } from \"viem\";\nimport type { PathKey, PoolKey } from \"@pafi-dev/core\";\nimport { COMMON_POOLS, POINT_TOKEN_POOLS } from \"@pafi-dev/core\";\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\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 swap paths from `tokenIn` to `tokenOut` using the given\n * pools. Returns an array of PathKey[] routes (each up to `maxHops` hops).\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): PathKey[][] {\n const results: PathKey[][] = [];\n\n function dfs(\n currentToken: Address,\n currentPath: PathKey[],\n usedPoolIndices: Set<number>,\n ) {\n if (currentPath.length > maxHops) return;\n\n // Check if we've reached the destination\n if (\n currentPath.length > 0 &&\n currentToken.toLowerCase() === tokenOut.toLowerCase()\n ) {\n results.push([...currentPath]);\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 c0 = pool.currency0.toLowerCase();\n const c1 = pool.currency1.toLowerCase();\n const curr = currentToken.toLowerCase();\n\n let nextToken: Address | null = null;\n if (curr === c0) {\n nextToken = pool.currency1 as Address;\n } else if (curr === c1) {\n nextToken = pool.currency0 as Address;\n }\n\n if (!nextToken) continue;\n\n const hop: PathKey = {\n intermediateCurrency: nextToken,\n fee: pool.fee,\n tickSpacing: pool.tickSpacing,\n hooks: pool.hooks ?? ZERO_ADDRESS,\n hookData: \"0x\",\n };\n\n usedPoolIndices.add(i);\n currentPath.push(hop);\n dfs(nextToken, currentPath, usedPoolIndices);\n currentPath.pop();\n usedPoolIndices.delete(i);\n }\n }\n\n dfs(tokenIn, [], new Set());\n return results;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type { BestQuote, PathKey, PoolKey, QuoteResult } from \"@pafi-dev/core\";\nimport { v4QuoterAbi } from \"@pafi-dev/core\";\nimport { buildAllPaths } from \"./routes\";\nimport { COMMON_POOLS, V4_QUOTER_ADDRESSES } from \"@pafi-dev/core\";\n\n/**\n * Quote exact-input for a multi-hop path.\n */\nexport async function quoteExactInput(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n path: PathKey[],\n exactAmount: bigint,\n): Promise<QuoteResult> {\n const [amountOut, gasEstimate] = await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInput\",\n args: [{ exactCurrency, path, exactAmount: BigInt(exactAmount) as unknown as number }],\n }) as [bigint, bigint];\n\n return { amountOut, gasEstimate, path };\n}\n\n/**\n * Quote exact-input for a single-hop swap, given an explicit PoolKey and direction.\n */\nexport async function quoteExactInputSingle(\n client: PublicClient,\n quoterAddress: Address,\n poolKey: PoolKey,\n zeroForOne: boolean,\n exactAmount: bigint,\n hookData: `0x${string}`,\n): Promise<{ amountOut: bigint; gasEstimate: bigint }> {\n const [amountOut, gasEstimate] = await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n poolKey,\n zeroForOne,\n exactAmount: BigInt(exactAmount) as unknown as number,\n hookData,\n },\n ],\n }) as [bigint, bigint];\n\n return { amountOut, gasEstimate };\n}\n\n/**\n * Try multiple PathKey[] routes and return the best quote plus all results.\n * Routes that fail (e.g. pool does not exist) are silently skipped.\n *\n * Uses viem multicall to batch all quotes into a single RPC call for speed.\n */\nexport async function quoteBestRoute(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n routes: PathKey[][],\n exactAmount: bigint,\n): Promise<BestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInput\" as const,\n args: [\n {\n exactCurrency,\n path,\n // `as unknown as number` cast — the V4 quoter's solidity\n // signature takes `uint256` (a bigint at the wire level), but\n // our pinned ABI types it as `number`. The runtime is fine\n // (bigint serializes correctly) — this cast tells TS to skip\n // the structural check until we re-generate the ABI with the\n // correct uint256 type. Tracked: SDK_CORE_TRADING_AUDIT.md H11.\n exactAmount: BigInt(exactAmount) as unknown as number,\n },\n ],\n })),\n allowFailure: true,\n });\n\n const allRoutes: QuoteResult[] = [];\n // v0.7.4 — collect first-failure reason so the thrown error carries\n // root cause when EVERY route fails. Previous behaviour swallowed\n // each route's revert via `allowFailure: true` then threw a generic\n // \"No valid routes found\", losing the cause (RPC down, pool removed,\n // hook revert, etc.). See SDK_CORE_TRADING_AUDIT.md H4.\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 [amountOut, gasEstimate] = r.result as unknown as [bigint, bigint];\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 from ${exactCurrency} (${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 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 V4_QUOTER_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 V4 Quoter 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 ?? V4_QUOTER_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V4 Quoter 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, tokenIn, 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 type { PathKey, QuoteResult } from \"@pafi-dev/core\";\n\n// -------------------------------------------------------------------------\n// V4 UniversalRouter command / action constants\n// Reference: https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/Actions.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V4 swap */\nexport const V4_SWAP = 0x10 as const;\n\n/** V4 actions */\nexport const SWAP_EXACT_IN_SINGLE = 0x06 as const;\nexport const SWAP_EXACT_IN = 0x07 as const;\nexport const SETTLE_ALL = 0x0c as const;\nexport const TAKE_ALL = 0x0f as const;\n\n// -------------------------------------------------------------------------\n// ABI type strings matching Uniswap's V4Planner encoding\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\n//\n// IMPORTANT: PathKey.fee is uint256 in the V4 Router ABI (not uint24).\n// -------------------------------------------------------------------------\n\n// PathKey components for V4 Router ABI encoding.\n// IMPORTANT: fee is uint256 in the V4 Router (not uint24 as in PoolKey).\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\nconst PATH_KEY_ABI_COMPONENTS = [\n { name: \"intermediateCurrency\", type: \"address\" },\n { name: \"fee\", type: \"uint256\" },\n { name: \"tickSpacing\", type: \"int24\" },\n { name: \"hooks\", type: \"address\" },\n { name: \"hookData\", type: \"bytes\" },\n] as const;\n\nconst EXACT_INPUT_PARAMS_ABI = [\n { name: \"currencyIn\", type: \"address\" },\n {\n name: \"path\",\n type: \"tuple[]\",\n components: PATH_KEY_ABI_COMPONENTS,\n },\n { name: \"amountIn\", type: \"uint128\" },\n { name: \"amountOutMinimum\", type: \"uint128\" },\n] as const;\n\n/**\n * Build the calldata inputs[0] (the V4_SWAP command payload) for\n * UniversalRouter.execute.\n *\n * Actions encoded: SWAP_EXACT_IN → SETTLE_ALL → TAKE_ALL\n *\n * Encoding matches the Uniswap V4 SDK's V4Planner — each action's params\n * are individually ABI-encoded, then wrapped together with the action bytes.\n */\nexport function buildV4SwapInput(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): Hex {\n const actions = encodePacked(\n [\"uint8\", \"uint8\", \"uint8\"],\n [SWAP_EXACT_IN, SETTLE_ALL, TAKE_ALL],\n );\n\n // Param 0: ExactInputParams — encoded as a single tuple so the CalldataDecoder\n // can locate it via a single offset pointer. fee is uint256 per V4 Router spec.\n const swapParam = encodeAbiParameters(\n [{ name: \"swap\", type: \"tuple\", components: EXACT_INPUT_PARAMS_ABI }],\n [\n {\n currencyIn,\n path: path.map((p) => ({\n intermediateCurrency: p.intermediateCurrency,\n fee: BigInt(p.fee),\n tickSpacing: p.tickSpacing,\n hooks: p.hooks,\n hookData: p.hookData,\n })),\n amountIn,\n amountOutMinimum: minAmountOut,\n },\n ],\n );\n\n // Param 1: SETTLE_ALL { currency, maxAmount }\n const settleParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint256\" },\n ],\n [currencyIn, amountIn],\n );\n\n // Param 2: TAKE_ALL { currency, minAmount }\n const takeParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"minAmount\", type: \"uint256\" },\n ],\n [outputCurrency, minAmountOut],\n );\n\n return encodeAbiParameters(\n [\n { name: \"actions\", type: \"bytes\" },\n { name: \"params\", type: \"bytes[]\" },\n ],\n [actions, [swapParam, settleParam, takeParam]],\n );\n}\n\n/**\n * Build the full commands + inputs args for UniversalRouter.execute.\n */\nexport function buildUniversalRouterExecuteArgs(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V4_SWAP]);\n const inputs: Hex[] = [\n buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build UniversalRouter execute args from a quote result.\n *\n * Takes the output of `findBestQuote` / `quoteBestRoute` and produces\n * ready-to-use `{ commands, inputs }` for `UniversalRouter.execute`.\n *\n * @param quote - Quote result containing the path\n * @param currencyIn - Input token address\n * @param currencyOut - Output token address\n * @param amountIn - Exact input amount (same value passed to the quoter)\n * @param minAmountOut - Minimum acceptable output (caller applies slippage)\n *\n * @deprecated Since v1.4 — the Issuer App no longer handles swaps.\n * For the new PT→USDT batch call on PAFI Web (Scenario 4 with\n * EIP-7702 gas deduction), use `buildSwapWithGasDeduction()` (v1.5).\n * This helper is kept for legacy v0.2.x consumers; will be removed in v2.0.\n */\nexport function buildSwapFromQuote(params: {\n quote: QuoteResult;\n currencyIn: Address;\n currencyOut: Address;\n amountIn: bigint;\n minAmountOut: bigint;\n}): { commands: Hex; inputs: Hex[] } {\n return buildUniversalRouterExecuteArgs(\n params.currencyIn,\n params.quote.path,\n params.amountIn,\n params.minAmountOut,\n params.currencyOut,\n );\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 PathKey,\n} from \"@pafi-dev/core\";\nimport { buildUniversalRouterExecuteArgs } from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\n\n/**\n * v0.3 — Generalized swap UserOp builder. Direction-agnostic: works\n * for **any** ERC-20 → ERC-20 pair routable through PAFI's V4 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)` — V4 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 * ## PAFI Hook fee\n *\n * The V4 PAFIHook charges 10% on PT → USDT direction (one-way). The\n * 10% is taken at pool level inside `UniversalRouter.execute`, so this\n * builder doesn't model it explicitly — it shows up as a smaller\n * `amountOut` from `findBestQuote`.\n *\n * - PT → USDT: pool charges 10% (output reduced)\n * - USDT → PT: no hook fee\n * - PT0 → PT1: 10% on PT0 → USDT leg, 0% on USDT → PT1 leg\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 * V4 pool path for the swap. Single-hop = 1 PathKey, multi-hop = N.\n * Get this from `findBestQuote().bestRoute.path`.\n */\n swapPath: PathKey[];\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.length === 0) {\n throw new Error(\n \"buildSwapUserOp: swapPath must contain at least one PathKey\",\n );\n }\n // v0.7.1 — assert deadline fits Permit2's uint48 expiration field\n // (max 2^48 - 1 ≈ year 8,921,478 in unix seconds). Catches the\n // common bug where a caller passes deadline in milliseconds; also\n // guards against any future caller passing > 2^53 (Number cast lossy).\n // See SDK_CORE_TRADING_AUDIT.md H10.\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.inputTokenAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n params.outputTokenAddress,\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","// 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 { buildSwapUserOp } 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 * (Simple7702Account or Coinbase SW v2 BatchExecutor). Throw with\n * a clear hint pointing at `delegateDirect()` if not delegated.\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. 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 // 2. Quote — uses the same primitives as `TradingHandlers.handleQuote`.\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\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.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 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 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 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"],"mappings":"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","names":["import_viem","import_core","import_core","import_core","import_core","import_viem","import_core","import_viem","import_core","userOp","import_core","import_core","import_core"]}
1
+ {"version":3,"sources":["../src/index.ts","../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"],"sourcesContent":["export { TradingHandlers } from \"./api/handlers\";\nexport type { TradingHandlersConfig } from \"./api/handlers\";\n\nexport type {\n ApiQuoteRequest,\n ApiQuoteResponse,\n ApiQuoteError,\n ApiSwapRequest,\n ApiSwapResponse,\n ApiQuoteExactOutRequest,\n ApiQuoteExactOutResponse,\n ApiSwapExactOutRequest,\n ApiSwapExactOutResponse,\n ApiPerpDepositRequest,\n ApiPerpDepositResponse,\n} from \"./api/types\";\n\nexport { fetchPafiPools, PAFI_SUBGRAPH_URL } from \"./pools\";\n\n// v1.6 — Generalized swap UserOp builder + V4 quoting (moved from\n// @pafi-dev/core 2026-04-27). Exposed as building blocks for callers\n// that compose swap flows beyond what `TradingHandlers` provides.\nexport {\n buildSwapUserOp,\n type BuildSwapUserOpParams,\n buildUniversalRouterExecuteArgs,\n buildV4SwapInput,\n buildSwapFromQuote,\n buildPermit2ApprovalCalldata,\n buildErc20ApprovalCalldata,\n checkAllowance,\n simulateSwap,\n type SwapSimulationResult,\n} from \"./swap\";\n\nexport {\n findBestQuote,\n quoteBestRoute,\n quoteExactInput,\n quoteExactInputSingle,\n buildAllPaths,\n combineRoutes,\n} from \"./quoting\";\n\n// v0.5 — V4 exact-output support. Purely additive sibling to the\n// exact-input surface above; existing exact-in callers are unchanged.\n// Operator fee is INPUT-token-side (charged before swap) so the user\n// receives a precise output amount.\nexport {\n findBestQuoteExactOut,\n quoteBestRouteExactOut,\n quoteExactOutput,\n quoteExactOutputSingle,\n} from \"./quoting\";\nexport {\n buildSwapUserOpExactOut,\n type BuildSwapUserOpExactOutParams,\n buildUniversalRouterExecuteArgsExactOut,\n buildV4SwapInputExactOut,\n SWAP_EXACT_OUT,\n SWAP_EXACT_OUT_SINGLE,\n} from \"./swap\";\n\n// v0.4.0 — FE-direct flows (no AA, no bundler, no sponsor-relayer).\n// User EOA pays gas in ETH and broadcasts a single type-2 tx calling\n// its own EIP-7702 delegated bytecode. Requires the user to have run\n// `delegateDirect()` (from @pafi-dev/core) first.\nexport {\n swapDirect,\n swapDirectExactOut,\n perpDepositDirect,\n type SwapDirectParams,\n type SwapDirectResult,\n type SwapDirectExactOutParams,\n type SwapDirectExactOutResult,\n type PerpDepositDirectParams,\n type PerpDepositDirectResult,\n} from \"./direct\";\n","import { getAddress } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport {\n buildPerpDepositWithGasDeduction,\n buildPerpDepositViaRelay,\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} 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} 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 V4 on-chain Quoter.\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.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 — V4 exact-output quote\n // =========================================================================\n\n /**\n * Quote the input required to receive `request.amount` of the output\n * token via Uniswap V4. 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 — V4 exact-output swap UserOp\n // =========================================================================\n\n /**\n * Build a V4 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 (V4 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.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/**\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 { PathKey, PoolKey } from \"@pafi-dev/core\";\nimport { COMMON_POOLS, POINT_TOKEN_POOLS } from \"@pafi-dev/core\";\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\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 swap paths from `tokenIn` to `tokenOut` using the given\n * pools. Returns an array of PathKey[] routes (each up to `maxHops` hops).\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): PathKey[][] {\n const results: PathKey[][] = [];\n\n function dfs(\n currentToken: Address,\n currentPath: PathKey[],\n usedPoolIndices: Set<number>,\n ) {\n if (currentPath.length > maxHops) return;\n\n // Check if we've reached the destination\n if (\n currentPath.length > 0 &&\n currentToken.toLowerCase() === tokenOut.toLowerCase()\n ) {\n results.push([...currentPath]);\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 c0 = pool.currency0.toLowerCase();\n const c1 = pool.currency1.toLowerCase();\n const curr = currentToken.toLowerCase();\n\n let nextToken: Address | null = null;\n if (curr === c0) {\n nextToken = pool.currency1 as Address;\n } else if (curr === c1) {\n nextToken = pool.currency0 as Address;\n }\n\n if (!nextToken) continue;\n\n const hop: PathKey = {\n intermediateCurrency: nextToken,\n fee: pool.fee,\n tickSpacing: pool.tickSpacing,\n hooks: pool.hooks ?? ZERO_ADDRESS,\n hookData: \"0x\",\n };\n\n usedPoolIndices.add(i);\n currentPath.push(hop);\n dfs(nextToken, currentPath, usedPoolIndices);\n currentPath.pop();\n usedPoolIndices.delete(i);\n }\n }\n\n dfs(tokenIn, [], new Set());\n return results;\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type {\n BestQuote,\n ExactOutputBestQuote,\n ExactOutputQuoteResult,\n PathKey,\n PoolKey,\n QuoteResult,\n} from \"@pafi-dev/core\";\nimport { v4QuoterAbi } from \"@pafi-dev/core\";\nimport { buildAllPaths } from \"./routes\";\nimport { COMMON_POOLS, V4_QUOTER_ADDRESSES } from \"@pafi-dev/core\";\n\n/**\n * Quote exact-input for a multi-hop path.\n */\nexport async function quoteExactInput(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n path: PathKey[],\n exactAmount: bigint,\n): Promise<QuoteResult> {\n const [amountOut, gasEstimate] = (await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInput\",\n args: [{ exactCurrency, path, exactAmount }],\n })) as [bigint, bigint];\n\n return { amountOut, gasEstimate, path };\n}\n\n/**\n * Quote exact-input for a single-hop swap, given an explicit PoolKey and direction.\n */\nexport async function quoteExactInputSingle(\n client: PublicClient,\n quoterAddress: Address,\n poolKey: PoolKey,\n zeroForOne: boolean,\n exactAmount: bigint,\n hookData: `0x${string}`,\n): Promise<{ amountOut: bigint; gasEstimate: bigint }> {\n const [amountOut, gasEstimate] = (await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n poolKey,\n zeroForOne,\n exactAmount,\n hookData,\n },\n ],\n })) as [bigint, bigint];\n\n return { amountOut, gasEstimate };\n}\n\n/**\n * Try multiple PathKey[] routes and return the best quote plus all results.\n * Routes that fail (e.g. pool does not exist) are silently skipped.\n *\n * Uses viem multicall to batch all quotes into a single RPC call for speed.\n */\nexport async function quoteBestRoute(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n routes: PathKey[][],\n exactAmount: bigint,\n): Promise<BestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactInput\" as const,\n args: [\n {\n exactCurrency,\n path,\n exactAmount,\n },\n ],\n })),\n allowFailure: true,\n });\n\n const allRoutes: QuoteResult[] = [];\n // Collect first-failure reason so the thrown error carries root\n // cause when EVERY route fails. Without this, `allowFailure: true`\n // swallows each route's revert and we'd throw a generic \"No valid\n // routes found\" — losing the cause (RPC down, pool removed, hook\n // revert, etc.).\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 [amountOut, gasEstimate] = r.result as unknown as [bigint, bigint];\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 from ${exactCurrency} (${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 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 V4_QUOTER_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 V4 Quoter 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 ?? V4_QUOTER_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V4 Quoter 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, tokenIn, paths, exactAmount);\n}\n\n// =========================================================================\n// V4 exact-output quoting\n// =========================================================================\n//\n// CAUTION: in `quoteExactOutput*`, `exactCurrency` is the OUTPUT token (the\n// one the user wants to receive a precise amount of), and `path` is\n// traversed output→input. This is the opposite of `quoteExactInput*`,\n// where `exactCurrency` is the INPUT token. The field names are\n// dangerously symmetric — read carefully when wiring callers.\n// =========================================================================\n\n/**\n * Quote V4 exact-output for a multi-hop path.\n *\n * @param exactCurrency - The OUTPUT token (the one the user wants to\n * receive a precise amount of).\n * @param path - PathKey[] in output→input orientation. Use\n * `buildAllPaths(pools, tokenOut, tokenIn, ...)`\n * (arguments swapped vs. exact-in) to produce\n * the right shape.\n * @param exactAmount - Exact OUTPUT amount the user wants.\n * @returns `{ amountIn, gasEstimate, path }` — the input amount required\n * to receive `exactAmount` of `exactCurrency`.\n */\nexport async function quoteExactOutput(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n path: PathKey[],\n exactAmount: bigint,\n): Promise<ExactOutputQuoteResult> {\n const [amountIn, gasEstimate] = (await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactOutput\",\n args: [{ exactCurrency, path, exactAmount }],\n })) as [bigint, bigint];\n\n return { amountIn, gasEstimate, path };\n}\n\n/**\n * Quote V4 exact-output for a single-hop swap, given an explicit PoolKey\n * and direction.\n *\n * `zeroForOne` semantics are identical to the exact-input variant —\n * \"trade direction\" is invariant to the exactness parameter. Only\n * `exactAmount` flips meaning (here: amount of *output* currency the\n * user wants to receive).\n */\nexport async function quoteExactOutputSingle(\n client: PublicClient,\n quoterAddress: Address,\n poolKey: PoolKey,\n zeroForOne: boolean,\n exactAmount: bigint,\n hookData: `0x${string}`,\n): Promise<{ amountIn: bigint; gasEstimate: bigint }> {\n const [amountIn, gasEstimate] = (await client.readContract({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactOutputSingle\",\n args: [\n {\n poolKey,\n zeroForOne,\n exactAmount,\n hookData,\n },\n ],\n })) as [bigint, bigint];\n\n return { amountIn, gasEstimate };\n}\n\n/**\n * Try multiple PathKey[] routes for an exact-output swap and return the\n * route requiring the **smallest** input amount, plus all results.\n * Routes that fail (e.g. pool does not exist) are silently skipped.\n *\n * Uses viem multicall to batch all quotes into a single RPC call.\n */\nexport async function quoteBestRouteExactOut(\n client: PublicClient,\n quoterAddress: Address,\n exactCurrency: Address,\n routes: PathKey[][],\n exactAmount: bigint,\n): Promise<ExactOutputBestQuote> {\n const results = await client.multicall({\n contracts: routes.map((path) => ({\n address: quoterAddress,\n abi: v4QuoterAbi,\n functionName: \"quoteExactOutput\" as const,\n args: [\n {\n exactCurrency,\n path,\n exactAmount,\n },\n ],\n })),\n allowFailure: true,\n });\n\n const allRoutes: ExactOutputQuoteResult[] = [];\n // Collect first-failure reason — same diagnostic pattern as\n // `quoteBestRoute` (exact-in variant). Wording flipped: \"to\" not \"from\".\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 [amountIn, gasEstimate] = r.result as unknown as [bigint, bigint];\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 to ${exactCurrency} (${routes.length} candidates probed)` +\n (firstFailure ? `; first failure: ${firstFailure}` : \"\"),\n );\n }\n\n // Best exact-output route = smallest required input.\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 V4 exact-output route from `tokenIn` to\n * `tokenOut` for a desired output amount.\n *\n * Symmetric to `findBestQuote` but with two key differences:\n *\n * - `exactAmount` is denominated in `tokenOut` (the OUTPUT token).\n * - Internally calls `buildAllPaths(allPools, tokenOut, tokenIn, ...)`\n * (arguments swapped) to enumerate paths in output→input\n * orientation, which is what `quoteExactOutput` expects.\n *\n * @param client - viem PublicClient.\n * @param chainId - Chain ID (looks up COMMON_POOLS + V4_QUOTER_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 V4 Quoter 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 ?? V4_QUOTER_ADDRESSES[chainId];\n if (!quoter) {\n throw new Error(`No V4 Quoter address configured for chain ${chainId}`);\n }\n\n const commonPools = COMMON_POOLS[chainId] ?? [];\n const allPools = [...pools, ...commonPools];\n\n // For exact-output we walk pools output→input. `buildAllPaths` is\n // direction-agnostic (treats pools as undirected edges), so swapping\n // the from/to arguments yields paths whose `path[i].intermediateCurrency`\n // is the previous currency in the route — exactly what\n // `quoteExactOutput` expects.\n const paths = buildAllPaths(allPools, tokenOut, tokenIn, maxHops);\n\n if (paths.length === 0) {\n throw new Error(\n `No exact-output paths found to ${tokenOut} from ${tokenIn}`,\n );\n }\n\n return quoteBestRouteExactOut(client, quoter, tokenOut, 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 type { PathKey, QuoteResult } from \"@pafi-dev/core\";\n\n// -------------------------------------------------------------------------\n// V4 UniversalRouter command / action constants\n// Reference: https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/Actions.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V4 swap */\nexport const V4_SWAP = 0x10 as const;\n\n/** V4 actions */\nexport const SWAP_EXACT_IN_SINGLE = 0x06 as const;\nexport const SWAP_EXACT_IN = 0x07 as const;\nexport const SWAP_EXACT_OUT_SINGLE = 0x08 as const;\nexport const SWAP_EXACT_OUT = 0x09 as const;\nexport const SETTLE_ALL = 0x0c as const;\nexport const TAKE_ALL = 0x0f 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// ABI type strings matching Uniswap's V4Planner encoding\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\n//\n// IMPORTANT: PathKey.fee is uint256 in the V4 Router ABI (not uint24).\n// -------------------------------------------------------------------------\n\n// PathKey components for V4 Router ABI encoding.\n// IMPORTANT: fee is uint256 in the V4 Router (not uint24 as in PoolKey).\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\nconst PATH_KEY_ABI_COMPONENTS = [\n { name: \"intermediateCurrency\", type: \"address\" },\n { name: \"fee\", type: \"uint256\" },\n { name: \"tickSpacing\", type: \"int24\" },\n { name: \"hooks\", type: \"address\" },\n { name: \"hookData\", type: \"bytes\" },\n] as const;\n\nconst EXACT_INPUT_PARAMS_ABI = [\n { name: \"currencyIn\", type: \"address\" },\n {\n name: \"path\",\n type: \"tuple[]\",\n components: PATH_KEY_ABI_COMPONENTS,\n },\n { name: \"amountIn\", type: \"uint128\" },\n { name: \"amountOutMinimum\", type: \"uint128\" },\n] as const;\n\n// V4 Router exact-output params layout. Tuple shape mirrors the\n// exact-input variant but with `currencyOut` (the token being received)\n// and `amountOut` / `amountInMaximum` swapped in. The `path` is\n// traversed output→input on chain, so each `path[i].intermediateCurrency`\n// is the previous currency in the route.\nconst EXACT_OUTPUT_PARAMS_ABI = [\n { name: \"currencyOut\", type: \"address\" },\n {\n name: \"path\",\n type: \"tuple[]\",\n components: PATH_KEY_ABI_COMPONENTS,\n },\n { name: \"amountOut\", type: \"uint128\" },\n { name: \"amountInMaximum\", type: \"uint128\" },\n] as const;\n\n/**\n * Build the calldata inputs[0] (the V4_SWAP command payload) for\n * UniversalRouter.execute.\n *\n * Actions encoded: SWAP_EXACT_IN → SETTLE_ALL → TAKE_ALL\n *\n * Encoding matches the Uniswap V4 SDK's V4Planner — each action's params\n * are individually ABI-encoded, then wrapped together with the action bytes.\n */\nexport function buildV4SwapInput(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): Hex {\n const actions = encodePacked(\n [\"uint8\", \"uint8\", \"uint8\"],\n [SWAP_EXACT_IN, SETTLE_ALL, TAKE_ALL],\n );\n\n // Param 0: ExactInputParams — encoded as a single tuple so the CalldataDecoder\n // can locate it via a single offset pointer. fee is uint256 per V4 Router spec.\n const swapParam = encodeAbiParameters(\n [{ name: \"swap\", type: \"tuple\", components: EXACT_INPUT_PARAMS_ABI }],\n [\n {\n currencyIn,\n path: path.map((p) => ({\n intermediateCurrency: p.intermediateCurrency,\n fee: BigInt(p.fee),\n tickSpacing: p.tickSpacing,\n hooks: p.hooks,\n hookData: p.hookData,\n })),\n amountIn,\n amountOutMinimum: minAmountOut,\n },\n ],\n );\n\n // Param 1: SETTLE_ALL { currency, maxAmount }\n const settleParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint256\" },\n ],\n [currencyIn, amountIn],\n );\n\n // Param 2: TAKE_ALL { currency, minAmount }\n const takeParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"minAmount\", type: \"uint256\" },\n ],\n [outputCurrency, minAmountOut],\n );\n\n return encodeAbiParameters(\n [\n { name: \"actions\", type: \"bytes\" },\n { name: \"params\", type: \"bytes[]\" },\n ],\n [actions, [swapParam, settleParam, takeParam]],\n );\n}\n\n/**\n * Build the full commands + inputs args for UniversalRouter.execute.\n */\nexport function buildUniversalRouterExecuteArgs(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V4_SWAP]);\n const inputs: Hex[] = [\n buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build the calldata inputs[0] (the V4_SWAP command payload) for\n * UniversalRouter.execute, using the V4 exact-output flow.\n *\n * Actions encoded: SWAP_EXACT_OUT → SETTLE_ALL → TAKE_ALL\n *\n * Settle/take semantics flip vs. the exact-input builder:\n * - SETTLE_ALL caps the input pulled at `maxAmountIn` (router pulls\n * only the actual amount the swap consumed; reverts if it exceeds\n * the cap).\n * - TAKE_ALL requires the user to receive *exactly* `amountOut` of\n * `outputCurrency`.\n *\n * The `path` argument here is in V4 exact-output orientation — i.e.\n * traversed output→input — which is what `findBestQuoteExactOut`\n * (and `buildAllPaths(pools, tokenOut, tokenIn, ...)`) returns.\n *\n * @throws if `amountOut` or `maxAmountIn` exceeds 2^128 - 1.\n */\nexport function buildV4SwapInputExactOut(\n currencyOut: Address,\n path: PathKey[],\n amountOut: bigint,\n maxAmountIn: bigint,\n inputCurrency: Address,\n): Hex {\n if (amountOut <= 0n || amountOut > UINT128_MAX) {\n throw new Error(\n `buildV4SwapInputExactOut: amountOut (${amountOut}) must be in (0, 2^128-1]`,\n );\n }\n if (maxAmountIn <= 0n || maxAmountIn > UINT128_MAX) {\n throw new Error(\n `buildV4SwapInputExactOut: maxAmountIn (${maxAmountIn}) must be in (0, 2^128-1]`,\n );\n }\n\n const actions = encodePacked(\n [\"uint8\", \"uint8\", \"uint8\"],\n [SWAP_EXACT_OUT, SETTLE_ALL, TAKE_ALL],\n );\n\n // Param 0: ExactOutputParams — encoded as a single tuple so the\n // CalldataDecoder can locate it via a single offset pointer. fee is\n // uint256 per V4 Router spec (mirrors the exact-input case).\n const swapParam = encodeAbiParameters(\n [{ name: \"swap\", type: \"tuple\", components: EXACT_OUTPUT_PARAMS_ABI }],\n [\n {\n currencyOut,\n path: path.map((p) => ({\n intermediateCurrency: p.intermediateCurrency,\n fee: BigInt(p.fee),\n tickSpacing: p.tickSpacing,\n hooks: p.hooks,\n hookData: p.hookData,\n })),\n amountOut,\n amountInMaximum: maxAmountIn,\n },\n ],\n );\n\n // Param 1: SETTLE_ALL { currency, maxAmount } — cap on input pulled.\n const settleParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint256\" },\n ],\n [inputCurrency, maxAmountIn],\n );\n\n // Param 2: TAKE_ALL { currency, minAmount } — exact-output guarantees\n // the user receives `amountOut`, so the floor IS amountOut.\n const takeParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"minAmount\", type: \"uint256\" },\n ],\n [currencyOut, amountOut],\n );\n\n return encodeAbiParameters(\n [\n { name: \"actions\", type: \"bytes\" },\n { name: \"params\", type: \"bytes[]\" },\n ],\n [actions, [swapParam, settleParam, takeParam]],\n );\n}\n\n/**\n * Build the full commands + inputs args for UniversalRouter.execute,\n * using the V4 exact-output flow.\n */\nexport function buildUniversalRouterExecuteArgsExactOut(\n currencyOut: Address,\n path: PathKey[],\n amountOut: bigint,\n maxAmountIn: bigint,\n inputCurrency: Address,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V4_SWAP]);\n const inputs: Hex[] = [\n buildV4SwapInputExactOut(\n currencyOut,\n path,\n amountOut,\n maxAmountIn,\n inputCurrency,\n ),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build UniversalRouter execute args from a quote result.\n *\n * Takes the output of `findBestQuote` / `quoteBestRoute` and produces\n * ready-to-use `{ commands, inputs }` for `UniversalRouter.execute`.\n *\n * @param quote - Quote result containing the path\n * @param currencyIn - Input token address\n * @param currencyOut - Output token address\n * @param amountIn - Exact input amount (same value passed to the quoter)\n * @param minAmountOut - Minimum acceptable output (caller applies slippage)\n *\n * @deprecated Since v1.4 — the Issuer App no longer handles swaps.\n * For the new PT→USDT batch call on PAFI Web (Scenario 4 with\n * EIP-7702 gas deduction), use `buildSwapWithGasDeduction()` (v1.5).\n * This helper is kept for legacy v0.2.x consumers; will be removed in v2.0.\n */\nlet _buildSwapFromQuoteWarned = false;\nexport function buildSwapFromQuote(params: {\n quote: QuoteResult;\n currencyIn: Address;\n currencyOut: Address;\n amountIn: bigint;\n minAmountOut: bigint;\n}): { commands: Hex; inputs: Hex[] } {\n if (!_buildSwapFromQuoteWarned) {\n _buildSwapFromQuoteWarned = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[PAFI] DEPRECATION (v1.4+): `buildSwapFromQuote` from @pafi-dev/trading \" +\n \"is deprecated and will be removed in v2.0. Use \" +\n \"`buildUniversalRouterExecuteArgs` directly with `quote.bestRoute.path`.\",\n );\n }\n return buildUniversalRouterExecuteArgs(\n params.currencyIn,\n params.quote.path,\n params.amountIn,\n params.minAmountOut,\n params.currencyOut,\n );\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 PathKey,\n} from \"@pafi-dev/core\";\nimport {\n buildUniversalRouterExecuteArgs,\n buildUniversalRouterExecuteArgsExactOut,\n} from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\n\n/**\n * v0.3 — Generalized swap UserOp builder. Direction-agnostic: works\n * for **any** ERC-20 → ERC-20 pair routable through PAFI's V4 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)` — V4 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 * ## PAFI Hook fee\n *\n * The V4 PAFIHook charges 10% on PT → USDT direction (one-way). The\n * 10% is taken at pool level inside `UniversalRouter.execute`, so this\n * builder doesn't model it explicitly — it shows up as a smaller\n * `amountOut` from `findBestQuote`.\n *\n * - PT → USDT: pool charges 10% (output reduced)\n * - USDT → PT: no hook fee\n * - PT0 → PT1: 10% on PT0 → USDT leg, 0% on USDT → PT1 leg\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 * V4 pool path for the swap. Single-hop = 1 PathKey, multi-hop = N.\n * Get this from `findBestQuote().bestRoute.path`.\n */\n swapPath: PathKey[];\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.length === 0) {\n throw new Error(\n \"buildSwapUserOp: swapPath must contain at least one PathKey\",\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.inputTokenAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n params.outputTokenAddress,\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// V4 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. V4's SETTLE_ALL settles the actual amount the swap\n// consumed and reverts if it exceeds 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 * V4 pool path in **output→input** orientation. Single-hop = 1 PathKey,\n * multi-hop = N. Get this from `findBestQuoteExactOut().bestRoute.path`.\n */\n swapPath: PathKey[];\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 V4 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)` — V4\n * exact-output swap; user receives exactly `amountOut`.\n *\n * @throws when `amountOut`/`maxAmountIn` are non-positive,\n * `gasFeeAmountInput` is negative, `swapPath` is empty, or `deadline`\n * 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.length === 0) {\n throw new Error(\n \"buildSwapUserOpExactOut: swapPath must contain at least one PathKey\",\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.outputTokenAddress,\n params.swapPath,\n params.amountOut,\n params.maxAmountIn,\n params.inputTokenAddress,\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 * (Simple7702Account or Coinbase SW v2 BatchExecutor). Throw with\n * a clear hint pointing at `delegateDirect()` if not delegated.\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.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 V4 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.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"],"mappings":"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","names":["import_viem","import_core","import_core","import_core","import_core","import_viem","import_core","import_viem","import_core","userOp","import_core","import_core","import_core","import_core"]}