@pafi-dev/core 0.9.6 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -189
- package/dist/{chunk-5NEAI2BH.cjs → chunk-4NTU7XGP.cjs} +2 -54
- package/dist/chunk-4NTU7XGP.cjs.map +1 -0
- package/dist/{chunk-BNO5SM25.cjs → chunk-BBQLGBOD.cjs} +2 -11
- package/dist/{chunk-Y5EYH2SQ.js.map → chunk-BBQLGBOD.cjs.map} +1 -1
- package/dist/{chunk-Y5EYH2SQ.js → chunk-J7EYOLMI.js} +1 -10
- package/dist/chunk-J7EYOLMI.js.map +1 -0
- package/dist/{chunk-HJYHGCMT.js → chunk-RVSW7I6U.js} +2 -54
- package/dist/chunk-RVSW7I6U.js.map +1 -0
- package/dist/contract/index.cjs +2 -4
- package/dist/contract/index.cjs.map +1 -1
- package/dist/contract/index.d.cts +2 -11
- package/dist/contract/index.d.ts +2 -11
- package/dist/contract/index.js +1 -3
- package/dist/eip712/index.cjs +2 -8
- package/dist/eip712/index.cjs.map +1 -1
- package/dist/eip712/index.d.cts +2 -41
- package/dist/eip712/index.d.ts +2 -41
- package/dist/eip712/index.js +3 -9
- package/dist/index.cjs +13 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -84
- package/dist/index.d.ts +36 -84
- package/dist/index.js +11 -47
- package/dist/index.js.map +1 -1
- package/dist/{types-DWLZNgcw.d.cts → types-B3UivyQ1.d.cts} +1 -10
- package/dist/{types-DWLZNgcw.d.ts → types-B3UivyQ1.d.ts} +1 -10
- package/package.json +10 -1
- package/dist/chunk-5NEAI2BH.cjs.map +0 -1
- package/dist/chunk-BNO5SM25.cjs.map +0 -1
- package/dist/chunk-HJYHGCMT.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/perp/buildPerpDepositWithGasDeduction.ts","../src/contracts/real/orderlyVault.ts","../src/userop/operations.ts","../src/userop/batchExecute.ts","../src/userop/buildUserOperation.ts","../src/perp/buildPerpDepositViaRelay.ts","../src/userop/types.ts","../src/userop/serializeUserOp.ts","../src/userop/computeUserOpHash.ts","../src/userop/eip7702Helpers.ts","../src/paymaster/config.ts","../src/utils/checkEthAndBranch.ts","../src/delegation/checkDelegation.ts","../src/delegation/buildDelegationUserOp.ts","../src/delegation/computeAuthorizationHash.ts","../src/delegation/eip7702Authorization.ts","../src/contracts/real/addresses.ts","../src/delegation/delegateDirect.ts","../src/transport/proxyTransport.ts","../src/transport/paymasterFallback.ts","../src/fee/operatorFeeQuoter.ts","../src/subgraph/pools.ts","../src/contracts/real/batchExecutor.ts","../src/contracts/real/pafi-services.ts","../src/web-handoff/webPopup.ts","../src/web-handoff/index.ts"],"sourcesContent":["import { createPublicClient, http } from \"viem\";\nimport type { Address, Hex, PublicClient, WalletClient } from \"viem\";\n\n// -------------------------------------------------------------------------\n// Re-export all sub-modules\n// -------------------------------------------------------------------------\nexport * from \"./types\";\nexport * from \"./constants\";\nexport * from \"./errors\";\nexport * from \"./abi/index\";\nexport * from \"./eip712/index\";\nexport * from \"./contract/index\";\n// quoting + swap moved to @pafi-dev/trading (2026-04-27). Core retains\n// underlying ABI primitives (universalRouterAbi, permit2Abi,\n// v4QuoterAbi) + types (PoolKey, PathKey, QuoteResult) — used by\n// trading, but core no longer ships swap UserOp builders / quote\n// orchestration.\nexport * from \"./perp/index\";\nexport * from \"./auth/index\";\n\n// v1.4 — Account Abstraction primitives (EIP-7702 + ERC-4337 v0.7)\nexport * from \"./userop/index\";\nexport * from \"./paymaster/index\";\nexport * from \"./utils/index\";\nexport * from \"./delegation/index\";\nexport * from \"./transport/index\";\n// Operator-fee quoter — pure on-chain + subgraph reads, lets the SDK\n// Direct path compute the PT operator fee without calling the issuer\n// backend. Sponsor-relayer's `FeeValidatorService` runs the same\n// math server-side (with a 5% tolerance window).\nexport * from \"./fee/index\";\n\n// v1.4 — Contract ABIs + addresses. ABI matches deployed PointToken on\n// Base mainnet; only `batchExecutor` address + Base Sepolia row remain\n// placeholder. EIP-712 helpers live under `./eip712/` and are already\n// exported above — not re-exported here.\n// Consumers: `import { POINT_TOKEN_V2_ABI, CONTRACT_ADDRESSES, ... } from '@pafi-dev/core'`\nexport * from \"./contracts/index\";\n\n// v1.5 — PAFI Web handoff (mobile + desktop modal helper).\n// `openPafiWebModal()` + adapter registry for platform-specific UX.\nexport * from \"./web-handoff/index\";\n\n// Subgraph helpers — pool discovery via PAFI-hosted subgraph.\n// Browser and Node compatible (plain fetch).\nexport * from \"./subgraph/index\";\n\n// -------------------------------------------------------------------------\n// Internal imports for PafiSDK class\n// -------------------------------------------------------------------------\nimport { buildMintRequestTypedData, signMintRequest, verifyMintRequest } from \"./eip712/mintRequest\";\nimport {\n buildReceiverConsentTypedData,\n signReceiverConsent,\n verifyReceiverConsent,\n} from \"./eip712/receiverConsent\";\nimport {\n getMintRequestNonce,\n getReceiverConsentNonce,\n getTokenName,\n} from \"./contract/pointToken\";\nimport { createLoginMessage } from \"./auth/loginMessage\";\nimport type { LoginMessageParams } from \"./auth/types\";\nimport { ConfigurationError } from \"./errors\";\nimport type {\n EIP712Signature,\n MintRequest,\n PafiSDKConfig,\n PointTokenDomainConfig,\n ReceiverConsent,\n SignatureVerification,\n} from \"./types\";\n\n// -------------------------------------------------------------------------\n// PafiSDK — convenience class wrapping all contract + crypto primitives.\n//\n// This class is HTTP-client-free on purpose. It covers signing, verifying,\n// contract reads, and calldata encoding — the things that need a signer\n// or a provider but no HTTP layer. The issuer backend defines its own HTTP\n// contract via `@pafi/issuer`; frontends build `fetch()` calls against\n// those types directly.\n// -------------------------------------------------------------------------\n\nexport class PafiSDK {\n private _pointTokenAddress?: Address;\n private _signer?: WalletClient;\n private _provider?: PublicClient;\n private _chainId?: number;\n\n // -------------------------------------------------------------------------\n // Domain namespaces — grouped by concern for better IDE autocomplete.\n // Each property is a plain object of bound methods; the underlying logic\n // lives in the flat methods below so both access styles work.\n // -------------------------------------------------------------------------\n\n readonly mint: {\n buildTypedData: PafiSDK[\"buildMintRequestTypedData\"];\n sign: PafiSDK[\"signMintRequest\"];\n verify: PafiSDK[\"verifyMintRequest\"];\n getNonce: PafiSDK[\"getMintRequestNonce\"];\n };\n\n readonly consent: {\n buildTypedData: PafiSDK[\"buildReceiverConsentTypedData\"];\n sign: PafiSDK[\"signReceiverConsent\"];\n verify: PafiSDK[\"verifyReceiverConsent\"];\n getNonce: PafiSDK[\"getReceiverConsentNonce\"];\n };\n\n readonly auth: {\n createLoginMessage: PafiSDK[\"createLoginMessage\"];\n signMessage: PafiSDK[\"signLoginMessage\"];\n };\n\n constructor(config: PafiSDKConfig) {\n this._pointTokenAddress = config.pointTokenAddress;\n this._signer = config.signer;\n this._chainId = config.chainId;\n\n if (config.provider) {\n this._provider = config.provider;\n } else if (config.rpcUrl) {\n this._provider = createPublicClient({\n transport: http(config.rpcUrl),\n });\n }\n\n this.mint = {\n buildTypedData: this.buildMintRequestTypedData.bind(this),\n sign: this.signMintRequest.bind(this),\n verify: this.verifyMintRequest.bind(this),\n getNonce: this.getMintRequestNonce.bind(this),\n };\n\n this.consent = {\n buildTypedData: this.buildReceiverConsentTypedData.bind(this),\n sign: this.signReceiverConsent.bind(this),\n verify: this.verifyReceiverConsent.bind(this),\n getNonce: this.getReceiverConsentNonce.bind(this),\n };\n\n this.auth = {\n createLoginMessage: this.createLoginMessage.bind(this),\n signMessage: this.signLoginMessage.bind(this),\n };\n }\n\n // -------------------------------------------------------------------------\n // Setters\n // -------------------------------------------------------------------------\n\n setPointTokenAddress(address: Address): void {\n this._pointTokenAddress = address;\n }\n\n setSigner(signer: WalletClient): void {\n this._signer = signer;\n }\n\n setProvider(provider: PublicClient): void {\n this._provider = provider;\n }\n\n // -------------------------------------------------------------------------\n // Private guards\n // -------------------------------------------------------------------------\n\n private requirePointToken(): Address {\n if (!this._pointTokenAddress) {\n throw new ConfigurationError(\"pointTokenAddress not set\");\n }\n return this._pointTokenAddress;\n }\n\n private requireProvider(): PublicClient {\n if (!this._provider) {\n throw new ConfigurationError(\"provider not set\");\n }\n return this._provider;\n }\n\n private requireSigner(): WalletClient {\n if (!this._signer) {\n throw new ConfigurationError(\"signer not set\");\n }\n return this._signer;\n }\n\n private requireChainId(): number {\n if (this._chainId === undefined) {\n throw new ConfigurationError(\"chainId not set\");\n }\n return this._chainId;\n }\n\n // -------------------------------------------------------------------------\n // Domain\n // -------------------------------------------------------------------------\n\n async getDomain(): Promise<PointTokenDomainConfig> {\n const provider = this.requireProvider();\n const pointToken = this.requirePointToken();\n const chainId = this.requireChainId();\n const name = await getTokenName(provider, pointToken);\n return { name, verifyingContract: pointToken, chainId };\n }\n\n // -------------------------------------------------------------------------\n // EIP-712 — delegates to pure functions\n // -------------------------------------------------------------------------\n\n async buildMintRequestTypedData(message: MintRequest) {\n const domain = await this.getDomain();\n return buildMintRequestTypedData(domain, message);\n }\n\n async buildReceiverConsentTypedData(message: ReceiverConsent) {\n const domain = await this.getDomain();\n return buildReceiverConsentTypedData(domain, message);\n }\n\n async signMintRequest(message: MintRequest): Promise<EIP712Signature> {\n const domain = await this.getDomain();\n return signMintRequest(this.requireSigner(), domain, message);\n }\n\n async verifyMintRequest(\n message: MintRequest,\n signature: Hex,\n expectedMinter: Address,\n ): Promise<SignatureVerification> {\n const domain = await this.getDomain();\n return verifyMintRequest(domain, message, signature, expectedMinter);\n }\n\n async signReceiverConsent(\n message: ReceiverConsent,\n ): Promise<EIP712Signature> {\n const domain = await this.getDomain();\n return signReceiverConsent(this.requireSigner(), domain, message);\n }\n\n async verifyReceiverConsent(\n message: ReceiverConsent,\n signature: Hex,\n expectedReceiver: Address,\n ): Promise<SignatureVerification> {\n const domain = await this.getDomain();\n return verifyReceiverConsent(domain, message, signature, expectedReceiver);\n }\n\n // -------------------------------------------------------------------------\n // Contract reads\n // -------------------------------------------------------------------------\n\n async getMintRequestNonce(receiver: Address): Promise<bigint> {\n return getMintRequestNonce(\n this.requireProvider(),\n this.requirePointToken(),\n receiver,\n );\n }\n\n async getReceiverConsentNonce(receiver: Address): Promise<bigint> {\n return getReceiverConsentNonce(\n this.requireProvider(),\n this.requirePointToken(),\n receiver,\n );\n }\n\n // -------------------------------------------------------------------------\n // Auth — EIP-4361 login helpers (offline, stateless)\n // -------------------------------------------------------------------------\n\n async createLoginMessage(\n params: Omit<LoginMessageParams, \"address\" | \"chainId\">,\n ): Promise<string> {\n const signer = this.requireSigner();\n const chainId = this.requireChainId();\n const account = signer.account;\n if (!account) {\n throw new ConfigurationError(\"signer has no account attached\");\n }\n return createLoginMessage({ ...params, address: account.address, chainId });\n }\n\n /** Sign a login message string with the current signer (personal_sign) */\n async signLoginMessage(message: string): Promise<Hex> {\n const signer = this.requireSigner();\n const account = signer.account;\n if (!account) {\n throw new ConfigurationError(\"signer has no account attached\");\n }\n return signer.signMessage({ account, message });\n }\n}\n\n// `buildUniversalRouterExecuteArgs` and other swap helpers moved to\n// `@pafi-dev/trading` along with `findBestQuote` (2026-04-27).\n","/**\n * Unified error base for the entire SDK (core + issuer + trading).\n * Subclasses declare `code` (machine-readable) and `httpStatus`\n * (recommended HTTP status for issuer's controller).\n *\n * Issuer's `createSdkErrorMapper` routes any `PafiSdkError` instance\n * through framework-specific exception factories; non-PafiSdkError\n * still becomes 500.\n */\nexport type SdkErrorHttpStatus =\n | \"not_found\"\n | \"forbidden\"\n | \"unprocessable\"\n | \"service_unavailable\";\n\n/**\n * Stripe-style error taxonomy. The SDK emits one of these on every\n * error so consumers can branch UI behavior on `type` (toast vs modal\n * vs retry banner) without whitelisting individual `code` values.\n */\nexport type PafiErrorType =\n | \"validation_error\"\n | \"authentication_error\"\n | \"authorization_error\"\n | \"not_found_error\"\n | \"business_logic_error\"\n | \"rate_limit_error\"\n | \"server_error\"\n | \"service_unavailable_error\";\n\n/** Numeric HTTP status implied by an `SdkErrorHttpStatus` slot. */\nexport const SDK_ERROR_HTTP_STATUS_CODE: Record<SdkErrorHttpStatus, number> = {\n not_found: 404,\n forbidden: 403,\n unprocessable: 422,\n service_unavailable: 503,\n};\n\n/** Default `type` slot for a numeric HTTP status. */\nexport function defaultErrorTypeForStatus(status: number): PafiErrorType {\n if (status === 400) return \"validation_error\";\n if (status === 401) return \"authentication_error\";\n if (status === 403) return \"authorization_error\";\n if (status === 404) return \"not_found_error\";\n if (status === 422) return \"business_logic_error\";\n if (status === 429) return \"rate_limit_error\";\n if (status === 503) return \"service_unavailable_error\";\n return \"server_error\";\n}\n\nexport abstract class PafiSdkError extends Error {\n abstract readonly code: string;\n /**\n * `true` when the FE should consider a retry safe — typically because\n * the failure is transient.\n */\n readonly safeToRetry: boolean = false;\n readonly details?: unknown;\n abstract readonly httpStatus: SdkErrorHttpStatus;\n /**\n * Optional Stripe-style taxonomy override. Defaults to the type\n * implied by `httpStatus` (forbidden→authorization_error,\n * unprocessable→business_logic_error, etc).\n */\n readonly type?: PafiErrorType;\n /**\n * Optional name of the request field that triggered the error (e.g.\n * `\"amount\"`, `\"chainId\"`). Surfaced on validation failures so the\n * client can highlight the offending field.\n */\n readonly param?: string;\n /**\n * Optional structured context (e.g. `{ available, requested }` for a\n * cap denial). Distinct from `details` — `metadata` is meant for\n * UI consumption; `details` carries raw debug info.\n */\n readonly metadata?: Record<string, unknown>;\n\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/**\n * @deprecated Use `PafiSdkError` (capital S, lowercase dk).\n * The two classes existed in parallel (\"PafiSDKError\" in core,\n * \"PafiSdkError\" in issuer) due to historical drift; consolidating\n * here. Kept as alias for back-compat through v0.7.x; will be removed\n * in v0.8.\n */\nexport class PafiSDKError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PafiSDKError\";\n }\n}\n\nexport class ConfigurationError extends PafiSDKError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class SigningError extends PafiSDKError {\n constructor(message: string) {\n super(message);\n this.name = \"SigningError\";\n }\n}\n\nexport class SimulationError extends PafiSDKError {\n constructor(\n public operation: string,\n public reason: string,\n ) {\n super(`Simulation failed for ${operation}: ${reason}`);\n this.name = \"SimulationError\";\n }\n}\n\nexport class ApiError extends PafiSDKError {\n constructor(\n message: string,\n public status?: number,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/**\n * Thrown by `quoteOperatorFee*` when an upstream price source\n * (Chainlink ETH/USD, PAFI subgraph) is unavailable or stale and the\n * caller did not opt in to the hardcoded fallback prices via\n * `allowStaleFallback: true`.\n *\n * Extends the unified `PafiSdkError` so issuer's `createSdkErrorMapper`\n * routes it to 503 instead of leaking as a 500.\n */\nexport class OracleStaleError extends PafiSdkError {\n readonly httpStatus = \"service_unavailable\" as const;\n readonly code = \"ORACLE_STALE\" as const;\n readonly source: \"chainlink\" | \"subgraph\";\n readonly reason: string;\n constructor(source: \"chainlink\" | \"subgraph\", reason: string) {\n super(`Oracle ${source} unavailable: ${reason}`);\n this.source = source;\n this.reason = reason;\n }\n}\n\n/**\n * Generic 4xx-class validation failure for input checks at any SDK\n * boundary (core helpers, trading handlers, etc.). Issuer's\n * `createSdkErrorMapper` routes to 422.\n *\n * Uses an instance `details` field so subclasses can override the\n * declaration; matches the issuer-side shape that pre-existed here.\n */\nexport class ValidationError extends PafiSdkError {\n readonly httpStatus = \"unprocessable\" as const;\n readonly type = \"validation_error\" as const;\n readonly code: string;\n declare readonly details?: Record<string, unknown>;\n declare readonly param?: string;\n declare readonly metadata?: Record<string, unknown>;\n\n constructor(\n code: string,\n message: string,\n details?: Record<string, unknown>,\n options?: { param?: string; metadata?: Record<string, unknown> },\n ) {\n super(message);\n this.code = code;\n (this as { details?: Record<string, unknown> }).details = details;\n if (options?.param) {\n (this as { param?: string }).param = options.param;\n }\n if (options?.metadata) {\n (this as { metadata?: Record<string, unknown> }).metadata = options.metadata;\n }\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport {\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n type VaultDepositFE,\n} from \"../contracts/real/orderlyVault\";\nimport { erc20ApproveOp, rawCallOp } from \"../userop/operations\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { Operation, PartialUserOperation } from \"../userop/types\";\n\n/**\n * v1.5 — Scenario 3: deposit USDC from the user's wallet into the\n * Orderly perp Vault on Base mainnet.\n *\n * Builds a `PartialUserOperation` packaging the 2 inner calls:\n *\n * 1. `USDC.approve(orderlyVault, amount)` — let the Vault pull USDC\n * 2. `OrderlyVault.deposit{value: layerZeroFee}(VaultDepositFE)` —\n * transfer USDC into the Vault + emit a LayerZero message that\n * credits the user's perp account on the Orderly chain\n *\n * ## ⚠️ Native ETH constraint\n *\n * PAFI sponsor-relayer sponsors GAS, **not `msg.value`**. The LayerZero\n * cross-chain fee MUST come from the user's own native ETH balance on\n * Base — even when the rest of the UserOp is sponsored.\n *\n * Quote the fee BEFORE calling this builder via:\n *\n * const fee = await client.readContract({\n * address: orderlyVault,\n * abi: ORDERLY_VAULT_ABI,\n * functionName: 'getDepositFee',\n * args: [user, depositData],\n * });\n *\n * If `user.eth < fee`, surface this error to the FE so the user can\n * top up before retrying — the Vault `deposit{value: 0}` call will\n * revert otherwise.\n *\n * ## Why no PT/USDC fee deduction?\n *\n * Unlike Scenario 1/2/4 which deduct an operator fee in PT/USDC inside\n * the batch, perp deposit doesn't append a fee transfer because:\n *\n * - User is paying Orderly's LayerZero fee directly via `msg.value`\n * - There's no PAFI-specific operator cost on top — Orderly handles\n * the off-chain accounting once the LayerZero message lands\n *\n * If we want to charge a PAFI service fee on top later, append a\n * `USDC.transfer(feeRecipient, fee)` op — same pattern as the swap\n * builder.\n */\nexport interface BuildPerpDepositWithGasDeductionParams {\n /** User EOA (will be `msg.sender` via EIP-7702 delegation). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Chain ID for Orderly Vault address resolution. */\n chainId: number;\n /**\n * Override Orderly Vault address (e.g. for fork tests). Defaults to\n * `ORDERLY_VAULT_ADDRESSES[chainId]`.\n */\n vaultAddress?: Address;\n\n /**\n * USDC ERC-20 address — the actual token Orderly accepts. Caller\n * resolves this via `vault.getAllowedToken(TOKEN_HASHES.USDC)` so we\n * don't hardcode the wrong USDC variant (native vs bridged).\n */\n usdcAddress: Address;\n\n /** USDC amount to deposit (uint128, 6 decimals). */\n amount: bigint;\n\n /**\n * Pre-built `VaultDepositFE` struct — caller computes accountId via\n * `computeAccountId(user, brokerHash)` and supplies tokenHash.\n */\n depositData: VaultDepositFE;\n\n /**\n * LayerZero fee in wei — from `vault.getDepositFee(user, data)`.\n * Becomes the `msg.value` on the `deposit()` call. User MUST hold\n * ≥ this much native ETH or the call reverts.\n */\n layerZeroFee: bigint;\n\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for Scenario 3. Returns a\n * `PartialUserOperation` — caller attaches paymaster sponsorship for\n * gas + the user's UserOp-hash signature, then submits to the Bundler.\n */\nexport function buildPerpDepositWithGasDeduction(\n params: BuildPerpDepositWithGasDeductionParams,\n): PartialUserOperation {\n if (params.amount <= 0n) {\n throw new Error(\"buildPerpDepositWithGasDeduction: amount must be positive\");\n }\n if (params.layerZeroFee < 0n) {\n throw new Error(\n \"buildPerpDepositWithGasDeduction: layerZeroFee cannot be negative\",\n );\n }\n if (params.depositData.tokenAmount !== params.amount) {\n throw new Error(\n `buildPerpDepositWithGasDeduction: depositData.tokenAmount (${params.depositData.tokenAmount}) ` +\n `must equal amount (${params.amount})`,\n );\n }\n\n const vault =\n params.vaultAddress ?? ORDERLY_VAULT_ADDRESSES[params.chainId];\n if (!vault) {\n throw new Error(\n `buildPerpDepositWithGasDeduction: no Orderly Vault address for chainId ${params.chainId}`,\n );\n }\n\n const depositCallData: Hex = encodeFunctionData({\n abi: ORDERLY_VAULT_ABI,\n functionName: \"deposit\",\n args: [params.depositData],\n });\n\n const operations: Operation[] = [\n erc20ApproveOp(params.usdcAddress, vault, params.amount),\n {\n ...rawCallOp(vault, depositCallData),\n // BatchExecutor passes `value` from the inner call along; this\n // becomes the LayerZero fee. The aggregated `msg.value` for the\n // top-level UserOp must equal the sum of inner `value`s.\n value: params.layerZeroFee,\n },\n ];\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 800_000n,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import { keccak256, encodePacked, encodeAbiParameters } from \"viem\";\nimport type { Address, Hex } from \"viem\";\n\n/**\n * Orderly Network Vault — entrypoint for **perp deposit** flow on\n * Base mainnet (Scenario 3).\n *\n * Source of truth for addresses + integration:\n * https://orderly.network/docs/build-on-omnichain/addresses#base\n *\n * ## Architecture\n *\n * User wallet (Base)\n * │ 1. USDC.approve(vault, amount)\n * │ 2. vault.deposit{value: layerZeroFee}({\n * │ accountId, brokerHash, tokenHash, tokenAmount\n * │ })\n * ▼\n * OrderlyVault (Base)\n * │ — locks USDC, emits LayerZero message\n * ▼\n * Orderly chain (off-chain matching engine)\n * │ — credits the user's perp account\n * ▼\n * User can now place perp orders via Orderly REST/WS API\n *\n * **Important:** `value` is required and is the LayerZero cross-chain\n * fee (paid in native ETH on Base). Quote it via\n * `vault.getDepositFee(user, data)` BEFORE calling deposit. Fees vary\n * with destination chain congestion.\n *\n * ## Sponsored vs direct\n *\n * ERC-4337 paymasters sponsor GAS, not `msg.value`. Even on the\n * sponsored path the user MUST hold enough native ETH on Base to cover\n * `getDepositFee()` (typically ~0.0002 ETH at quiet times).\n */\n\n/** Orderly Vault on Base mainnet (EIP-55 checksum). */\nexport const ORDERLY_VAULT_BASE_MAINNET: Address =\n \"0x816f722424B49Cf1275cc86DA9840Fbd5a6167e9\";\n\n/**\n * Per-chain registry of the Orderly Vault. Add chains here as Orderly\n * deploys them.\n */\nexport const ORDERLY_VAULT_ADDRESSES: Record<number, Address> = {\n 8453: ORDERLY_VAULT_BASE_MAINNET,\n};\n\n/**\n * Pre-computed broker hashes — `keccak256(abi.encodePacked(brokerId))`.\n * Add new brokers as they launch.\n *\n * Reference: https://orderly.network/docs/build-on-omnichain/user-flows/accountId\n */\nexport const BROKER_HASHES = {\n /** Default partner broker on Base — most commonly whitelisted. */\n woofi_pro: keccak256(encodePacked([\"string\"], [\"woofi_pro\"])),\n /** Orderly's own white-label broker. */\n orderly: keccak256(encodePacked([\"string\"], [\"orderly\"])),\n /** LogX. */\n logx: keccak256(encodePacked([\"string\"], [\"logx\"])),\n} as const satisfies Record<string, Hex>;\n\n/**\n * Pre-computed token hashes — `keccak256(abi.encodePacked(tokenSymbol))`.\n * The hash maps to the actual ERC-20 address on each chain via\n * `vault.getAllowedToken(tokenHash)`.\n *\n * Note: Orderly canonicalises by symbol (USDC, not \"USD Coin\").\n */\nexport const TOKEN_HASHES = {\n USDC: keccak256(encodePacked([\"string\"], [\"USDC\"])),\n} as const satisfies Record<string, Hex>;\n\n/**\n * Compute Orderly's `accountId` — uniquely identifies a user+broker\n * tuple. Matches the off-chain formula used by the Orderly SDK so\n * deposits + future REST API calls reference the same account.\n *\n * accountId = keccak256(abi.encode(user, brokerHash))\n *\n * Note `abi.encode` (not `encodePacked`) — uses 32-byte left-padding.\n */\nexport function computeAccountId(\n user: Address,\n brokerHash: Hex,\n): Hex {\n return keccak256(\n encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"bytes32\" },\n ],\n [user, brokerHash],\n ),\n );\n}\n\n/**\n * Minimal Orderly Vault ABI — just the functions PAFI needs for\n * Scenario 3 (perp deposit). Full ABI is on Orderly's docs site.\n */\nexport const ORDERLY_VAULT_ABI = [\n // Deposit USDC into Orderly perp account. Emits LayerZero message\n // to the Orderly chain. `msg.value` MUST equal `getDepositFee(...)`.\n {\n type: \"function\",\n name: \"deposit\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"data\",\n type: \"tuple\",\n components: [\n { name: \"accountId\", type: \"bytes32\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"tokenHash\", type: \"bytes32\" },\n { name: \"tokenAmount\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [],\n },\n // Quote the LayerZero fee for a deposit message. Pass the same\n // VaultDepositFE struct you intend to send.\n {\n type: \"function\",\n name: \"getDepositFee\",\n stateMutability: \"view\",\n inputs: [\n { name: \"user\", type: \"address\" },\n {\n name: \"data\",\n type: \"tuple\",\n components: [\n { name: \"accountId\", type: \"bytes32\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"tokenHash\", type: \"bytes32\" },\n { name: \"tokenAmount\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n // Pre-flight check — is this brokerId whitelisted on this Vault?\n {\n type: \"function\",\n name: \"getAllowedBroker\",\n stateMutability: \"view\",\n inputs: [{ name: \"brokerHash\", type: \"bytes32\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n // Pre-flight check — what ERC-20 address does this token symbol\n // resolve to on this Vault?\n {\n type: \"function\",\n name: \"getAllowedToken\",\n stateMutability: \"view\",\n inputs: [{ name: \"tokenHash\", type: \"bytes32\" }],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n] as const;\n\n/** Struct mirror of `IOrderlyVault.VaultDepositFE` for type-safe builders. */\nexport interface VaultDepositFE {\n accountId: Hex;\n brokerHash: Hex;\n tokenHash: Hex;\n /** uint128 — USDC has 6 decimals. */\n tokenAmount: bigint;\n}\n","import { encodeFunctionData, erc20Abi, parseAbi } from \"viem\";\nimport type { Address } from \"viem\";\nimport type { Operation } from \"./types\";\n\n/**\n * ERC20Burnable extension — `burn(uint256 amount)` burns from msg.sender.\n * The EOA (via EIP-7702 delegation) is the `msg.sender` when a batch\n * runs — so this burns the user's balance without any role check.\n */\nconst ERC20_BURNABLE_ABI = parseAbi([\"function burn(uint256 amount)\"]);\n\n/**\n * Build an ERC-20 `transfer(to, amount)` operation. Used inside a batch\n * to move fee tokens from the user to the fee recipient atomically with\n * the main action.\n */\nexport function erc20TransferOp(\n token: Address,\n to: Address,\n amount: bigint,\n): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"transfer\",\n args: [to, amount],\n }),\n };\n}\n\n/**\n * Build an ERC-20 `approve(spender, amount)` operation. Used inside a\n * batch before a swap / deposit call so the AMM / protocol can pull\n * tokens from the user.\n */\nexport function erc20ApproveOp(\n token: Address,\n spender: Address,\n amount: bigint,\n): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n }),\n };\n}\n\n/**\n * Build an ERC-20 `burn(amount)` operation (OpenZeppelin ERC20Burnable\n * extension). Burns from `msg.sender`, which — via EIP-7702 — is the\n * user's EOA.\n *\n * Requires the PointToken contract to expose a public `burn(uint256)`\n * without a role check. See\n * [SDK_V1.4_TASKS.md §11 — PointToken.burn callable via batch].\n */\nexport function erc20BurnOp(token: Address, amount: bigint): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: ERC20_BURNABLE_ABI,\n functionName: \"burn\",\n args: [amount],\n }),\n };\n}\n\n/**\n * Build a raw call operation with caller-supplied calldata. Useful for\n * non-ERC-20 contracts (PoolManager.swap, PerpDEX.deposit, Relayer.mint)\n * where the encoding is specific to that protocol.\n */\nexport function rawCallOp(\n target: Address,\n data: `0x${string}`,\n value: bigint = 0n,\n): Operation {\n return { target, value, data };\n}\n","import { decodeFunctionData, encodeFunctionData, parseAbi } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { Operation } from \"./types\";\n\n/**\n * Standard BatchExecutor ABI — a contract that takes an array of calls\n * and invokes each one in sequence, reverting all if any fail.\n *\n * Function name is `executeBatch` (selector `0x34fcd5be`) to match\n * Pimlico's `Simple7702Account` and Coinbase Smart Wallet v2 — both\n * EIP-7702 delegate impls expose `executeBatch(Call[])`, not `execute`.\n * The shorter `execute(Call[])` (selector `0x3f707e6b`) only exists on\n * legacy/standalone batch executor contracts; calling it on a 7702\n * delegated EOA falls through to the fallback function and reverts\n * with \"account: not from EntryPoint\" (AA23).\n */\nexport const BATCH_EXECUTOR_ABI = parseAbi([\n \"function executeBatch((address target, uint256 value, bytes data)[] calls)\",\n]);\n\n/**\n * Encode a batch of operations into calldata for `BatchExecutor.execute()`.\n * The resulting calldata goes into `UserOperation.callData`.\n *\n * When the EOA has an EIP-7702 delegation to a BatchExecutor, calling\n * this calldata against the EOA runs all operations with\n * `msg.sender = EOA` for each inner call.\n *\n * @param operations batch of calls, in execution order\n * @returns calldata bytes for `execute((address,uint256,bytes)[])`\n */\nexport function encodeBatchExecute(operations: Operation[]): Hex {\n if (operations.length === 0) {\n throw new Error(\"encodeBatchExecute: operations array must not be empty\");\n }\n return encodeFunctionData({\n abi: BATCH_EXECUTOR_ABI,\n functionName: \"executeBatch\",\n args: [\n operations.map((op) => ({\n target: op.target,\n value: op.value,\n data: op.data,\n })),\n ],\n });\n}\n\n/**\n * Decode `BatchExecutor.execute(calls[])` callData back into individual\n * `{ to, data, value }` objects.\n *\n * Used by issuer backends to convert a `PartialUserOperation.callData`\n * into the `calls[]` array returned to web/FE clients (which submit via\n * `permissionless.sendTransaction({ calls })`).\n */\nexport function decodeBatchExecuteCalls(\n callData: Hex,\n): Array<{ to: string; data: string; value: string }> {\n const { args } = decodeFunctionData({\n abi: BATCH_EXECUTOR_ABI,\n data: callData,\n });\n return (\n args[0] as ReadonlyArray<{ target: Address; value: bigint; data: Hex }>\n ).map((c) => ({\n to: c.target,\n data: c.data,\n value: c.value.toString(),\n }));\n}\n","import type { Address } from \"viem\";\nimport type { Operation, PartialUserOperation, UserOperation } from \"./types\";\nimport { encodeBatchExecute } from \"./batchExecute\";\n\n/**\n * Default gas limits — rough upper bounds for a 2-op batch on Base.\n * Bundler re-estimates before submission, so these are only used when\n * the caller doesn't supply their own.\n */\nconst DEFAULT_CALL_GAS_LIMIT = 500_000n;\nconst DEFAULT_VERIFICATION_GAS_LIMIT = 150_000n;\nconst DEFAULT_PRE_VERIFICATION_GAS = 50_000n;\n\nexport interface BuildPartialUserOpParams {\n /** User's EOA (with EIP-7702 delegation). */\n sender: Address;\n /** Batch of operations — encoded into callData via `encodeBatchExecute`. */\n operations: Operation[];\n /** EntryPoint nonce for this sender. Caller fetches from the EntryPoint contract. */\n nonce: bigint;\n /** Optional gas overrides; bundler re-estimates before submission. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n /** Optional fee overrides; bundler usually fills these. */\n feeOverrides?: {\n maxFeePerGas?: bigint;\n maxPriorityFeePerGas?: bigint;\n };\n}\n\n/**\n * Build a partial ERC-4337 UserOperation from a batch of operations.\n * Paymaster fields and signature are populated later:\n * 1. Call `PafiBackendClient.requestSponsorship()` → get paymaster fields\n * 2. Compute userOpHash and have the user sign it (via Privy)\n * 3. Attach `signature` → submit to bundler\n *\n * This function is a pure struct builder — no network calls.\n */\nexport function buildPartialUserOperation(\n params: BuildPartialUserOpParams,\n): PartialUserOperation {\n return {\n sender: params.sender,\n nonce: params.nonce,\n callData: encodeBatchExecute(params.operations),\n callGasLimit: params.gasLimits?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ??\n DEFAULT_VERIFICATION_GAS_LIMIT,\n preVerificationGas:\n params.gasLimits?.preVerificationGas ?? DEFAULT_PRE_VERIFICATION_GAS,\n maxFeePerGas: params.feeOverrides?.maxFeePerGas ?? 0n,\n maxPriorityFeePerGas: params.feeOverrides?.maxPriorityFeePerGas ?? 0n,\n };\n}\n\n/**\n * Assemble a full UserOperation once paymaster fields + signature are\n * known. Used after `PafiBackendClient.requestSponsorship()` and user\n * signing complete.\n */\nexport function assembleUserOperation(\n partial: PartialUserOperation,\n paymaster: {\n paymaster: Address;\n paymasterData: `0x${string}`;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n },\n signature: `0x${string}`,\n): UserOperation {\n return {\n ...partial,\n paymaster: paymaster.paymaster,\n paymasterData: paymaster.paymasterData,\n paymasterVerificationGasLimit: paymaster.paymasterVerificationGasLimit,\n paymasterPostOpGasLimit: paymaster.paymasterPostOpGasLimit,\n signature,\n };\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { erc20ApproveOp, erc20TransferOp, rawCallOp } from \"../userop/operations\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { Operation, PartialUserOperation } from \"../userop/types\";\n\n/**\n * Minimal ABI for the Orderly perp-deposit Relay (deployed at\n * `CONTRACT_ADDRESSES[chainId].orderlyRelay`).\n *\n * The Relay holds an ETH reserve and pays Orderly's LayerZero msg.value\n * out of it. Users only need USDC + the Relay-charged USDC fee — they\n * never hold ETH for msg.value, which unblocks the ERC-4337 sponsored\n * gas path for perp deposits (paymaster covers gas, NOT msg.value).\n */\nexport const ORDERLY_RELAY_ABI = [\n {\n type: \"function\",\n name: \"deposit\",\n stateMutability: \"nonpayable\",\n inputs: [\n {\n name: \"req\",\n type: \"tuple\",\n components: [\n { name: \"token\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"totalAmount\", type: \"uint128\" },\n { name: \"maxFee\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [],\n },\n {\n type: \"function\",\n name: \"quoteTokenFee\",\n stateMutability: \"view\",\n inputs: [\n {\n name: \"req\",\n type: \"tuple\",\n components: [\n { name: \"token\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"totalAmount\", type: \"uint128\" },\n { name: \"maxFee\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [{ name: \"\", type: \"uint128\" }],\n },\n] as const;\n\n/**\n * `Relay.DepositRequest` — the struct passed to `deposit()` and\n * `quoteTokenFee()`. The Relay pulls `totalAmount` of `token` from\n * `msg.sender`, computes a token-denominated fee (capped at `maxFee`)\n * to cover the LayerZero msg.value out of its ETH reserve, and forwards\n * `(totalAmount - tokenFee)` to Orderly Vault on behalf of `receiver`.\n */\nexport interface OrderlyRelayDepositRequest {\n /** ERC-20 to deposit (must be registered + enabled on the Relay). */\n token: Address;\n /** Orderly account owner — typically the user's EOA. */\n receiver: Address;\n /** Orderly broker hash (e.g. `BROKER_HASHES.woofi_pro`). */\n brokerHash: Hex;\n /** Total amount the user is sending to the Relay (raw token units, uint128). */\n totalAmount: bigint;\n /** Max acceptable token fee — slippage cap on the Relay's USD-pricing. */\n maxFee: bigint;\n}\n\nexport interface BuildPerpDepositViaRelayParams {\n /** User EOA (msg.sender via EIP-7702 delegation). */\n userAddress: Address;\n /** ERC-4337 account nonce. */\n aaNonce: bigint;\n /** Relay contract address — `getContractAddresses(chainId).orderlyRelay`. */\n relayAddress: Address;\n /** Deposit request (token, receiver, brokerHash, totalAmount, maxFee). */\n request: OrderlyRelayDepositRequest;\n\n /**\n * Optional USDC (input-token) gas-fee transfer prepended to the batch.\n * The user holds USDC at the start of the batch, so the fee comes out\n * of the same input token — no second-token requirement. Set both\n * `gasFeeUsdcRecipient` and `gasFeeUsdc` together for sponsored\n * flows (PAFI gas reimbursement). Pass `0n` / `undefined` for the\n * fallback path where the user pays ERC-4337 gas in ETH directly.\n *\n * v0.7 — input-token fee position rule: user holds USDC BEFORE\n * deposit (token-availability), so charge there. Replaces the old\n * `gasFeePt` / `gasFeePtRecipient` / `pointTokenAddress` triple from\n * v0.6.\n */\n gasFeeUsdc?: bigint;\n gasFeeUsdcRecipient?: Address;\n\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build a UserOp for Orderly perp deposit via the PAFI Relay.\n *\n * Sponsored ops: `[USDC.transfer(feeRecipient, gasFeeUsdc), USDC.approve(relay, total), Relay.deposit(req)]`\n * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`\n *\n * No `msg.value` — the Relay covers LayerZero out of its own ETH reserve.\n *\n * Fee position rule: user holds USDC at start of batch → fee transfer\n * runs FIRST in the same token. User must hold `totalAmount + gasFeeUsdc`\n * USDC; net deposit to Orderly is `totalAmount - relayTokenFee`.\n */\nexport function buildPerpDepositViaRelay(\n params: BuildPerpDepositViaRelayParams,\n): PartialUserOperation {\n if (params.request.totalAmount <= 0n) {\n throw new Error(\"buildPerpDepositViaRelay: totalAmount must be positive\");\n }\n if (params.request.maxFee < 0n) {\n throw new Error(\"buildPerpDepositViaRelay: maxFee cannot be negative\");\n }\n if (!params.relayAddress) {\n throw new Error(\"buildPerpDepositViaRelay: relayAddress required\");\n }\n\n const operations: Operation[] = [];\n\n // Optional USDC (input-token) gas fee transfer — sponsored path.\n // Position: BEFORE approve+deposit, because user holds USDC at this\n // point in the batch (token-availability rule).\n if (params.gasFeeUsdc && params.gasFeeUsdc > 0n) {\n if (!params.gasFeeUsdcRecipient) {\n throw new Error(\n \"buildPerpDepositViaRelay: gasFeeUsdcRecipient required when gasFeeUsdc > 0\",\n );\n }\n operations.push(\n erc20TransferOp(\n params.request.token,\n params.gasFeeUsdcRecipient,\n params.gasFeeUsdc,\n ),\n );\n }\n\n // USDC.approve(relay, totalAmount) — Relay pulls via transferFrom.\n operations.push(\n erc20ApproveOp(\n params.request.token,\n params.relayAddress,\n params.request.totalAmount,\n ),\n );\n\n // Relay.deposit(req) — Relay charges tokenFee, deposits the rest to Orderly.\n const depositCallData: Hex = encodeFunctionData({\n abi: ORDERLY_RELAY_ABI,\n functionName: \"deposit\",\n args: [\n {\n token: params.request.token,\n receiver: params.request.receiver,\n brokerHash: params.request.brokerHash,\n totalAmount: params.request.totalAmount,\n maxFee: params.request.maxFee,\n },\n ],\n });\n operations.push(rawCallOp(params.relayAddress, depositCallData));\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 800_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import type { Address, Hex } from \"viem\";\nexport { ENTRY_POINT_V07, ENTRY_POINT_V08 } from \"../constants\";\n\n/**\n * A single call inside a batch. `BatchExecutor.execute(Call[])` iterates\n * and invokes each one. When the batch runs via EIP-7702 delegation,\n * `msg.sender` for each call is the user's EOA.\n */\nexport interface Operation {\n target: Address;\n value: bigint;\n data: Hex;\n}\n\n/**\n * Paymaster fields attached to a UserOperation. Populated by the\n * PAFI sponsor-relayer (via PAFI Backend proxy) before the user signs.\n */\nexport interface PaymasterFields {\n paymaster: Address;\n paymasterData: Hex;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n}\n\n/**\n * Partial UserOp used during preparation — before paymaster fields are\n * attached or the user signs.\n */\nexport interface PartialUserOperation {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n}\n\n/**\n * Full ERC-4337 v0.7 UserOperation, ready for bundler submission.\n */\nexport interface UserOperation extends PartialUserOperation {\n paymaster: Address;\n paymasterData: Hex;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n signature: Hex;\n}\n\n/**\n * Receipt returned by a bundler after a UserOp lands on-chain.\n */\nexport interface UserOpReceipt {\n userOpHash: Hex;\n success: boolean;\n txHash: Hex;\n blockNumber: bigint;\n gasUsed: bigint;\n /** Effective gas cost paid (wei). */\n actualGasCost: bigint;\n}\n\n/**\n * Sentinel operation value used in tests + docs when `Operation.value`\n * is irrelevant (ERC-20 transfers, for example).\n */\nexport const ZERO_VALUE = 0n;\n","import type { Address, Hex } from \"viem\";\n\n/**\n * Serialize a fully assembled ERC-4337 v0.7 UserOperation into the\n * JSON-RPC wire format expected by `eth_sendUserOperation`.\n *\n * All numeric fields (nonce, gas limits, fees) are converted from bigint\n * to 0x-prefixed hex strings. Optional paymaster fields are included when\n * present, otherwise set to null.\n *\n * Use this on the **backend** (mobile submit path) right before calling\n * `PafiBackendClient.relayUserOperation()`.\n */\nexport function serializeUserOpToJsonRpc(\n userOp: {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n paymaster?: Address;\n paymasterVerificationGasLimit?: bigint;\n paymasterPostOpGasLimit?: bigint;\n paymasterData?: Hex;\n },\n signature: Hex,\n): Record<string, string | null> {\n const p = userOp;\n return {\n sender: p.sender,\n nonce: `0x${p.nonce.toString(16)}`,\n factory: null,\n factoryData: null,\n callData: p.callData,\n callGasLimit: `0x${p.callGasLimit.toString(16)}`,\n verificationGasLimit: `0x${p.verificationGasLimit.toString(16)}`,\n preVerificationGas: `0x${p.preVerificationGas.toString(16)}`,\n maxFeePerGas: `0x${p.maxFeePerGas.toString(16)}`,\n maxPriorityFeePerGas: `0x${p.maxPriorityFeePerGas.toString(16)}`,\n paymaster: p.paymaster ?? null,\n paymasterData: p.paymasterData ?? null,\n paymasterVerificationGasLimit:\n p.paymasterVerificationGasLimit != null\n ? `0x${p.paymasterVerificationGasLimit.toString(16)}`\n : null,\n paymasterPostOpGasLimit:\n p.paymasterPostOpGasLimit != null\n ? `0x${p.paymasterPostOpGasLimit.toString(16)}`\n : null,\n signature,\n };\n}\n","import {\n concat,\n hashTypedData,\n pad,\n toHex,\n type Address,\n type Hex,\n type TypedDataDomain,\n} from \"viem\";\nimport { ENTRY_POINT_V08 } from \"./types\";\n\nconst PACKED_USER_OPERATION_TYPES = {\n PackedUserOperation: [\n { name: \"sender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"initCode\", type: \"bytes\" },\n { name: \"callData\", type: \"bytes\" },\n { name: \"accountGasLimits\", type: \"bytes32\" },\n { name: \"preVerificationGas\", type: \"uint256\" },\n { name: \"gasFees\", type: \"bytes32\" },\n { name: \"paymasterAndData\", type: \"bytes\" },\n ],\n} as const;\n\nexport type PackedUserOperationMessage = {\n sender: Address;\n nonce: bigint;\n initCode: Hex;\n callData: Hex;\n accountGasLimits: Hex;\n preVerificationGas: bigint;\n gasFees: Hex;\n paymasterAndData: Hex;\n};\n\nexport type UserOpTypedData = {\n domain: TypedDataDomain;\n types: typeof PACKED_USER_OPERATION_TYPES;\n primaryType: \"PackedUserOperation\";\n message: PackedUserOperationMessage;\n};\n\n/**\n * Build the EIP-712 typed-data payload for an ERC-4337 v0.8 UserOp.\n *\n * The deployed Pimlico `Simple7702Account` (impl `0xe6Cae8...`) validates\n * the user's signature by calling `SignatureCheckerLib.isValidSignatureNow`\n * with the **raw** userOpHash (no EIP-191 prefix). For an EOA signer this\n * means `ecrecover(userOpHash, sig)` must equal the EOA address.\n *\n * Because `userOpHash` is itself the EIP-712 typed digest of the\n * `PackedUserOperation` struct, signing the typed data with\n * `eth_signTypedData_v4` produces a signature whose recover-from-raw-digest\n * == the userOpHash. That matches what the contract expects.\n *\n * Do NOT sign with `personal_sign` / `signMessage({ raw })` — that adds the\n * EIP-191 prefix, which the contract does not undo, so recovery returns a\n * different address and the bundler reverts with `AA24 signature error`.\n */\nexport function buildUserOpTypedData(\n userOp: {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n paymaster?: Address;\n paymasterVerificationGasLimit?: bigint;\n paymasterPostOpGasLimit?: bigint;\n paymasterData?: Hex;\n },\n chainId: number,\n): UserOpTypedData {\n const accountGasLimits = pack128(\n userOp.verificationGasLimit,\n userOp.callGasLimit,\n );\n const gasFees = pack128(userOp.maxPriorityFeePerGas, userOp.maxFeePerGas);\n\n const paymasterAndData: Hex = userOp.paymaster\n ? concat([\n userOp.paymaster,\n pad(toHex(userOp.paymasterVerificationGasLimit ?? 0n), { size: 16 }),\n pad(toHex(userOp.paymasterPostOpGasLimit ?? 0n), { size: 16 }),\n (userOp.paymasterData ?? \"0x\") as Hex,\n ])\n : \"0x\";\n\n return {\n domain: {\n name: \"ERC4337\",\n version: \"1\",\n chainId,\n verifyingContract: ENTRY_POINT_V08,\n },\n types: PACKED_USER_OPERATION_TYPES,\n primaryType: \"PackedUserOperation\",\n message: {\n sender: userOp.sender,\n nonce: userOp.nonce,\n initCode: \"0x\" as Hex,\n callData: userOp.callData,\n accountGasLimits,\n preVerificationGas: userOp.preVerificationGas,\n gasFees,\n paymasterAndData,\n },\n };\n}\n\n/**\n * EIP-712 typed digest of an ERC-4337 v0.8 UserOp. Equals on-chain\n * `EntryPoint.getUserOpHash(userOp)`.\n */\nexport function computeUserOpHash(\n userOp: Parameters<typeof buildUserOpTypedData>[0],\n chainId: number,\n): Hex {\n const td = buildUserOpTypedData(userOp, chainId);\n return hashTypedData(td);\n}\n\nfunction pack128(hi: bigint, lo: bigint): Hex {\n return `0x${((hi << 128n) | lo).toString(16).padStart(64, \"0\")}` as Hex;\n}\n","import { type Address, type Hex, getAddress } from \"viem\";\n\n/**\n * EIP-7702 delegate impls supported by the PAFI mobile prepare/submit\n * flow. Each impl exposes `execute((address,uint256,bytes)[])` (same\n * selector `0x34fcd5be...`) so callData encoding is identical, but\n * each may use a slightly different dummy-signature pattern that\n * Pimlico's `pm_sponsorUserOperation` simulation accepts.\n */\nexport type DelegateImpl =\n | \"simple7702\" // Pimlico's `to7702SimpleSmartAccount` impl\n | \"batchExecutor\" // Coinbase Smart Wallet v2 BatchExecutor\n | \"unknown\";\n\n/**\n * Pimlico's `Simple7702Account` implementation address on Base mainnet.\n * Used by `permissionless.to7702SimpleSmartAccount`.\n */\nexport const SIMPLE_7702_IMPL_BASE_MAINNET =\n \"0xe6Cae83BdE06E4c305530e199D7217f42808555B\" as Address;\n\n/**\n * Coinbase Smart Wallet v2 BatchExecutor — original PAFI delegation\n * target. Same on Base mainnet + Base Sepolia.\n */\nexport const BATCH_EXECUTOR_7702_IMPL =\n \"0x7702cb554e6bFb442cb743A7dF23154544a7176C\" as Address;\n\n/**\n * Standard ERC-4337 v0.7 ECDSA dummy signature — 65 bytes that\n * are well-formed (so signature recovery doesn't crash) but\n * obviously invalid (so they can't accidentally authorize a real\n * tx). Both Simple7702 and BatchExecutor accept this pattern as\n * the \"estimating\" signature during paymaster simulation.\n *\n * Source: viem-account-abstraction's default; matches what\n * `permissionless.toSimpleSmartAccount` and `to7702SimpleSmartAccount`\n * use for `getStubSignature()`.\n */\nexport const DUMMY_SIGNATURE_V07: Hex =\n \"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c\";\n\n/**\n * Map an EIP-7702 delegate target address to its `DelegateImpl` kind.\n * Returns `'unknown'` when the address isn't a recognised PAFI-supported\n * impl — caller should reject or fall back to a default behaviour.\n */\nexport function detectDelegateImpl(delegate: Address | null | undefined): DelegateImpl {\n if (!delegate) return \"unknown\";\n const addr = getAddress(delegate).toLowerCase();\n if (addr === SIMPLE_7702_IMPL_BASE_MAINNET.toLowerCase()) return \"simple7702\";\n if (addr === BATCH_EXECUTOR_7702_IMPL.toLowerCase()) return \"batchExecutor\";\n return \"unknown\";\n}\n\n/**\n * Return a dummy signature appropriate for a given delegate impl. Used\n * by sponsor-relayer's `pm_sponsorUserOperation` forwarding so Pimlico\n * can simulate validateUserOp without the user's actual signature\n * (which is supplied later via `personal_sign(userOpHash)`).\n *\n * Currently both Simple7702 and BatchExecutor use the same v0.7 ECDSA\n * dummy. Kept impl-keyed so future impls (Safe, Kernel, Biconomy) can\n * supply their own pattern (e.g. ERC-1271 stubs) without forcing a\n * sponsor-relayer redeploy.\n */\nexport function getDummySignatureFor7702(impl: DelegateImpl): Hex {\n // Same dummy works for both impls — both use ECDSA recovery on\n // userOpHash, both accept the v0.7 standard stub.\n void impl;\n return DUMMY_SIGNATURE_V07;\n}\n","import type { PaymasterConfig } from \"./types\";\n\n/**\n * @deprecated v0.7.1 — module-level paymaster config is unused in\n * production. The actual paymaster path runs through\n * `@pafi-dev/issuer/PafiBackendClient` (instantiated per-issuer with\n * its own config). Will be removed in v0.8. Migrate by passing\n * `PafiBackendClient` directly into your issuer adapter / handler.\n *\n * Kept exported through v0.7.x for back-compat.\n */\nlet _config: PaymasterConfig | null = null;\n\nlet _deprecationWarned = false;\nfunction warnDeprecated(fn: string): void {\n if (_deprecationWarned) return;\n _deprecationWarned = true;\n // eslint-disable-next-line no-console\n console.warn(\n `[PAFI] DEPRECATION (v0.7.1+): \\`${fn}\\` from @pafi-dev/core/paymaster is ` +\n \"deprecated and will be removed in v0.8. Use `PafiBackendClient` from \" +\n \"@pafi-dev/issuer/pafi-backend instead.\",\n );\n}\n\n/**\n * @deprecated v0.7.1 — see file comment.\n *\n * Set the application-wide paymaster config. Safe to call multiple\n * times (later calls override earlier). Throws if required fields\n * are missing.\n */\nexport function setPaymasterConfig(config: PaymasterConfig): void {\n warnDeprecated(\"setPaymasterConfig\");\n if (!config.pafiBackendUrl) {\n throw new Error(\"setPaymasterConfig: pafiBackendUrl is required\");\n }\n if (!config.issuerId) {\n throw new Error(\"setPaymasterConfig: issuerId is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"setPaymasterConfig: apiKey is required\");\n }\n if (!config.feeRecipient) {\n throw new Error(\"setPaymasterConfig: feeRecipient is required\");\n }\n _config = { ...config };\n}\n\n/**\n * @deprecated v0.7.1 — see file comment.\n */\nexport function getPaymasterConfig(): PaymasterConfig {\n warnDeprecated(\"getPaymasterConfig\");\n if (!_config) {\n throw new Error(\n \"PaymasterConfig not initialized — call setPaymasterConfig() at application boot before invoking any batch builder\",\n );\n }\n return _config;\n}\n\n/** Test helper — clear the singleton. */\nexport function _resetPaymasterConfigForTests(): void {\n _config = null;\n}\n\n/** Check whether paymaster config has been initialized. */\nexport function isPaymasterConfigured(): boolean {\n return _config !== null;\n}\n","import type { Address, PublicClient } from \"viem\";\n\n/**\n * Submission path chosen by `checkEthAndBranch`.\n * - `normal`: initiator has enough ETH; submit via `walletClient.writeContract`\n * or a plain `eth_sendRawTransaction`. No paymaster round-trip.\n * - `paymaster`: initiator doesn't have enough ETH; wrap the batch as a\n * UserOperation and route through PAFI Backend → PAFI sponsor-relayer\n * → Bundler.\n */\nexport type SubmissionPath = \"normal\" | \"paymaster\";\n\nexport interface CheckEthAndBranchParams {\n /** viem PublicClient bound to the target chain. */\n client: PublicClient;\n /** The address whose ETH balance we check. */\n initiator: Address;\n /** Estimated gas cost in wei for the upcoming tx. */\n estimatedGasWei: bigint;\n /**\n * Optional safety margin multiplier (basis points). Defaults to\n * 11_000 (110%) — the initiator needs 10% above the estimate to\n * qualify for the normal path. Prevents edge cases where gas price\n * spikes between estimation and submission cause a \"has enough\"\n * decision to fail at broadcast time.\n */\n marginBps?: number;\n}\n\nconst DEFAULT_MARGIN_BPS = 11_000;\n\n/**\n * Step 3 of the Generalized Flow ([SPONSORED_PATH_FLOW.md §2]):\n * choose between the normal path (initiator pays ETH directly) and the\n * paymaster path (bundler + PAFI sponsor-relayer).\n *\n * Intentionally synchronous in spirit — the only network call is\n * `getBalance`. Callers can parallelize it with other reads.\n */\nexport async function checkEthAndBranch(\n params: CheckEthAndBranchParams,\n): Promise<SubmissionPath> {\n const marginBps = params.marginBps ?? DEFAULT_MARGIN_BPS;\n const required =\n (params.estimatedGasWei * BigInt(marginBps)) / 10_000n;\n\n const balance = await params.client.getBalance({\n address: params.initiator,\n });\n\n return balance >= required ? \"normal\" : \"paymaster\";\n}\n","import type { Address, Hex, PublicClient } from \"viem\";\n\n/**\n * EIP-7702 delegation designator prefix: 0xef0100 + 20-byte implementation address.\n *\n * When an EOA has been delegated via EIP-7702, `eth_getCode` returns bytecode\n * that starts with this magic prefix followed by the 20-byte address of the\n * implementation contract (BatchExecutor).\n *\n * References: EIP-7702 §4.2 — \"delegation designator\"\n */\nconst EIP7702_MAGIC = \"0xef0100\" as const;\n\n/**\n * Parse the implementation address out of an EIP-7702 delegation designator.\n *\n * Returns `null` when:\n * - `code` is undefined / empty / `\"0x\"` (plain EOA, no code)\n * - `code` does not contain the EIP-7702 magic prefix (regular contract)\n *\n * @param code - bytecode returned by `eth_getCode` / `client.getCode()`\n * @returns the 20-byte implementation address (checksummed), or `null`\n *\n * @example\n * const code = await client.getCode({ address });\n * const impl = parseEip7702DelegatedAddress(code);\n * // null → not delegated\n * // '0x7702cb554e6bFb442cb743A7dF23154544a7176C' → delegated to BatchExecutor\n */\nexport function parseEip7702DelegatedAddress(\n code: Hex | string | null | undefined,\n): Address | null {\n if (!code || code === \"0x\" || code === \"0x0\") return null;\n const normalized = code.toLowerCase();\n const magic = EIP7702_MAGIC.toLowerCase();\n // Strict prefix + exact-length check per EIP-7702 §4.2. Bytecode of\n // a delegated EOA is exactly 23 bytes (`0xef0100` || 20-byte impl)\n // → 40 hex chars AFTER the magic prefix. Substring search would\n // false-positive on regular contract bytecode containing `ef0100`\n // mid-stream.\n if (!normalized.startsWith(magic)) return null;\n if (normalized.length !== magic.length + 40) return null;\n return `0x${normalized.slice(magic.length)}` as Address;\n}\n\n/**\n * Read the EIP-7702 delegation status of an EOA from the chain.\n *\n * @param client - viem PublicClient (any provider — only `eth_getCode` is called)\n * @param address - EOA address to inspect\n * @returns the implementation address the EOA is delegated to, or `null`\n *\n * @example\n * const impl = await checkDelegation(publicClient, userAddress);\n * if (impl === null) {\n * // show \"Setup Wallet\" button\n * } else {\n * // EOA already delegated; safe to send UserOps\n * }\n */\nexport async function checkDelegation(\n client: PublicClient,\n address: Address,\n): Promise<Address | null> {\n const code = await client.getCode({ address });\n return parseEip7702DelegatedAddress(code);\n}\n\n/**\n * Return `true` when the EOA at `address` is currently delegated to `target`.\n *\n * Useful for asserting that the delegation points specifically at the expected\n * BatchExecutor rather than some other implementation (e.g. old deployment).\n *\n * @example\n * import { BATCH_EXECUTOR_ADDRESS_BASE_MAINNET } from '@pafi-dev/core';\n * const ok = await isDelegatedTo(client, userAddress, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET);\n */\nexport async function isDelegatedTo(\n client: PublicClient,\n address: Address,\n target: Address,\n): Promise<boolean> {\n const impl = await checkDelegation(client, address);\n if (!impl) return false;\n return impl.toLowerCase() === target.toLowerCase();\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type { PartialUserOperation } from \"../userop/types\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport { ENTRY_POINT_V08 } from \"../constants\";\n\n/**\n * Parameters for building a delegation-only UserOperation.\n *\n * This UserOp carries no calldata — its sole purpose is to anchor the\n * EIP-7702 authorization (signed externally via `signAuthorization`) into\n * a sponsored transaction so the user doesn't need native ETH to delegate.\n */\nexport interface BuildDelegationUserOpParams {\n /** User EOA to delegate. */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint. Pass 0n on first ever op. */\n aaNonce: bigint;\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build the minimal `PartialUserOperation` used to sponsor the one-time\n * EIP-7702 delegation.\n *\n * The caller must:\n * 1. Sign the EIP-7702 authorization via `signAuthorization()` (Privy hook).\n * 2. Pass the authorization as `authorization` alongside `calls` (or alone)\n * to `smartClient.sendTransaction()`.\n *\n * The permissionless SDK + Pimlico bundler handle the rest: they detect the\n * `authorization` field and submit an EIP-7702 type-4 transaction that sets\n * the EOA's bytecode to `0xef0100<batchExecutorAddress>`.\n *\n * This builder is a convenience wrapper — in practice you can also pass\n * `{ to: userAddress, value: 0n, data: '0x', authorization }` directly to\n * `smartClient.sendTransaction()` without calling this function at all.\n * Use it when you need a `PartialUserOperation` struct for inspection or\n * custom paymaster flows.\n *\n * @example\n * // Typical flow — no need to call this builder directly:\n * const nonce = await publicClient.getTransactionCount({ address, blockTag: 'pending' });\n * const authorization = await signAuthorization({ contractAddress: BATCH_EXECUTOR, chainId: 8453, nonce });\n * const txHash = await smartClient.sendTransaction({\n * to: address,\n * value: 0n,\n * data: '0x',\n * authorization,\n * paymasterContext: { sponsorshipPolicyId },\n * });\n */\nexport function buildDelegationUserOp(\n params: BuildDelegationUserOpParams,\n): PartialUserOperation {\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations: [\n {\n // Self-call with no data — triggers EIP-7702 delegation without\n // executing any inner logic. The BatchExecutor.execute([]) call with\n // an empty array would revert, so we target the EOA itself (which\n // forwards to BatchExecutor that then no-ops on empty input).\n target: params.userAddress,\n value: 0n,\n data: \"0x\",\n },\n ],\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 50_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n\n/**\n * Fetch the AA nonce for a user EOA from the EntryPoint v0.7.\n *\n * Convenience helper so callers don't need to import the EntryPoint ABI\n * themselves when building the delegation UserOp.\n *\n * @param client - viem PublicClient\n * @param userAddress - EOA to query\n * @returns bigint nonce (0n on first-ever UserOp)\n */\nexport async function getAaNonce(\n client: PublicClient,\n userAddress: Address,\n): Promise<bigint> {\n const NONCE_ABI = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n return client.readContract({\n address: ENTRY_POINT_V08,\n abi: NONCE_ABI,\n functionName: \"getNonce\",\n args: [userAddress, 0n],\n });\n}\n","import { concat, keccak256, toRlp, type Address, type Hex } from \"viem\";\n\n/**\n * EIP-7702 authorization tuple hash.\n *\n * keccak256(0x05 || rlp([chain_id, address, nonce]))\n *\n * The user signs this hash with a **raw secp256k1 sign** (no EIP-191 prefix).\n * On mobile, pass the result to the wallet's raw signing primitive.\n *\n * The resulting 65-byte signature is sent to `POST /delegate/submit` as `authSig`.\n *\n * Reference: EIP-7702 §3 — Authorization tuple\n */\nexport function computeAuthorizationHash(\n chainId: number,\n address: Address,\n nonce: bigint,\n): Hex {\n const rlpEncoded = toRlp([\n toMinimalHex(BigInt(chainId)),\n address,\n toMinimalHex(nonce),\n ]);\n return keccak256(concat([\"0x05\", rlpEncoded]));\n}\n\n/**\n * Check whether an EOA code string carries an EIP-7702 delegation to `target`.\n *\n * Sync alternative to `isDelegatedTo()` for callers that already have the\n * code from a prior `eth_getCode` call and don't want another RPC round-trip.\n *\n * Delegation designator format: 0xef0100 (3 bytes) || address (20 bytes)\n */\nexport function isDelegatedToTarget(\n code: string | null | undefined,\n target: Address,\n): boolean {\n if (!code || code === \"0x\") return false;\n const expected = `0xef0100${target.slice(2).toLowerCase()}`;\n return code.toLowerCase() === expected;\n}\n\n/** Minimal-length big-endian hex for RLP integer encoding (no leading zeros). */\nfunction toMinimalHex(n: bigint): Hex {\n if (n === 0n) return \"0x\";\n const hex = n.toString(16);\n return `0x${hex.length % 2 === 0 ? hex : \"0\" + hex}` as Hex;\n}\n","import type { Address, Hex } from \"viem\";\n\n/**\n * EIP-7702 authorization tuple in the JSON-RPC wire format that bundlers\n * (Pimlico, Stackup, etc.) accept on `eth_sendUserOperation`. All\n * numeric fields are 0x-prefixed hex strings.\n *\n * Constructed from the user's secp256k1 signature over\n * `keccak256(0x05 || rlp([chainId, address, nonce]))` — see\n * `computeAuthorizationHash`.\n */\nexport interface Eip7702AuthorizationJsonRpc {\n chainId: Hex;\n address: Address;\n nonce: Hex;\n r: Hex;\n s: Hex;\n yParity: Hex;\n}\n\n/**\n * Split a serialized 65-byte ECDSA signature (`r || s || v`) into the\n * `{ r, s, yParity }` triple required by EIP-7702 authorization tuples\n * and EIP-1559+ transactions.\n *\n * Accepts the legacy `v ∈ {27, 28}` form and converts to `yParity ∈ {0, 1}`\n * automatically. Already-normalized `v ∈ {0, 1}` passes through unchanged.\n *\n * @throws when the signature is not 65 bytes (130 hex chars).\n */\nexport function splitAuthorizationSig(authSig: Hex | string): {\n r: Hex;\n s: Hex;\n yParity: 0 | 1;\n} {\n const raw = authSig.startsWith(\"0x\")\n ? authSig.slice(2)\n : authSig;\n if (raw.length !== 130) {\n throw new Error(\n `splitAuthorizationSig: expected 65-byte signature (130 hex chars), got ${raw.length}`,\n );\n }\n const r = `0x${raw.slice(0, 64)}` as Hex;\n const s = `0x${raw.slice(64, 128)}` as Hex;\n const v = parseInt(raw.slice(128, 130), 16);\n const yParity: 0 | 1 = v === 27 ? 0 : v === 28 ? 1 : (v as 0 | 1);\n if (yParity !== 0 && yParity !== 1) {\n throw new Error(\n `splitAuthorizationSig: invalid recovery byte ${v} (expected 0/1/27/28)`,\n );\n }\n return { r, s, yParity };\n}\n\n/**\n * Build the JSON-RPC EIP-7702 authorization tuple from raw fields and a\n * 65-byte secp256k1 signature.\n *\n * The `authSig` is the user's signature over `computeAuthorizationHash(\n * chainId, address, nonce )` — typically obtained via\n * `wallet.signAuthorization(...)` on the client.\n */\nexport function buildEip7702Authorization(params: {\n chainId: number;\n address: Address;\n nonce: bigint;\n authSig: Hex | string;\n}): Eip7702AuthorizationJsonRpc {\n const { r, s, yParity } = splitAuthorizationSig(params.authSig);\n return {\n chainId: `0x${params.chainId.toString(16)}` as Hex,\n address: params.address,\n nonce: `0x${params.nonce.toString(16)}` as Hex,\n r,\n s,\n yParity: `0x${yParity}` as Hex,\n };\n}\n","import type { Address } from \"viem\";\n\n/**\n * Per-chain deployed contract addresses — v1.6 flow.\n *\n * ## Status (2026-05-07)\n *\n * Base mainnet (8453): v1.6 redeploy. PAFIHook removed entirely — fee on\n * mint now happens via `MintFeeWrapper` (single global instance, multi-PT).\n * `pafiHook` field kept as placeholder for back-compat with consumers that\n * still reference it; set to a deterministic dead address to make misuse\n * obvious.\n *\n * Base Sepolia (84532): entire row is placeholder — not in active use.\n *\n * ## What lives where\n *\n * pointToken — DEAD legacy field (per-issuer, not chain-level).\n * Each issuer's clone is configured via env or\n * resolved from PointTokenFactory at runtime. Set\n * to a deterministic dead address so misuse fails\n * loudly. Will be removed when downstream consumers\n * stop referencing it.\n * batchExecutor — EIP-7702 delegation target (Pimlico Simple7702Account)\n * usdt — MockERC20 used by Uniswap pools\n * issuerRegistry — registry of all issuers on this chain\n * mintingOracle — per-token mint cap enforcer (v1.6: per-token, not per-issuer)\n * mintFeeWrapper — v1.6 mint-time fee splitter (single global instance)\n * pafiHook — DEAD; v1.5 V4 swap fee removed in v1.6. Kept for ABI compat.\n *\n * PointTokenFactory + PointToken implementation addresses live in\n * separate exports below — they're only needed at provisioning /\n * observability time, not in the hot mint/burn path, so excluded from\n * the per-chain bundle.\n */\nexport interface ContractAddresses {\n pointToken: Address;\n batchExecutor: Address;\n usdt: Address;\n issuerRegistry: Address;\n mintingOracle: Address;\n /**\n * v1.6 — single-instance MintFeeWrapper that skims a fee on every\n * sig-gated mint and distributes across the registered recipient\n * list for the target PointToken. Issuers route mints through this\n * by passing `mintFeeWrapperAddress` to `prepareMint`.\n */\n mintFeeWrapper: Address;\n /**\n * @deprecated v1.5 PAFIHook (10% PT→USDT swap fee) was removed in\n * v1.6. Field kept as a dead placeholder so older consumers don't\n * crash on missing-property errors; do not use for new code.\n */\n pafiHook: Address;\n /** Chainlink ETH/USD price feed — used by FeeManager to convert gas cost to USDT. */\n chainlinkEthUsd: Address;\n /**\n * Orderly perp-deposit Relay — holds an ETH reserve to cover the\n * LayerZero msg.value, charges a USDC token-fee reimbursement.\n * Lets perp deposits ride the ERC-4337 sponsored gas path without\n * the user holding ETH for msg.value.\n */\n orderlyRelay: Address;\n /**\n * PAFI fee recipient — receives PT gas-reimbursement transfers from\n * the user on the sponsored path of every scenario (mint, burn,\n * swap, perp deposit). This is PAFI-controlled, NOT issuer-controlled,\n * because PAFI pays the ERC-4337 gas via the paymaster — issuers\n * shouldn't be able to redirect this fee to themselves.\n */\n pafiFeeRecipient: Address;\n /** Uniswap V4 UniversalRouter — swap entry point for the swap handler. */\n universalRouter: Address;\n}\n\nconst PLACEHOLDER_DEAD = (suffix: string): Address =>\n `0x000000000000000000000000000000000000${suffix.toLowerCase().padStart(4, \"0\")}` as Address;\n\nexport const CONTRACT_ADDRESSES: Record<number, ContractAddresses> = {\n // Base mainnet — v1.6 redeploy (2026-05-07)\n // registry: IssuerRegistry 0xAB1d1e117c41636f30bb10194Fe6B774B6Da9E01\n // factory: PointTokenFactory 0xA08274458b43E7D6F4ff61ddFe8A9852c6531085\n // oracle: MintingOracle 0x2f4cf8C5F8b41efC970c5b46a5d905CeA1f871a0\n // tokenImpl: PointToken (impl) 0xc41c3F8A0380c7760Ee1209d6d19C4b81dE994e4\n // mintFeeWrapper: MintFeeWrapper 0xD324EE2e3220B23d1b1BfbB85f5bC1EF2E917B93\n // mockUsdt: MockERC20 0x3F7e71B150e97316Bb9f363A32c19CcD36ac2382\n // batchExecutor: Pimlico Simple7702 0xe6Cae83BdE06E4c305530e199D7217f42808555B (unchanged from v1.5)\n //\n // pointToken: PER-ISSUER, not chain-level. Each issuer deploys their\n // own clone via PointTokenFactory.createToken() and tracks the address\n // separately (env var, DB, or factory readout). This field is a\n // historical leftover from v1.4 single-issuer days and has no SDK\n // consumer — kept as dead-zero so any code that mistakenly reads it\n // fails loudly instead of silently routing to a stale token.\n // Known clones (informational, NOT to be used as a default):\n // gg56 (Test Point / TPT) — 0x855c2046AD49AcF9B3B32557176FfCB1a1A38A22\n 8453: {\n pointToken: PLACEHOLDER_DEAD(\"dead\"),\n batchExecutor: \"0xe6Cae83BdE06E4c305530e199D7217f42808555B\",\n usdt: \"0x3F7e71B150e97316Bb9f363A32c19CcD36ac2382\",\n issuerRegistry: \"0xAB1d1e117c41636f30bb10194Fe6B774B6Da9E01\",\n mintingOracle: \"0x2f4cf8C5F8b41efC970c5b46a5d905CeA1f871a0\",\n mintFeeWrapper: \"0xD324EE2e3220B23d1b1BfbB85f5bC1EF2E917B93\",\n pafiHook: PLACEHOLDER_DEAD(\"dead\"),\n chainlinkEthUsd: \"0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70\",\n orderlyRelay: \"0xDA082DAce1522c185aeB5A713FcA6fa6B6E99e7f\",\n pafiFeeRecipient: \"0xa3F71eadEd101513a0151007590020dCFD7C495e\",\n universalRouter: \"0x6fF5693b99212Da76ad316178A184AB56D299b43\",\n },\n // Base Sepolia — not in active use; placeholders kept so the map\n // compiles for tooling that enumerates chains.\n 84532: {\n pointToken: PLACEHOLDER_DEAD(\"dead\"),\n batchExecutor: PLACEHOLDER_DEAD(\"de01\"),\n usdt: PLACEHOLDER_DEAD(\"dead\"),\n issuerRegistry: PLACEHOLDER_DEAD(\"dead\"),\n mintingOracle: PLACEHOLDER_DEAD(\"dead\"),\n mintFeeWrapper: PLACEHOLDER_DEAD(\"dead\"),\n pafiHook: PLACEHOLDER_DEAD(\"dead\"),\n chainlinkEthUsd: PLACEHOLDER_DEAD(\"de02\"),\n orderlyRelay: PLACEHOLDER_DEAD(\"de03\"),\n pafiFeeRecipient: PLACEHOLDER_DEAD(\"de04\"),\n universalRouter: PLACEHOLDER_DEAD(\"de05\"),\n },\n};\n\n/**\n * PointTokenFactory address — separate from `ContractAddresses` because\n * it's only used at provisioning time (issuer onboard + token creation),\n * not in the hot mint/burn path.\n */\nexport const POINT_TOKEN_FACTORY_ADDRESSES: Record<number, Address> = {\n 8453: \"0xA08274458b43E7D6F4ff61ddFe8A9852c6531085\",\n 84532: PLACEHOLDER_DEAD(\"dead\"),\n};\n\n/**\n * PointToken implementation address — the EIP-1167 clone target used\n * by PointTokenFactory. Exposed for observability / proxy verification;\n * consumers should never call this directly.\n */\nexport const POINT_TOKEN_IMPL_ADDRESSES: Record<number, Address> = {\n 8453: \"0xc41c3F8A0380c7760Ee1209d6d19C4b81dE994e4\",\n 84532: PLACEHOLDER_DEAD(\"dead\"),\n};\n\n/**\n * Lookup helper — throws if the chain isn't in the map so callers fail\n * loudly on misconfiguration instead of silently using `undefined`.\n */\nexport function getContractAddresses(chainId: number): ContractAddresses {\n const addrs = CONTRACT_ADDRESSES[chainId];\n if (!addrs) {\n throw new Error(\n `getContractAddresses: no addresses for chainId ${chainId}. ` +\n `Supported: ${Object.keys(CONTRACT_ADDRESSES).join(\", \")}`,\n );\n }\n return addrs;\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n WalletClient,\n TransactionReceipt,\n} from \"viem\";\nimport { getContractAddresses } from \"../contracts/real/addresses\";\nimport { parseEip7702DelegatedAddress } from \"./checkDelegation\";\n\n/**\n * Privy-style EIP-7702 authorization signer. Matches the shape returned\n * by `useSign7702Authorization()` from `@privy-io/react-auth` /\n * `@privy-io/expo`. Pass it via `params.signAuthorization` and the\n * helper takes care of the rest.\n *\n * The signer MUST be the user's Privy embedded wallet — external\n * wallets (MetaMask, WalletConnect, …) cannot produce raw secp256k1\n * EIP-7702 authorizations.\n */\nexport type SignAuthorizationFn = (args: {\n contractAddress: Address;\n chainId: number;\n nonce: number;\n}) => Promise<{\n contractAddress?: Address;\n address?: Address;\n chainId: number;\n nonce: number;\n r: Hex | string;\n s: Hex | string;\n // Privy returns `v` as bigint, viem types it as bigint, some SDKs as\n // string/number. Accept all and ignore — we use yParity directly.\n v?: bigint | string | number;\n // Privy returns 0 | 1 (number); some SDKs return '0x0' / '0x1' (hex\n // string). Accept both shapes — `delegateDirect` normalizes\n // internally.\n yParity: number | string;\n}>;\n\n/**\n * Authorization tuple in the shape `walletClient.sendTransaction`\n * expects on its `authorizationList` field. Mirrors viem's\n * `SignedAuthorization` so callers can also build it manually.\n */\nexport interface SignedAuthorization {\n contractAddress: Address;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: 0 | 1;\n}\n\nexport interface DelegateDirectParams {\n /** User EOA — must equal `walletClient.account.address`. */\n userAddress: Address;\n chainId: number;\n /** viem PublicClient — used for `getCode` + `getTransactionCount`. */\n publicClient: PublicClient;\n /** viem WalletClient (or any sender that exposes `sendTransaction`). */\n walletClient: WalletClient;\n /**\n * Privy hook that produces the EIP-7702 authorization signature.\n * Pass `useSign7702Authorization().signAuthorization` directly.\n */\n signAuthorization: SignAuthorizationFn;\n /**\n * Override the impl the EOA delegates to. Defaults to\n * `getContractAddresses(chainId).batchExecutor` (Pimlico\n * Simple7702Account on Base mainnet — the canonical PAFI delegate\n * target).\n */\n contractAddress?: Address;\n /**\n * When the user already has a 7702 delegation pointing at the\n * expected impl, skip the tx and return early. Default `true`.\n * Set `false` to force re-delegate even if status check passes.\n */\n skipIfAlreadyDelegated?: boolean;\n /**\n * Wait for the transaction receipt before returning. Default\n * `true` — caller usually wants to know \"delegation completed\"\n * before proceeding to claim/redeem flows.\n */\n waitForReceipt?: boolean;\n /** Optional onWarning hook for non-fatal warnings (logger surface). */\n onWarning?: (msg: string) => void;\n}\n\nexport interface DelegateDirectResult {\n /** `'sent'` when a tx was broadcast; `'already-delegated'` when skipped. */\n status: \"sent\" | \"already-delegated\";\n /** Transaction hash. `undefined` on `already-delegated`. */\n txHash?: Hex;\n /** Receipt — present when `waitForReceipt` AND status is `'sent'`. */\n receipt?: TransactionReceipt;\n /** EIP-7702 authorization tuple actually sent. */\n authorization: SignedAuthorization;\n /** Impl address user delegated to. */\n delegatedTo: Address;\n}\n\n/**\n * One-shot helper for the FE-direct EIP-7702 delegation path —\n * **no AA, no paymaster, no PAFI sponsor-relayer**. The user EOA\n * pays gas in ETH and broadcasts a single type-4 transaction with the\n * authorization attached.\n *\n * Use this when:\n * - The FE already has a Privy embedded wallet ready and the user\n * has a small ETH balance for gas (~$0.01–0.10 on Base).\n * - You don't want to depend on `permissionless` / Pimlico bundlers\n * / sponsor-relayer for the one-time delegation step.\n * - You're testing or running a self-hosted dev environment without\n * the full PAFI infra.\n *\n * Flow:\n * 1. Read on-chain code; short-circuit if already delegated to the\n * expected impl (`skipIfAlreadyDelegated`).\n * 2. Read EOA tx nonce (pending).\n * 3. Call `signAuthorization` (Privy hook) → r/s/yParity.\n * 4. Send EIP-7702 type-4 tx with `authorizationList: [auth]` and\n * `to: userAddress, data: '0x'` (no-op self-call; the work is\n * bundling the authorization).\n * 5. Wait for receipt (optional).\n *\n * Caller's `signAuthorization` MUST be wired to the user's Privy\n * embedded wallet — external wallets (MetaMask, …) do NOT support\n * raw secp256k1 EIP-7702 sign.\n *\n * @example\n * ```ts\n * import { useSign7702Authorization, useWallets } from \"@privy-io/react-auth\";\n * import { delegateDirect } from \"@pafi-dev/core\";\n * import { createWalletClient, custom } from \"viem\";\n * import { base } from \"viem/chains\";\n *\n * function DelegateButton() {\n * const { wallets } = useWallets();\n * const { signAuthorization } = useSign7702Authorization();\n * const wallet = wallets.find(w => w.walletClientType === \"privy\"); // embedded\n *\n * async function handleClick() {\n * const provider = await wallet.getEthereumProvider();\n * const walletClient = createWalletClient({\n * account: wallet.address,\n * chain: base,\n * transport: custom(provider),\n * });\n *\n * const result = await delegateDirect({\n * userAddress: wallet.address as `0x${string}`,\n * chainId: 8453,\n * publicClient,\n * walletClient,\n * signAuthorization,\n * });\n *\n * if (result.status === \"already-delegated\") {\n * console.log(\"Already delegated to\", result.delegatedTo);\n * } else {\n * console.log(\"Delegated! tx:\", result.txHash);\n * }\n * }\n * }\n * ```\n */\nexport async function delegateDirect(\n params: DelegateDirectParams,\n): Promise<DelegateDirectResult> {\n const target =\n params.contractAddress ??\n (getContractAddresses(params.chainId).batchExecutor as Address);\n\n // 1. Short-circuit if already delegated to the expected impl.\n if (params.skipIfAlreadyDelegated !== false) {\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const current = parseEip7702DelegatedAddress(code);\n if (current && current.toLowerCase() === target.toLowerCase()) {\n // Build a no-op authorization placeholder for the response —\n // we didn't actually sign one because we skipped.\n return {\n status: \"already-delegated\",\n delegatedTo: current,\n authorization: {\n contractAddress: target,\n chainId: params.chainId,\n nonce: 0,\n r: \"0x\" as Hex,\n s: \"0x\" as Hex,\n yParity: 0,\n },\n };\n }\n }\n\n // 2. Read EOA tx nonce (pending — covers any in-flight sends).\n const nonce = await params.publicClient.getTransactionCount({\n address: params.userAddress,\n blockTag: \"pending\",\n });\n\n // 3. Sign authorization via Privy hook.\n const raw = await params.signAuthorization({\n contractAddress: target,\n chainId: params.chainId,\n nonce,\n });\n\n // Normalize to viem's SignedAuthorization shape. Privy returns\n // `yParity` as either `0/1` (number) or `'0x0'/'0x1'` (hex string)\n // depending on SDK version — handle both.\n const yParityRaw = raw.yParity;\n const yParityNum =\n typeof yParityRaw === \"number\"\n ? yParityRaw\n : String(yParityRaw) === \"1\" || String(yParityRaw) === \"0x1\"\n ? 1\n : 0;\n const yParity: 0 | 1 = yParityNum === 1 ? 1 : 0;\n\n const authorization: SignedAuthorization = {\n contractAddress: target,\n chainId: params.chainId,\n nonce,\n r: normalizeHex32(raw.r),\n s: normalizeHex32(raw.s),\n yParity,\n };\n\n // 4. Send EIP-7702 type-4 tx. viem auto-encodes when\n // `authorizationList` is supplied. Self-call (data: '0x') is a\n // no-op — the work is the authorization itself.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"delegateDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n\n // Cast to bypass viem's strict generic chain inference; runtime\n // shape matches `EIP7702Transaction` regardless of declared chain.\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: \"0x\" as Hex,\n authorizationList: [authorization],\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n const waitForReceipt = params.waitForReceipt !== false;\n let receipt: TransactionReceipt | undefined;\n if (waitForReceipt) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `delegateDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n status: \"sent\",\n txHash,\n receipt,\n authorization,\n delegatedTo: target,\n };\n}\n\n/**\n * Normalize a hex r/s component to exactly `0x` + 64 hex chars\n * (32 bytes). Privy occasionally returns less-than-32-byte values\n * when the leading byte is zero; viem's `authorizationList` expects\n * full-width hex.\n */\nfunction normalizeHex32(value: Hex | string | undefined): Hex {\n if (!value) return \"0x\" as Hex;\n const stripped = value.replace(/^0x/i, \"\");\n return (\"0x\" + stripped.padStart(64, \"0\")) as Hex;\n}\n","import { http } from \"viem\";\nimport type { HttpTransport } from \"viem\";\n\n/**\n * Parameters for `createPafiProxyTransport`.\n */\nexport interface PafiProxyTransportParams {\n /**\n * Full URL of the PAFI sponsor-relayer Pimlico proxy endpoint.\n * @example \"https://sponsor-relayer.pacificfinance.org/pimlico\"\n * @example \"http://localhost:4000/pimlico\"\n */\n proxyUrl: string;\n\n /**\n * Called on every request to get the current Privy identity token.\n * Use a getter (or a ref's `.current`) so the transport always sends\n * the latest token without needing to be rebuilt when it rotates.\n *\n * @example () => identityTokenRef.current\n * @example () => privyHook.identityToken\n */\n getIdentityToken: () => string | null | undefined;\n\n /**\n * Issuer ID sent as `X-Issuer-Id` header.\n * sponsor-relayer uses this to look up per-issuer rate limits and policy.\n * Obtain from PAFI team during onboarding.\n */\n issuerId: string;\n}\n\n/**\n * Create a viem `HttpTransport` that proxies all Pimlico JSON-RPC calls\n * through the PAFI sponsor-relayer (`POST /pimlico`).\n *\n * The transport:\n * - Sets `Authorization: Bearer <identityToken>` on every request\n * - Sets `X-Issuer-Id: <issuerId>` on every request\n * - Reads the identity token lazily via `getIdentityToken()` so it is\n * always fresh without rebuilding the SmartAccountClient on each rotation\n *\n * Pass the returned transport to both `createPimlicoClient` and\n * `createSmartAccountClient` so ALL Pimlico RPC calls (paymaster + bundler)\n * go through the proxy with auth headers attached.\n *\n * @example\n * ```ts\n * import { createPafiProxyTransport, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET } from '@pafi-dev/core';\n * import { createSmartAccountClient } from 'permissionless';\n * import { createPimlicoClient } from 'permissionless/clients/pimlico';\n * import { useIdentityToken } from '@privy-io/react-auth';\n *\n * const { identityToken } = useIdentityToken();\n * const identityTokenRef = useRef<string | null>(null);\n * useEffect(() => { identityTokenRef.current = identityToken; }, [identityToken]);\n *\n * const proxyTransport = createPafiProxyTransport({\n * proxyUrl: process.env.NEXT_PUBLIC_PIMLICO_PROXY_URL!,\n * getIdentityToken: () => identityTokenRef.current,\n * issuerId: process.env.NEXT_PUBLIC_ISSUER_ID!,\n * });\n *\n * const pimlicoClient = createPimlicoClient({ chain: base, transport: proxyTransport });\n * const smartClient = createSmartAccountClient({\n * client: publicClient,\n * chain: base,\n * account,\n * paymaster: pimlicoClient,\n * bundlerTransport: proxyTransport,\n * });\n * ```\n */\nexport function createPafiProxyTransport(\n params: PafiProxyTransportParams,\n): HttpTransport {\n const { proxyUrl, getIdentityToken, issuerId } = params;\n\n return http(proxyUrl, {\n fetchOptions: {},\n // fetchFn intercepts every fetch call the viem http transport makes,\n // injecting the auth headers before the request leaves the browser.\n fetchFn: (input: RequestInfo | URL, init?: RequestInit) => {\n const headers = new Headers(init?.headers);\n const token = getIdentityToken();\n if (token) {\n headers.set(\"authorization\", `Bearer ${token}`);\n }\n headers.set(\"x-issuer-id\", issuerId);\n return fetch(input, { ...init, headers });\n },\n });\n}\n","import type { Hex } from \"viem\";\n\n/**\n * Minimal interface for any smart-account client capable of submitting\n * transactions. Deliberately duck-typed so the SDK does not need a hard\n * dependency on permissionless — any client with this shape works.\n */\nexport interface SmartAccountSender {\n sendTransaction(params: Record<string, unknown>): Promise<Hex>;\n}\n\n/**\n * HTTP statuses returned by the PAFI sponsor-relayer / Pimlico proxy\n * that mean \"paymaster declined sponsorship, retrying without it is a\n * sensible UX.\" 401/403/429/503 only — NOT 4xx/5xx generally (a\n * generic 500 could be anything).\n */\nconst PAYMASTER_HTTP_STATUSES = new Set([401, 403, 429, 503]);\n\n/**\n * Word-boundary patterns matching paymaster-layer failures. Use\n * regex (not substring) so arbitrary error text containing the\n * digits \"503\" / \"403\" / etc. (transit IDs, addresses, log lines)\n * doesn't false-positive.\n *\n * - `\\bAA3[1-4]\\b` — ERC-4337 paymaster validation codes (AA31..AA34)\n * - `\\bpaymaster\\b` — Pimlico / sponsor-relayer plain text\n * - `\\bsponsorship\\b` — Pimlico declines\n * - `\\bpm_\\w+` — JSON-RPC method (pm_getPaymasterData, pm_sponsorUserOperation)\n * - `\\brate ?limit\\b` — generic rate limiter\n * - `\\bunauthorized\\b` — auth failure (also caught by HTTP status check below)\n */\nconst PAYMASTER_PATTERNS: RegExp[] = [\n /\\bAA3[1-4]\\b/i,\n /\\bpaymaster\\b/i,\n /\\bsponsorship\\b/i,\n /\\bpm_\\w+/i,\n /\\brate ?limit\\b/i,\n /\\bunauthorized\\b/i,\n];\n\ninterface MaybeHttpError {\n status?: number;\n statusCode?: number;\n response?: { status?: number };\n cause?: { status?: number };\n message?: string;\n}\n\n/**\n * Returns true when `err` originates from the **paymaster layer** rather\n * than the contract or bundler layer. Covers:\n *\n * - ERC-4337 AA3x validation errors (AA31–AA34, word-boundary match)\n * - Pimlico sponsorship rejections (`pm_*` methods, \"sponsorship\" / \"paymaster\")\n * - PAFI proxy HTTP errors — checked via typed `status` / `statusCode`\n * field when present, NOT substring match\n * - Generic \"rate limit\" / \"unauthorized\" strings\n *\n * Use this to decide whether retrying without a paymaster makes sense.\n * Contract reverts (AA23, AA24, AA25) and bundler errors are NOT matched.\n */\nexport function isPaymasterError(err: unknown): boolean {\n if (err == null || typeof err !== \"object\") return false;\n const e = err as MaybeHttpError;\n\n // 1. Typed HTTP status check — strict integer match, no substring drift.\n const status =\n e.status ?? e.statusCode ?? e.response?.status ?? e.cause?.status;\n if (typeof status === \"number\" && PAYMASTER_HTTP_STATUSES.has(status)) {\n return true;\n }\n\n // 2. Word-boundary regex against the error message. Avoids false\n // positives from arbitrary strings containing the digits \"503\"\n // or substrings like \"403\" inside a hex address.\n const msg = e.message ?? String(err);\n return PAYMASTER_PATTERNS.some((re) => re.test(msg));\n}\n\nexport interface SendWithPaymasterFallbackParams {\n /** Smart-account client with paymaster configured — tried first. */\n primaryClient: SmartAccountSender;\n /**\n * Smart-account client without paymaster — used when `primaryClient`\n * throws a paymaster error. User pays gas from their ETH balance.\n * Pass `null` or `undefined` to disable fallback (error re-thrown as-is).\n */\n fallbackClient: SmartAccountSender | null | undefined;\n /** Transaction params forwarded verbatim to `sendTransaction`. */\n txParams: Record<string, unknown>;\n /**\n * Optional alternate `txParams` used **only on the fallback attempt**.\n * Lets callers strip operator-fee transfers from the calldata when the\n * paymaster refuses — there's no point charging a \"PAFI gas\n * reimbursement\" fee in PT/USDC if PAFI didn't actually sponsor the\n * gas. When omitted, the same `txParams` is reused for both attempts.\n */\n txParamsFallback?: Record<string, unknown>;\n /**\n * Called just before the fallback attempt so the caller can log or\n * update UI. Receives the error message from the failed primary attempt.\n */\n onFallback?: (errorMessage: string) => void;\n}\n\n/**\n * Submit a UserOp with paymaster sponsorship, falling back to user-paid gas\n * if the paymaster refuses.\n *\n * Flow:\n * 1. Call `primaryClient.sendTransaction(txParams)`.\n * 2. If it throws and `isPaymasterError` returns true, call `onFallback` then\n * retry with `fallbackClient` (no paymaster — user pays gas).\n * 3. All other errors (contract revert, bundler rejection, network) are\n * re-thrown immediately without a retry.\n *\n * @example\n * ```ts\n * import { sendWithPaymasterFallback } from '@pafi-dev/core';\n *\n * const txHash = await sendWithPaymasterFallback({\n * primaryClient: smartClientWithPaymaster,\n * fallbackClient: smartClientNoPaymaster,\n * txParams: { calls, paymasterContext: { sponsorshipPolicyId } },\n * onFallback: (msg) => addLog(`Paymaster refused (${msg}) — you will pay gas.`),\n * });\n * ```\n */\nexport async function sendWithPaymasterFallback(\n params: SendWithPaymasterFallbackParams,\n): Promise<Hex> {\n const { primaryClient, fallbackClient, txParams, txParamsFallback, onFallback } = params;\n try {\n return await primaryClient.sendTransaction(txParams);\n } catch (err) {\n if (isPaymasterError(err) && fallbackClient) {\n const msg = (err as any)?.message ?? String(err);\n onFallback?.(msg);\n return await fallbackClient.sendTransaction(txParamsFallback ?? txParams);\n }\n throw err;\n }\n}\n","import { parseAbi } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport { PAFI_SUBGRAPH_URL } from \"../subgraph/pools\";\nimport { getContractAddresses } from \"../contracts/real/addresses\";\nimport { OracleStaleError } from \"../errors\";\n\n/**\n * Operator-fee quoter — pure on-chain + subgraph reads, no issuer\n * backend involvement.\n *\n * Computes the PT amount the user must transfer to PAFI's fee\n * recipient to reimburse the ERC-4337 gas cost of a sponsored UserOp:\n *\n * nativeWei = gasUnits × gasPrice\n * premium = nativeWei × premiumBps / 10_000\n * feeInUsdt = premium × ethPriceUsd / 10^(18+8-6) // Chainlink\n * feeInPt = feeInUsdt × ptPerUsdt_18dec / 10^(18-6) // V4 pool spot\n *\n * Used by the SDK Direct path so callers don't need to hit any\n * issuer-specific endpoint to figure out the fee. The sponsor-relayer\n * `FeeValidatorService` runs the same quote server-side with a 5%\n * tolerance window — minor drift between client and server is\n * accepted.\n *\n * @example\n * ```ts\n * import { quoteOperatorFeePt } from \"@pafi-dev/core\";\n *\n * const fee = await quoteOperatorFeePt({\n * provider: publicClient,\n * chainId: 8453,\n * pointTokenAddress: POINT_TOKEN,\n * });\n *\n * await trading.handleSwap({\n * ...,\n * gasFeePt: fee,\n * feeRecipient: getContractAddresses(8453).pafiFeeRecipient,\n * });\n * ```\n */\n\nconst CHAINLINK_ABI = parseAbi([\n \"function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80)\",\n]);\n\n// Base ETH/USD heartbeat — feed updates hourly or on 0.5% deviation.\nconst CHAINLINK_MAX_AGE_S = 3_600n;\n\nconst POOL_PRICE_QUERY = `\n query GetPoolPrice($id: ID!) {\n pafiToken(id: $id) {\n pool {\n token0 { id }\n token1 { id }\n token0Price\n token1Price\n }\n }\n }\n`;\n\ninterface GraphQLPriceResponse {\n data?: {\n pafiToken: {\n pool: {\n token0: { id: string };\n token1: { id: string };\n token0Price: string;\n token1Price: string;\n } | null;\n } | null;\n };\n errors?: { message: string }[];\n}\n\n/**\n * Per-scenario gas budgets (callGasLimit + verificationGas + preVerify)\n * used by `quoteOperatorFee*`. Defaults are calibrated against the\n * actual UserOps the issuer + trading SDKs build:\n *\n * mint — `RelayService.prepareMint` callGasLimit 300k → 500k margin\n * burn — `RelayService.prepareBurn` 300k → 500k margin\n * swap — `buildSwapUserOp` callGasLimit 700k (UR.execute heavy)\n * perp-deposit — `buildPerpDepositViaRelay` 800k (LayerZero msg)\n * delegate — minimal no-op self-call, 200k margin\n *\n * Pass an explicit `gasUnits` to override.\n */\nexport type FeeScenario =\n | \"mint\"\n | \"burn\"\n | \"swap\"\n | \"perp-deposit\"\n | \"delegate\";\n\nexport const SCENARIO_GAS_UNITS: Record<FeeScenario, bigint> = {\n mint: 500_000n,\n burn: 500_000n,\n swap: 700_000n,\n \"perp-deposit\": 800_000n,\n delegate: 200_000n,\n};\n\nexport interface QuoteOperatorFeePtConfig {\n provider: PublicClient;\n chainId: number;\n pointTokenAddress: Address;\n /**\n * Scenario tag — picks default `gasUnits` from `SCENARIO_GAS_UNITS`.\n * Ignored when `gasUnits` is explicit. Default `\"mint\"` for back-\n * compat (matches the legacy 500_000 constant).\n */\n scenario?: FeeScenario;\n /**\n * ERC-4337 gas units the UserOp will consume on chain. Defaults to\n * `SCENARIO_GAS_UNITS[scenario]`, falling back to 500_000n. Pass a\n * tighter number when you have a Pimlico estimate to feed in.\n */\n gasUnits?: bigint;\n /**\n * Premium applied on top of raw gas cost in basis points. Default\n * 12_000 (= 1.2×, 20% buffer to cover oracle drift + paymaster\n * overhead). Same default the issuer SDK's `FeeManager` uses.\n */\n premiumBps?: number;\n /** Chainlink ETH/USD feed override. Defaults to chain's address. */\n chainlinkFeedAddress?: Address;\n /** Subgraph URL override. Defaults to `PAFI_SUBGRAPH_URL`. */\n subgraphUrl?: string;\n /** USDT token decimals. Default 6 (USDC/USDT on Base/Ethereum). */\n usdtDecimals?: number;\n /**\n * Opt-in fallback prices used when Chainlink / subgraph is\n * unavailable. Default `false` — throw `OracleStaleError`. Set\n * `true` AND configure `fallbackEthPriceUsd` / `fallbackPtPriceUsdt`\n * to absorb oracle outages instead of surfacing them.\n *\n * When fallback fires, callers SHOULD observe via `onFallback` so\n * production can flag the under-priced quote (e.g. show \"fee priced\n * against stale oracle\" banner in FE; alert on-call).\n */\n allowStaleFallback?: boolean;\n /** Fallback ETH price (USD) when Chainlink is unreachable. Only used when `allowStaleFallback: true`. Default 3000. */\n fallbackEthPriceUsd?: number;\n /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Only used when `allowStaleFallback: true`. Default 0.1. */\n fallbackPtPriceUsdt?: number;\n /**\n * Observability hook fired when the quoter falls back to stale\n * prices. Callers SHOULD wire this to their alert pipeline (Sentry,\n * Datadog, PagerDuty) so under-priced quotes don't go unnoticed.\n * When omitted, falls back to `console.warn` (kept for back-compat\n * but invisible in most prod log shippers).\n */\n onFallback?: (info: FallbackInfo) => void;\n fetchImpl?: typeof fetch;\n}\n\n/**\n * Detail surfaced via `onFallback` when the quoter substitutes a\n * stale-fallback price. Callers can format this into a UI banner or\n * log line.\n */\nexport interface FallbackInfo {\n /** Which oracle failed. */\n source: \"chainlink\" | \"subgraph\";\n /** Underlying reason from the oracle call (e.g. RPC error message). */\n reason: string;\n /** The fallback value that was used (in source-native units). */\n fallbackValue: number;\n}\n\n/**\n * Subset of `QuoteOperatorFeePtConfig` that doesn't need the V4 pool\n * step — used by `quoteOperatorFeeUsdt` (FE cashout-preview / `/gas-fee`\n * replacement). No `pointTokenAddress`, no `subgraphUrl`, no PT-side\n * fallback.\n */\nexport interface QuoteOperatorFeeUsdtConfig {\n provider: PublicClient;\n chainId: number;\n /** See `QuoteOperatorFeePtConfig.scenario`. v0.7.4. */\n scenario?: FeeScenario;\n gasUnits?: bigint;\n premiumBps?: number;\n chainlinkFeedAddress?: Address;\n usdtDecimals?: number;\n /**\n * Opt-in fallback price when Chainlink is unavailable. Default\n * `false` — throw `OracleStaleError`.\n */\n allowStaleFallback?: boolean;\n fallbackEthPriceUsd?: number;\n /** See QuoteOperatorFeePtConfig.onFallback. */\n onFallback?: (info: FallbackInfo) => void;\n}\n\nconst DEFAULT_GAS_UNITS = 500_000n;\nconst DEFAULT_PREMIUM_BPS = 12_000;\nconst DEFAULT_USDT_DECIMALS = 6;\n\n/**\n * Operator fee quoted in USDT raw units (default 6 decimals). Returns\n * the same value the legacy `GET /gas-fee` endpoint produced —\n * `withPremium_wei × ethPrice / 10^(18 + 8 - usdtDecimals)`. Does NOT\n * convert to PT, so no V4 subgraph call needed; pure on-chain\n * Chainlink read + RPC `getGasPrice`.\n *\n * Use this on the FE for the cashout preview screen (or anywhere a\n * USDT-denominated estimate is wanted) instead of round-tripping the\n * issuer backend's `/gas-fee` endpoint.\n *\n * @example\n * ```ts\n * import { quoteOperatorFeeUsdt } from \"@pafi-dev/core\";\n * const gasFeeUsdt = await quoteOperatorFeeUsdt({\n * provider, chainId: 8453,\n * });\n * // gasFeeUsdt is a bigint in 6-decimal USDT raw units\n * ```\n */\nexport async function quoteOperatorFeeUsdt(\n config: QuoteOperatorFeeUsdtConfig,\n): Promise<bigint> {\n const {\n provider,\n chainId,\n scenario = \"mint\",\n gasUnits = SCENARIO_GAS_UNITS[scenario] ?? DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\n allowStaleFallback = false,\n fallbackEthPriceUsd = 3_000,\n } = config;\n\n const chainlinkFeedAddress =\n config.chainlinkFeedAddress ??\n getContractAddresses(chainId).chainlinkEthUsd;\n\n const gasPrice = await provider.getGasPrice();\n const nativeCost = gasPrice * gasUnits;\n const withPremium = (nativeCost * BigInt(premiumBps)) / 10_000n;\n\n const ethPrice8dec = await getEthPrice8dec(\n provider,\n chainlinkFeedAddress,\n allowStaleFallback ? fallbackEthPriceUsd : null,\n config.onFallback,\n );\n\n // feeUsdt_<usdtDec> = withPremium_wei × ethPrice_8dec / 10^(18 + 8 - usdtDec)\n const denomExp = 18 + 8 - usdtDecimals;\n return (withPremium * ethPrice8dec) / 10n ** BigInt(denomExp);\n}\n\nexport async function quoteOperatorFeePt(\n config: QuoteOperatorFeePtConfig,\n): Promise<bigint> {\n const {\n provider,\n chainId,\n pointTokenAddress,\n scenario = \"mint\",\n gasUnits = SCENARIO_GAS_UNITS[scenario] ?? DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n subgraphUrl = PAFI_SUBGRAPH_URL,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\n allowStaleFallback = false,\n fallbackEthPriceUsd = 3_000,\n fallbackPtPriceUsdt = 0.1,\n fetchImpl = globalThis.fetch,\n } = config;\n\n const chainlinkFeedAddress =\n config.chainlinkFeedAddress ??\n getContractAddresses(chainId).chainlinkEthUsd;\n\n const gasPrice = await provider.getGasPrice();\n const nativeCost = gasPrice * gasUnits;\n const withPremium = (nativeCost * BigInt(premiumBps)) / 10_000n;\n\n const [ethPrice8dec, ptPerUsdt18dec] = await Promise.all([\n getEthPrice8dec(\n provider,\n chainlinkFeedAddress,\n allowStaleFallback ? fallbackEthPriceUsd : null,\n config.onFallback,\n ),\n getPtPerUsdt18dec(\n fetchImpl,\n subgraphUrl,\n pointTokenAddress,\n allowStaleFallback ? fallbackPtPriceUsdt : null,\n config.onFallback,\n ),\n ]);\n\n // feeInUsdt_<usdtDec> = withPremium_wei × ethPrice_8dec / 10^(18+8-usdtDec)\n // feeInPt_18dec = feeInUsdt × ptPerUsdt_18dec / 10^(18-usdtDec)\n // combined = withPremium × ethPrice × ptPerUsdt / 10^(18+8-usdtDec + 18-usdtDec)\n // = / 10^(44 - 2·usdtDec)\n // For usdtDecimals=6: 10^(44-12) = 10^32. But ptPerUsdt is already 18-scaled\n // so we subtract another 18: 10^(32-18) = 10^14? No — let me redo cleanly.\n //\n // Working in fractional units to keep it readable:\n // eth_human = withPremium / 10^18\n // usdt_human = eth_human × ethPriceFloat\n // pt_human = usdt_human × ptPerUsdtFloat\n // pt_18dec = pt_human × 10^18\n //\n // Substituting bigint scales:\n // ethPrice_8dec = ethPriceFloat × 10^8\n // ptPerUsdt_18dec = ptPerUsdtFloat × 10^18 (PT raw per 1 *human* USDT)\n //\n // pt_18dec = (withPremium / 10^18) × (ethPrice_8dec / 10^8)\n // × (ptPerUsdt_18dec / 10^18) × 10^18\n // = withPremium × ethPrice_8dec × ptPerUsdt_18dec / 10^26\n return (withPremium * ethPrice8dec * ptPerUsdt18dec) / 10n ** 26n;\n}\n\n/**\n * Fetch ETH/USD from Chainlink. When the feed is unavailable or stale,\n * either:\n * - fallback is `null` → throw `OracleStaleError` (default, v0.7.1+).\n * - fallback is a number → return `Math.round(fallback * 1e8)` after\n * `console.warn`. Caller opted in via `allowStaleFallback: true`.\n */\nasync function getEthPrice8dec(\n provider: PublicClient,\n feed: Address,\n fallback: number | null,\n onFallback?: (info: FallbackInfo) => void,\n): Promise<bigint> {\n try {\n const result = await provider.readContract({\n address: feed,\n abi: CHAINLINK_ABI,\n functionName: \"latestRoundData\",\n });\n const answer = result[1];\n const updatedAt = result[3];\n\n if (answer <= 0n) throw new Error(\"Chainlink: non-positive price\");\n\n const ageS = BigInt(Math.floor(Date.now() / 1000)) - updatedAt;\n if (ageS > CHAINLINK_MAX_AGE_S) {\n throw new Error(`Chainlink: price stale by ${ageS}s`);\n }\n\n return answer;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n if (fallback === null) {\n throw new OracleStaleError(\"chainlink\", reason);\n }\n if (onFallback) {\n onFallback({ source: \"chainlink\", reason, fallbackValue: fallback });\n } else {\n // Back-compat: default to console.warn when caller hasn't wired\n // an observability hook. Production callers SHOULD pass\n // `onFallback` to surface the fallback in their alert pipeline.\n // eslint-disable-next-line no-console\n console.warn(\n \"[quoteOperatorFee] Chainlink unavailable, using opt-in fallback:\",\n reason,\n );\n }\n return BigInt(Math.round(fallback * 1e8));\n }\n}\n\n/**\n * Fetch PT/USDT price from PAFI subgraph. When subgraph is unavailable\n * either:\n * - `fallbackPtPriceUsdt` is `null` → throw `OracleStaleError`\n * (default, v0.7.1+).\n * - is a number → fall back to `1 / fallback` after `console.warn`.\n */\nasync function getPtPerUsdt18dec(\n fetchImpl: typeof fetch,\n subgraphUrl: string,\n pointTokenAddress: Address,\n fallbackPtPriceUsdt: number | null,\n onFallback?: (info: FallbackInfo) => void,\n): Promise<bigint> {\n try {\n const response = await fetchImpl(subgraphUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: POOL_PRICE_QUERY,\n variables: { id: pointTokenAddress.toLowerCase() },\n }),\n });\n\n if (!response.ok) throw new Error(`subgraph HTTP ${response.status}`);\n\n const json = (await response.json()) as GraphQLPriceResponse;\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n\n const pool = json.data?.pafiToken?.pool;\n if (!pool) throw new Error(\"pafiToken or pool not found\");\n\n // Subgraph V4 returns HUMAN-readable price ratios (decimals already\n // applied). For pool {token0=USDT, token1=PT}:\n // token0Price = USDT_human per 1 PT_human (e.g. \"2.0015\")\n // token1Price = PT_human per 1 USDT_human (e.g. \"0.4996\")\n //\n // We want `ptPerUsdt_18dec` = PT_raw per 1 USDT_human, i.e. the price\n // in PT-raw units per one human USDT. That's:\n // PT_human_per_USDT_human × 10^18 = PT_raw_per_USDT_human\n //\n // So always pick the price string that's \"PT per USDT in human\":\n // isPtToken0 → token0Price is \"PT/USDT_other\" but we have USDT here\n // (PT is token0, token1 is USDT) → token0Price is\n // USDT_human per 1 PT_human → invert\n // !isPtToken0 → token1Price is PT_human per 1 USDT_human → use as-is\n //\n // (Older comment claiming subgraph returns raw ratio + the\n // 10^24 / raw formula was wrong — it returned values off by ~10^11\n // for the typical 18/6 decimals split, making operator fee in PT\n // effectively zero.)\n const isPtToken0 =\n pool.token0.id.toLowerCase() === pointTokenAddress.toLowerCase();\n\n let ptPerUsdtHumanStr: string;\n if (isPtToken0) {\n // token0Price = USDT_human per 1 PT_human → invert to PT/USDT\n const usdtPerPtHuman = Number(pool.token0Price);\n if (!Number.isFinite(usdtPerPtHuman) || usdtPerPtHuman <= 0) {\n throw new Error(`invalid pool token0Price from subgraph: ${pool.token0Price}`);\n }\n ptPerUsdtHumanStr = (1 / usdtPerPtHuman).toFixed(18);\n } else {\n // token1Price = PT_human per 1 USDT_human → use directly\n ptPerUsdtHumanStr = pool.token1Price;\n if (!ptPerUsdtHumanStr || Number(ptPerUsdtHumanStr) <= 0) {\n throw new Error(`invalid pool token1Price from subgraph: ${ptPerUsdtHumanStr}`);\n }\n }\n\n const ptPerUsdt18dec = parseBigDecimalTo18(ptPerUsdtHumanStr);\n if (ptPerUsdt18dec === 0n) {\n throw new Error(`pool price parsed to zero: ${ptPerUsdtHumanStr}`);\n }\n return ptPerUsdt18dec;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n if (fallbackPtPriceUsdt === null) {\n throw new OracleStaleError(\"subgraph\", reason);\n }\n if (onFallback) {\n onFallback({\n source: \"subgraph\",\n reason,\n fallbackValue: fallbackPtPriceUsdt,\n });\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n \"[quoteOperatorFeePt] subgraph unavailable, using opt-in fallback:\",\n reason,\n );\n }\n const ptPerUsdtHuman = 1 / fallbackPtPriceUsdt;\n return parseBigDecimalTo18(ptPerUsdtHuman.toFixed(18));\n }\n}\n\nfunction parseBigDecimalTo18(s: string): bigint {\n const SCALE = 18;\n const [whole = \"0\", frac = \"\"] = s.split(\".\");\n const padded = (frac + \"0\".repeat(SCALE)).slice(0, SCALE);\n return BigInt(whole + padded);\n}\n","import { isAddress } from \"viem\";\nimport type { Address } from \"viem\";\nimport type { PoolKey } from \"../types\";\n\n/**\n * PAFI-hosted subgraph endpoint — single source of truth across all SDK packages.\n *\n * v3 (deployed 2026-05-08) indexes the v1.6 contract redeploy starting at\n * block 45683465 — IssuerRegistry/PointTokenFactory/MintingOracle/MintFeeWrapper\n * (single global wrapper instance, replaces v1.5 PAFIHook). Schema additions:\n * `MintFeeWrapper`, `MintFeeConfig`, `FeeRecipient`, `MintWithFeeEvent`,\n * `FeeDistribution`. v2 endpoint is kept live as rollback for ~1 week before\n * removal.\n */\nexport const PAFI_SUBGRAPH_URL =\n \"https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v3\";\n\nconst POOL_QUERY = `\n query GetPoolForPointToken($id: ID!) {\n pafiToken(id: $id) {\n id\n pool {\n id\n feeTier\n tickSpacing\n hooks\n token0 { id }\n token1 { id }\n }\n }\n }\n`;\n\ninterface GraphQLResponse {\n data?: {\n pafiToken: {\n id: string;\n pool: {\n id: string;\n feeTier: string;\n tickSpacing: string;\n hooks: string;\n token0: { id: string };\n token1: { id: string };\n } | null;\n } | null;\n };\n errors?: { message: string }[];\n}\n\nfunction sortCurrencies(a: Address, b: Address): [Address, Address] {\n return a.toLowerCase() < b.toLowerCase() ? [a, b] : [b, a];\n}\n\n/**\n * Fetch the Uniswap V4 pool(s) for a PAFI PointToken from the subgraph.\n *\n * Browser and Node compatible — uses globalThis.fetch. Returns an empty\n * array (never throws) when the token has no pool yet or the subgraph is\n * unreachable, so callers can show \"quote unavailable\" without crashing.\n *\n * @param chainId - Chain ID (reserved for multi-subgraph routing; currently unused)\n * @param pointTokenAddress - The PointToken contract address\n * @param subgraphUrl - Override the default PAFI subgraph URL\n */\nexport async function fetchPafiPools(\n _chainId: number,\n pointTokenAddress: Address,\n subgraphUrl: string = PAFI_SUBGRAPH_URL,\n): Promise<PoolKey[]> {\n let response: Response;\n try {\n response = await fetch(subgraphUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: POOL_QUERY,\n variables: { id: pointTokenAddress.toLowerCase() },\n }),\n });\n } catch (err) {\n console.warn(\"[fetchPafiPools] subgraph unreachable:\", (err as Error).message);\n return [];\n }\n\n if (!response.ok) {\n console.warn(`[fetchPafiPools] subgraph returned ${response.status}`);\n return [];\n }\n\n const json = (await response.json()) as GraphQLResponse;\n if (json.errors && json.errors.length > 0) {\n console.warn(\n \"[fetchPafiPools] subgraph errors:\",\n json.errors.map((e) => e.message).join(\"; \"),\n );\n return [];\n }\n\n const pool = json.data?.pafiToken?.pool;\n if (!pool) return [];\n\n if (\n !isAddress(pool.hooks) ||\n !isAddress(pool.token0.id) ||\n !isAddress(pool.token1.id) ||\n !Number.isFinite(Number(pool.feeTier)) ||\n !Number.isFinite(Number(pool.tickSpacing))\n ) {\n console.error(\"[fetchPafiPools] invalid pool data in subgraph response — skipping\");\n return [];\n }\n\n const [currency0, currency1] = sortCurrencies(\n pool.token0.id as Address,\n pool.token1.id as Address,\n );\n\n return [{\n currency0,\n currency1,\n fee: Number(pool.feeTier),\n tickSpacing: Number(pool.tickSpacing),\n hooks: pool.hooks as Address,\n }];\n}\n","import { getContractAddresses } from \"./addresses\";\n\n// Derived from addresses.ts — single source of truth.\n// Update addresses.ts when SC team redeploys; these follow automatically.\nexport const BATCH_EXECUTOR_ADDRESS_BASE_MAINNET = getContractAddresses(8453).batchExecutor;\nexport const BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA = getContractAddresses(84532).batchExecutor;\n\n// The ABI itself is fully real — re-exported from userop/ for\n// convenience so consumers don't need two imports.\nexport { BATCH_EXECUTOR_ABI } from \"../../userop/batchExecute\";\n","/**\n * PAFI HTTP service URLs by chainId. Mirrors the `getContractAddresses`\n * pattern: SDK ships with the URL for each supported chain so issuers\n * don't pass URLs as env vars / constructor args.\n *\n * When PAFI changes URLs (rebrand, re-host, environment migration),\n * bump the SDK version and re-publish. Issuers pin a version, get the\n * URLs that match.\n *\n * No env override is provided on purpose — different environments use\n * different SDK versions (e.g. an `@pafi-dev/issuer-dev` channel for\n * staging). This keeps issuer integration to chainId + creds only.\n */\nexport interface PafiServiceUrls {\n /**\n * sponsor-relayer base URL (paymaster proxy). PafiBackendClient\n * appends `/paymaster/sponsor`, `/bundler/receipt`, etc.\n */\n sponsorRelayer: string;\n\n /**\n * issuer-api base URL. SettlementClient appends\n * `/issuers/:issuerId/redemption-policy`.\n */\n issuerApi: string;\n}\n\n/**\n * Per-chain URL map. URLs follow the pattern\n * `https://<host>/api/<service>` so Kong gateway can route by path.\n *\n * NOTE: placeholder URLs — Phi will swap in real prod/staging hosts\n * once the deploy targets are finalized. SDK version bump captures\n * the change.\n */\nexport const PAFI_SERVICE_URLS: Record<number, PafiServiceUrls> = {\n // Base mainnet\n 8453: {\n sponsorRelayer: \"https://api-dev.pacificfinance.org/api/sponsor\",\n issuerApi: \"https://api-dev.pacificfinance.org/api/issuer\",\n },\n // Base sepolia\n 84532: {\n sponsorRelayer: \"https://api-dev.pacificfinance.org/api/sponsor\",\n issuerApi: \"https://api-dev.pacificfinance.org/api/issuer\",\n },\n};\n\nexport function getPafiServiceUrls(chainId: number): PafiServiceUrls {\n const urls = PAFI_SERVICE_URLS[chainId];\n if (!urls) {\n throw new Error(\n `getPafiServiceUrls: no PAFI service URLs for chainId ${chainId}. ` +\n `Supported: ${Object.keys(PAFI_SERVICE_URLS).join(\", \")}`,\n );\n }\n return urls;\n}\n","import type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\n\nconst DEFAULT_WIDTH = 900;\nconst DEFAULT_HEIGHT = 700;\nconst DEFAULT_NAME = \"pafi-web\";\n\n/**\n * Web browser popup adapter. Opens the given URL in a centered\n * `window.open()` popup, polls for close, and optionally forwards\n * `postMessage` events back to the caller.\n *\n * Runtime requirement: `window.open` must exist. Throws if called\n * under Node / SSR / React Native — use `setPafiWebModalAdapter()` to\n * provide a platform-specific adapter in those environments.\n *\n * ## Popup blocking\n *\n * Browsers block `window.open()` unless it happens inside a user\n * gesture (click handler). Callers MUST wire this into a direct click\n * handler — wrapping it in a `setTimeout` or async await before the\n * open call will trigger the blocker.\n */\nexport function openWebPopup(\n url: string,\n options: ModalOpenOptions = {},\n): PafiWebModalHandle {\n if (typeof window === \"undefined\" || typeof window.open !== \"function\") {\n throw new Error(\n \"openWebPopup: `window.open` is not available in this runtime. \" +\n \"Register a platform adapter via setPafiWebModalAdapter() instead.\",\n );\n }\n\n const width = options.width ?? DEFAULT_WIDTH;\n const height = options.height ?? DEFAULT_HEIGHT;\n const name = options.windowName ?? DEFAULT_NAME;\n\n // Center on the screen — works in all major browsers. Falls back\n // gracefully if `screen.availWidth`/`screenX` are unavailable.\n const screenW = window.screen?.availWidth ?? window.innerWidth;\n const screenH = window.screen?.availHeight ?? window.innerHeight;\n const left = Math.max(0, Math.floor((screenW - width) / 2));\n const top = Math.max(0, Math.floor((screenH - height) / 2));\n\n const features = [\n `width=${width}`,\n `height=${height}`,\n `left=${left}`,\n `top=${top}`,\n \"resizable=yes\",\n \"scrollbars=yes\",\n \"noopener=no\", // we need opener.postMessage to work\n ].join(\",\");\n\n const popup = window.open(url, name, features);\n if (!popup) {\n throw new Error(\n \"openWebPopup: popup was blocked. Ensure this call runs inside a user gesture (click handler).\",\n );\n }\n\n // Set up state + listeners --------------------------------------------\n\n let closed = false;\n let pollId: ReturnType<typeof setInterval> | null = null;\n let messageListener: ((e: MessageEvent) => void) | null = null;\n\n const dispose = (): void => {\n if (closed) return;\n closed = true;\n if (pollId !== null) {\n clearInterval(pollId);\n pollId = null;\n }\n if (messageListener) {\n window.removeEventListener(\"message\", messageListener);\n messageListener = null;\n }\n options.onClose?.();\n };\n\n // Poll every 500ms for popup close — there's no `close` event.\n // Stops when `popup.closed` flips to true OR our handle is closed.\n pollId = setInterval(() => {\n if (popup.closed) {\n dispose();\n }\n }, 500);\n\n // Wire postMessage filtering by origin — secure-by-default. An\n // empty `allowedOrigins` would silently reject every message (UI\n // hangs forever waiting for a callback that never arrives), so we\n // throw at construction to surface misconfiguration at startup.\n if (options.onMessage) {\n const allowed = options.allowedOrigins ?? [];\n if (allowed.length === 0) {\n throw new Error(\n \"openPafiWebModal: `allowedOrigins` is empty/missing while `onMessage` \" +\n \"is supplied. The popup-message listener would silently reject every \" +\n \"message — caller must explicitly whitelist PAFI Web's host (e.g. \" +\n \"`['https://app.pacificfinance.org']`) before any payload reaches the \" +\n \"callback. To accept any origin (insecure), pass an explicit list \" +\n \"containing '*' or omit `onMessage` entirely.\",\n );\n }\n const onMessage = options.onMessage;\n messageListener = (event: MessageEvent): void => {\n if (event.source !== popup) return;\n // Allow caller-side wildcard explicitly opt-in; never silently allow.\n if (!allowed.includes(\"*\") && !allowed.includes(event.origin)) return;\n onMessage(event.data, event.origin);\n };\n window.addEventListener(\"message\", messageListener);\n }\n\n // Handle object -------------------------------------------------------\n\n return {\n get isOpen(): boolean {\n return !closed && !popup.closed;\n },\n close(): void {\n if (closed) return;\n try {\n popup.close();\n } catch {\n // Some browsers block close() unless the popup was opened by\n // the same document. Dispose our listeners anyway.\n }\n dispose();\n },\n focus(): void {\n if (closed || popup.closed) return;\n try {\n popup.focus();\n } catch {\n // No-op on failure — focus is best-effort.\n }\n },\n postMessage(data: unknown): void {\n if (closed || popup.closed) return;\n try {\n // targetOrigin '*' is fine here because the caller owns the\n // data being sent. For security on the receiving side, the\n // PAFI Web page should check event.origin itself.\n popup.postMessage(data, \"*\");\n } catch {\n // No-op.\n }\n },\n };\n}\n\n/**\n * The web popup packaged as a {@link PafiWebModalAdapter} so callers\n * can register it explicitly (e.g. in a test harness).\n */\nexport const webPopupAdapter: PafiWebModalAdapter = {\n open(url, options) {\n return openWebPopup(url, options);\n },\n};\n","import { openWebPopup } from \"./webPopup\";\nimport type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\n\nexport type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\nexport { openWebPopup, webPopupAdapter } from \"./webPopup\";\n\n/**\n * Module-level adapter registry — allows platform consumers (React\n * Native, Electron, Tauri, etc.) to plug in their own handoff\n * implementation without forking the SDK.\n *\n * Callers set this once at app boot; `openPafiWebModal()` below uses\n * whatever is registered, or falls back to the web popup adapter\n * when `window.open` is available.\n */\nlet registeredAdapter: PafiWebModalAdapter | null = null;\n\n/**\n * Register the adapter used by `openPafiWebModal()`. Typically called\n * once during app initialization — mobile apps register a\n * SFSafariViewController / Chrome Custom Tabs adapter, desktop apps\n * can leave it unset (web popup is the default).\n *\n * Pass `null` to unregister and fall back to the default.\n */\nexport function setPafiWebModalAdapter(\n adapter: PafiWebModalAdapter | null,\n): void {\n registeredAdapter = adapter;\n}\n\n/**\n * Return the currently registered adapter, or `null` when none is set.\n * Useful for tests that want to snapshot-and-restore the adapter.\n */\nexport function getPafiWebModalAdapter(): PafiWebModalAdapter | null {\n return registeredAdapter;\n}\n\n/**\n * Open PAFI Web in the host platform's appropriate UX:\n *\n * - Browser (window.open): centered popup, 900×700 by default\n * - React Native (with adapter registered): SFSafariViewController\n * / Chrome Custom Tabs via `react-native-inappbrowser-reborn` or\n * `expo-web-browser`\n * - Desktop (with adapter registered): custom BrowserWindow / new tab\n *\n * Resolution order:\n * 1. If an adapter was registered via `setPafiWebModalAdapter()`, use it.\n * 2. Else if `window.open` is available, use the built-in web popup.\n * 3. Else throw with a clear error pointing at the adapter registry.\n *\n * @example\n * ```ts\n * // User clicks \"Trade on PAFI\" button\n * button.addEventListener('click', async () => {\n * const modal = await openPafiWebModal('https://app.pacificfinance.org', {\n * allowedOrigins: ['https://app.pacificfinance.org'],\n * onMessage: (data, origin) => {\n * if (typeof data === 'object' && data && 'txHash' in data) {\n * console.log('Swap confirmed:', data.txHash);\n * modal.close();\n * }\n * },\n * onClose: () => {\n * console.log('User closed modal');\n * },\n * });\n * });\n * ```\n */\nexport async function openPafiWebModal(\n url: string,\n options: ModalOpenOptions = {},\n): Promise<PafiWebModalHandle> {\n if (!url || typeof url !== \"string\") {\n throw new Error(\"openPafiWebModal: `url` is required\");\n }\n\n if (registeredAdapter) {\n return Promise.resolve(registeredAdapter.open(url, options));\n }\n\n if (typeof window !== \"undefined\" && typeof window.open === \"function\") {\n return openWebPopup(url, options);\n }\n\n throw new Error(\n \"openPafiWebModal: no adapter registered and `window.open` is unavailable. \" +\n \"Call `setPafiWebModalAdapter()` with a platform-specific adapter (e.g. SFSafariViewController on iOS) during app boot.\",\n );\n}\n"],"mappings":"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","names":["http","encodeFunctionData","erc20Abi","encodeFunctionData","parseAbi","encodeFunctionData","encodeFunctionData","encodeFunctionData","concat","keccak256","parseAbi","parseAbi","http"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/perp/buildPerpDepositWithGasDeduction.ts","../src/contracts/real/orderlyVault.ts","../src/userop/operations.ts","../src/userop/batchExecute.ts","../src/userop/buildUserOperation.ts","../src/perp/buildPerpDepositViaRelay.ts","../src/userop/types.ts","../src/userop/serializeUserOp.ts","../src/userop/computeUserOpHash.ts","../src/userop/eip7702Helpers.ts","../src/paymaster/config.ts","../src/utils/checkEthAndBranch.ts","../src/delegation/checkDelegation.ts","../src/delegation/buildDelegationUserOp.ts","../src/delegation/computeAuthorizationHash.ts","../src/delegation/eip7702Authorization.ts","../src/contracts/real/addresses.ts","../src/delegation/delegateDirect.ts","../src/transport/proxyTransport.ts","../src/transport/paymasterFallback.ts","../src/fee/operatorFeeQuoter.ts","../src/subgraph/pools.ts","../src/contracts/real/batchExecutor.ts","../src/contracts/real/pafi-services.ts","../src/web-handoff/webPopup.ts","../src/web-handoff/index.ts"],"sourcesContent":["import { createPublicClient, http } from \"viem\";\nimport type { Address, Hex, PublicClient, WalletClient } from \"viem\";\n\n// -------------------------------------------------------------------------\n// Re-export all sub-modules\n// -------------------------------------------------------------------------\nexport * from \"./types\";\nexport * from \"./constants\";\nexport * from \"./errors\";\nexport * from \"./abi/index\";\nexport * from \"./eip712/index\";\nexport * from \"./contract/index\";\n// quoting + swap moved to @pafi-dev/trading (2026-04-27). Core retains\n// underlying ABI primitives (universalRouterAbi, permit2Abi,\n// v4QuoterAbi) + types (PoolKey, PathKey, QuoteResult) — used by\n// trading, but core no longer ships swap UserOp builders / quote\n// orchestration.\nexport * from \"./perp/index\";\nexport * from \"./auth/index\";\n\n// v1.4 — Account Abstraction primitives (EIP-7702 + ERC-4337 v0.7)\nexport * from \"./userop/index\";\nexport * from \"./paymaster/index\";\nexport * from \"./utils/index\";\nexport * from \"./delegation/index\";\nexport * from \"./transport/index\";\n// Operator-fee quoter — pure on-chain + subgraph reads, lets the SDK\n// Direct path compute the PT operator fee without calling the issuer\n// backend. Sponsor-relayer's `FeeValidatorService` runs the same\n// math server-side (with a 5% tolerance window).\nexport * from \"./fee/index\";\n\n// v1.4 — Contract ABIs + addresses. ABI matches deployed PointToken on\n// Base mainnet; only `batchExecutor` address + Base Sepolia row remain\n// placeholder. EIP-712 helpers live under `./eip712/` and are already\n// exported above — not re-exported here.\n// Consumers: `import { POINT_TOKEN_V2_ABI, CONTRACT_ADDRESSES, ... } from '@pafi-dev/core'`\nexport * from \"./contracts/index\";\n\n// v1.5 — PAFI Web handoff (mobile + desktop modal helper).\n// `openPafiWebModal()` + adapter registry for platform-specific UX.\nexport * from \"./web-handoff/index\";\n\n// Subgraph helpers — pool discovery via PAFI-hosted subgraph.\n// Browser and Node compatible (plain fetch).\nexport * from \"./subgraph/index\";\n\n// -------------------------------------------------------------------------\n// Internal imports for PafiSDK class\n// -------------------------------------------------------------------------\nimport { buildMintRequestTypedData, signMintRequest, verifyMintRequest } from \"./eip712/mintRequest\";\nimport {\n getMintRequestNonce,\n getTokenName,\n} from \"./contract/pointToken\";\nimport { createLoginMessage } from \"./auth/loginMessage\";\nimport type { LoginMessageParams } from \"./auth/types\";\nimport { ConfigurationError } from \"./errors\";\nimport type {\n EIP712Signature,\n MintRequest,\n PafiSDKConfig,\n PointTokenDomainConfig,\n SignatureVerification,\n} from \"./types\";\n\n// -------------------------------------------------------------------------\n// PafiSDK — convenience class wrapping all contract + crypto primitives.\n//\n// This class is HTTP-client-free on purpose. It covers signing, verifying,\n// contract reads, and calldata encoding — the things that need a signer\n// or a provider but no HTTP layer. The issuer backend defines its own HTTP\n// contract via `@pafi/issuer`; frontends build `fetch()` calls against\n// those types directly.\n// -------------------------------------------------------------------------\n\nexport class PafiSDK {\n private _pointTokenAddress?: Address;\n private _signer?: WalletClient;\n private _provider?: PublicClient;\n private _chainId?: number;\n\n // -------------------------------------------------------------------------\n // Domain namespaces — grouped by concern for better IDE autocomplete.\n // Each property is a plain object of bound methods; the underlying logic\n // lives in the flat methods below so both access styles work.\n // -------------------------------------------------------------------------\n\n readonly mint: {\n buildTypedData: PafiSDK[\"buildMintRequestTypedData\"];\n sign: PafiSDK[\"signMintRequest\"];\n verify: PafiSDK[\"verifyMintRequest\"];\n getNonce: PafiSDK[\"getMintRequestNonce\"];\n };\n\n readonly auth: {\n createLoginMessage: PafiSDK[\"createLoginMessage\"];\n signMessage: PafiSDK[\"signLoginMessage\"];\n };\n\n constructor(config: PafiSDKConfig) {\n this._pointTokenAddress = config.pointTokenAddress;\n this._signer = config.signer;\n this._chainId = config.chainId;\n\n if (config.provider) {\n this._provider = config.provider;\n } else if (config.rpcUrl) {\n this._provider = createPublicClient({\n transport: http(config.rpcUrl),\n });\n }\n\n this.mint = {\n buildTypedData: this.buildMintRequestTypedData.bind(this),\n sign: this.signMintRequest.bind(this),\n verify: this.verifyMintRequest.bind(this),\n getNonce: this.getMintRequestNonce.bind(this),\n };\n\n this.auth = {\n createLoginMessage: this.createLoginMessage.bind(this),\n signMessage: this.signLoginMessage.bind(this),\n };\n }\n\n // -------------------------------------------------------------------------\n // Setters\n // -------------------------------------------------------------------------\n\n setPointTokenAddress(address: Address): void {\n this._pointTokenAddress = address;\n }\n\n setSigner(signer: WalletClient): void {\n this._signer = signer;\n }\n\n setProvider(provider: PublicClient): void {\n this._provider = provider;\n }\n\n // -------------------------------------------------------------------------\n // Private guards\n // -------------------------------------------------------------------------\n\n private requirePointToken(): Address {\n if (!this._pointTokenAddress) {\n throw new ConfigurationError(\"pointTokenAddress not set\");\n }\n return this._pointTokenAddress;\n }\n\n private requireProvider(): PublicClient {\n if (!this._provider) {\n throw new ConfigurationError(\"provider not set\");\n }\n return this._provider;\n }\n\n private requireSigner(): WalletClient {\n if (!this._signer) {\n throw new ConfigurationError(\"signer not set\");\n }\n return this._signer;\n }\n\n private requireChainId(): number {\n if (this._chainId === undefined) {\n throw new ConfigurationError(\"chainId not set\");\n }\n return this._chainId;\n }\n\n // -------------------------------------------------------------------------\n // Domain\n // -------------------------------------------------------------------------\n\n async getDomain(): Promise<PointTokenDomainConfig> {\n const provider = this.requireProvider();\n const pointToken = this.requirePointToken();\n const chainId = this.requireChainId();\n const name = await getTokenName(provider, pointToken);\n return { name, verifyingContract: pointToken, chainId };\n }\n\n // -------------------------------------------------------------------------\n // EIP-712 — delegates to pure functions\n // -------------------------------------------------------------------------\n\n async buildMintRequestTypedData(message: MintRequest) {\n const domain = await this.getDomain();\n return buildMintRequestTypedData(domain, message);\n }\n\n async signMintRequest(message: MintRequest): Promise<EIP712Signature> {\n const domain = await this.getDomain();\n return signMintRequest(this.requireSigner(), domain, message);\n }\n\n async verifyMintRequest(\n message: MintRequest,\n signature: Hex,\n expectedMinter: Address,\n ): Promise<SignatureVerification> {\n const domain = await this.getDomain();\n return verifyMintRequest(domain, message, signature, expectedMinter);\n }\n\n // -------------------------------------------------------------------------\n // Contract reads\n // -------------------------------------------------------------------------\n\n async getMintRequestNonce(receiver: Address): Promise<bigint> {\n return getMintRequestNonce(\n this.requireProvider(),\n this.requirePointToken(),\n receiver,\n );\n }\n\n // -------------------------------------------------------------------------\n // Auth — EIP-4361 login helpers (offline, stateless)\n // -------------------------------------------------------------------------\n\n async createLoginMessage(\n params: Omit<LoginMessageParams, \"address\" | \"chainId\">,\n ): Promise<string> {\n const signer = this.requireSigner();\n const chainId = this.requireChainId();\n const account = signer.account;\n if (!account) {\n throw new ConfigurationError(\"signer has no account attached\");\n }\n return createLoginMessage({ ...params, address: account.address, chainId });\n }\n\n /** Sign a login message string with the current signer (personal_sign) */\n async signLoginMessage(message: string): Promise<Hex> {\n const signer = this.requireSigner();\n const account = signer.account;\n if (!account) {\n throw new ConfigurationError(\"signer has no account attached\");\n }\n return signer.signMessage({ account, message });\n }\n}\n\n// `buildUniversalRouterExecuteArgs` and other swap helpers moved to\n// `@pafi-dev/trading` along with `findBestQuote` (2026-04-27).\n","/**\n * Unified error base for the entire SDK (core + issuer + trading).\n * Subclasses declare `code` (machine-readable) and `httpStatus`\n * (recommended HTTP status for issuer's controller).\n *\n * Issuer's `createSdkErrorMapper` routes any `PafiSdkError` instance\n * through framework-specific exception factories; non-PafiSdkError\n * still becomes 500.\n */\nexport type SdkErrorHttpStatus =\n | \"not_found\"\n | \"forbidden\"\n | \"unprocessable\"\n | \"service_unavailable\";\n\n/**\n * Stripe-style error taxonomy. The SDK emits one of these on every\n * error so consumers can branch UI behavior on `type` (toast vs modal\n * vs retry banner) without whitelisting individual `code` values.\n */\nexport type PafiErrorType =\n | \"validation_error\"\n | \"authentication_error\"\n | \"authorization_error\"\n | \"not_found_error\"\n | \"business_logic_error\"\n | \"rate_limit_error\"\n | \"server_error\"\n | \"service_unavailable_error\";\n\n/** Numeric HTTP status implied by an `SdkErrorHttpStatus` slot. */\nexport const SDK_ERROR_HTTP_STATUS_CODE: Record<SdkErrorHttpStatus, number> = {\n not_found: 404,\n forbidden: 403,\n unprocessable: 422,\n service_unavailable: 503,\n};\n\n/** Default `type` slot for a numeric HTTP status. */\nexport function defaultErrorTypeForStatus(status: number): PafiErrorType {\n if (status === 400) return \"validation_error\";\n if (status === 401) return \"authentication_error\";\n if (status === 403) return \"authorization_error\";\n if (status === 404) return \"not_found_error\";\n if (status === 422) return \"business_logic_error\";\n if (status === 429) return \"rate_limit_error\";\n if (status === 503) return \"service_unavailable_error\";\n return \"server_error\";\n}\n\nexport abstract class PafiSdkError extends Error {\n abstract readonly code: string;\n /**\n * `true` when the FE should consider a retry safe — typically because\n * the failure is transient.\n */\n readonly safeToRetry: boolean = false;\n readonly details?: unknown;\n abstract readonly httpStatus: SdkErrorHttpStatus;\n /**\n * Optional Stripe-style taxonomy override. Defaults to the type\n * implied by `httpStatus` (forbidden→authorization_error,\n * unprocessable→business_logic_error, etc).\n */\n readonly type?: PafiErrorType;\n /**\n * Optional name of the request field that triggered the error (e.g.\n * `\"amount\"`, `\"chainId\"`). Surfaced on validation failures so the\n * client can highlight the offending field.\n */\n readonly param?: string;\n /**\n * Optional structured context (e.g. `{ available, requested }` for a\n * cap denial). Distinct from `details` — `metadata` is meant for\n * UI consumption; `details` carries raw debug info.\n */\n readonly metadata?: Record<string, unknown>;\n\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/**\n * @deprecated Use `PafiSdkError` (capital S, lowercase dk).\n * The two classes existed in parallel (\"PafiSDKError\" in core,\n * \"PafiSdkError\" in issuer) due to historical drift; consolidating\n * here. Kept as alias for back-compat through v0.7.x; will be removed\n * in v0.8.\n */\nexport class PafiSDKError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PafiSDKError\";\n }\n}\n\nexport class ConfigurationError extends PafiSDKError {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class SigningError extends PafiSDKError {\n constructor(message: string) {\n super(message);\n this.name = \"SigningError\";\n }\n}\n\nexport class SimulationError extends PafiSDKError {\n constructor(\n public operation: string,\n public reason: string,\n ) {\n super(`Simulation failed for ${operation}: ${reason}`);\n this.name = \"SimulationError\";\n }\n}\n\nexport class ApiError extends PafiSDKError {\n constructor(\n message: string,\n public status?: number,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/**\n * Thrown by `quoteOperatorFee*` when an upstream price source\n * (Chainlink ETH/USD, PAFI subgraph) is unavailable or stale and the\n * caller did not opt in to the hardcoded fallback prices via\n * `allowStaleFallback: true`.\n *\n * Extends the unified `PafiSdkError` so issuer's `createSdkErrorMapper`\n * routes it to 503 instead of leaking as a 500.\n */\nexport class OracleStaleError extends PafiSdkError {\n readonly httpStatus = \"service_unavailable\" as const;\n readonly code = \"ORACLE_STALE\" as const;\n readonly source: \"chainlink\" | \"subgraph\";\n readonly reason: string;\n constructor(source: \"chainlink\" | \"subgraph\", reason: string) {\n super(`Oracle ${source} unavailable: ${reason}`);\n this.source = source;\n this.reason = reason;\n }\n}\n\n/**\n * Generic 4xx-class validation failure for input checks at any SDK\n * boundary (core helpers, trading handlers, etc.). Issuer's\n * `createSdkErrorMapper` routes to 422.\n *\n * Uses an instance `details` field so subclasses can override the\n * declaration; matches the issuer-side shape that pre-existed here.\n */\nexport class ValidationError extends PafiSdkError {\n readonly httpStatus = \"unprocessable\" as const;\n readonly type = \"validation_error\" as const;\n readonly code: string;\n declare readonly details?: Record<string, unknown>;\n declare readonly param?: string;\n declare readonly metadata?: Record<string, unknown>;\n\n constructor(\n code: string,\n message: string,\n details?: Record<string, unknown>,\n options?: { param?: string; metadata?: Record<string, unknown> },\n ) {\n super(message);\n this.code = code;\n (this as { details?: Record<string, unknown> }).details = details;\n if (options?.param) {\n (this as { param?: string }).param = options.param;\n }\n if (options?.metadata) {\n (this as { metadata?: Record<string, unknown> }).metadata = options.metadata;\n }\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport {\n ORDERLY_VAULT_ABI,\n ORDERLY_VAULT_ADDRESSES,\n type VaultDepositFE,\n} from \"../contracts/real/orderlyVault\";\nimport { erc20ApproveOp, rawCallOp } from \"../userop/operations\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { Operation, PartialUserOperation } from \"../userop/types\";\n\n/**\n * v1.5 — Scenario 3: deposit USDC from the user's wallet into the\n * Orderly perp Vault on Base mainnet.\n *\n * Builds a `PartialUserOperation` packaging the 2 inner calls:\n *\n * 1. `USDC.approve(orderlyVault, amount)` — let the Vault pull USDC\n * 2. `OrderlyVault.deposit{value: layerZeroFee}(VaultDepositFE)` —\n * transfer USDC into the Vault + emit a LayerZero message that\n * credits the user's perp account on the Orderly chain\n *\n * ## ⚠️ Native ETH constraint\n *\n * PAFI sponsor-relayer sponsors GAS, **not `msg.value`**. The LayerZero\n * cross-chain fee MUST come from the user's own native ETH balance on\n * Base — even when the rest of the UserOp is sponsored.\n *\n * Quote the fee BEFORE calling this builder via:\n *\n * const fee = await client.readContract({\n * address: orderlyVault,\n * abi: ORDERLY_VAULT_ABI,\n * functionName: 'getDepositFee',\n * args: [user, depositData],\n * });\n *\n * If `user.eth < fee`, surface this error to the FE so the user can\n * top up before retrying — the Vault `deposit{value: 0}` call will\n * revert otherwise.\n *\n * ## Why no PT/USDC fee deduction?\n *\n * Unlike Scenario 1/2/4 which deduct an operator fee in PT/USDC inside\n * the batch, perp deposit doesn't append a fee transfer because:\n *\n * - User is paying Orderly's LayerZero fee directly via `msg.value`\n * - There's no PAFI-specific operator cost on top — Orderly handles\n * the off-chain accounting once the LayerZero message lands\n *\n * If we want to charge a PAFI service fee on top later, append a\n * `USDC.transfer(feeRecipient, fee)` op — same pattern as the swap\n * builder.\n */\nexport interface BuildPerpDepositWithGasDeductionParams {\n /** User EOA (will be `msg.sender` via EIP-7702 delegation). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** Chain ID for Orderly Vault address resolution. */\n chainId: number;\n /**\n * Override Orderly Vault address (e.g. for fork tests). Defaults to\n * `ORDERLY_VAULT_ADDRESSES[chainId]`.\n */\n vaultAddress?: Address;\n\n /**\n * USDC ERC-20 address — the actual token Orderly accepts. Caller\n * resolves this via `vault.getAllowedToken(TOKEN_HASHES.USDC)` so we\n * don't hardcode the wrong USDC variant (native vs bridged).\n */\n usdcAddress: Address;\n\n /** USDC amount to deposit (uint128, 6 decimals). */\n amount: bigint;\n\n /**\n * Pre-built `VaultDepositFE` struct — caller computes accountId via\n * `computeAccountId(user, brokerHash)` and supplies tokenHash.\n */\n depositData: VaultDepositFE;\n\n /**\n * LayerZero fee in wei — from `vault.getDepositFee(user, data)`.\n * Becomes the `msg.value` on the `deposit()` call. User MUST hold\n * ≥ this much native ETH or the call reverts.\n */\n layerZeroFee: bigint;\n\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for Scenario 3. Returns a\n * `PartialUserOperation` — caller attaches paymaster sponsorship for\n * gas + the user's UserOp-hash signature, then submits to the Bundler.\n */\nexport function buildPerpDepositWithGasDeduction(\n params: BuildPerpDepositWithGasDeductionParams,\n): PartialUserOperation {\n if (params.amount <= 0n) {\n throw new Error(\"buildPerpDepositWithGasDeduction: amount must be positive\");\n }\n if (params.layerZeroFee < 0n) {\n throw new Error(\n \"buildPerpDepositWithGasDeduction: layerZeroFee cannot be negative\",\n );\n }\n if (params.depositData.tokenAmount !== params.amount) {\n throw new Error(\n `buildPerpDepositWithGasDeduction: depositData.tokenAmount (${params.depositData.tokenAmount}) ` +\n `must equal amount (${params.amount})`,\n );\n }\n\n const vault =\n params.vaultAddress ?? ORDERLY_VAULT_ADDRESSES[params.chainId];\n if (!vault) {\n throw new Error(\n `buildPerpDepositWithGasDeduction: no Orderly Vault address for chainId ${params.chainId}`,\n );\n }\n\n const depositCallData: Hex = encodeFunctionData({\n abi: ORDERLY_VAULT_ABI,\n functionName: \"deposit\",\n args: [params.depositData],\n });\n\n const operations: Operation[] = [\n erc20ApproveOp(params.usdcAddress, vault, params.amount),\n {\n ...rawCallOp(vault, depositCallData),\n // BatchExecutor passes `value` from the inner call along; this\n // becomes the LayerZero fee. The aggregated `msg.value` for the\n // top-level UserOp must equal the sum of inner `value`s.\n value: params.layerZeroFee,\n },\n ];\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 800_000n,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import { keccak256, encodePacked, encodeAbiParameters } from \"viem\";\nimport type { Address, Hex } from \"viem\";\n\n/**\n * Orderly Network Vault — entrypoint for **perp deposit** flow on\n * Base mainnet (Scenario 3).\n *\n * Source of truth for addresses + integration:\n * https://orderly.network/docs/build-on-omnichain/addresses#base\n *\n * ## Architecture\n *\n * User wallet (Base)\n * │ 1. USDC.approve(vault, amount)\n * │ 2. vault.deposit{value: layerZeroFee}({\n * │ accountId, brokerHash, tokenHash, tokenAmount\n * │ })\n * ▼\n * OrderlyVault (Base)\n * │ — locks USDC, emits LayerZero message\n * ▼\n * Orderly chain (off-chain matching engine)\n * │ — credits the user's perp account\n * ▼\n * User can now place perp orders via Orderly REST/WS API\n *\n * **Important:** `value` is required and is the LayerZero cross-chain\n * fee (paid in native ETH on Base). Quote it via\n * `vault.getDepositFee(user, data)` BEFORE calling deposit. Fees vary\n * with destination chain congestion.\n *\n * ## Sponsored vs direct\n *\n * ERC-4337 paymasters sponsor GAS, not `msg.value`. Even on the\n * sponsored path the user MUST hold enough native ETH on Base to cover\n * `getDepositFee()` (typically ~0.0002 ETH at quiet times).\n */\n\n/** Orderly Vault on Base mainnet (EIP-55 checksum). */\nexport const ORDERLY_VAULT_BASE_MAINNET: Address =\n \"0x816f722424B49Cf1275cc86DA9840Fbd5a6167e9\";\n\n/**\n * Per-chain registry of the Orderly Vault. Add chains here as Orderly\n * deploys them.\n */\nexport const ORDERLY_VAULT_ADDRESSES: Record<number, Address> = {\n 8453: ORDERLY_VAULT_BASE_MAINNET,\n};\n\n/**\n * Pre-computed broker hashes — `keccak256(abi.encodePacked(brokerId))`.\n * Add new brokers as they launch.\n *\n * Reference: https://orderly.network/docs/build-on-omnichain/user-flows/accountId\n */\nexport const BROKER_HASHES = {\n /** Default partner broker on Base — most commonly whitelisted. */\n woofi_pro: keccak256(encodePacked([\"string\"], [\"woofi_pro\"])),\n /** Orderly's own white-label broker. */\n orderly: keccak256(encodePacked([\"string\"], [\"orderly\"])),\n /** LogX. */\n logx: keccak256(encodePacked([\"string\"], [\"logx\"])),\n} as const satisfies Record<string, Hex>;\n\n/**\n * Pre-computed token hashes — `keccak256(abi.encodePacked(tokenSymbol))`.\n * The hash maps to the actual ERC-20 address on each chain via\n * `vault.getAllowedToken(tokenHash)`.\n *\n * Note: Orderly canonicalises by symbol (USDC, not \"USD Coin\").\n */\nexport const TOKEN_HASHES = {\n USDC: keccak256(encodePacked([\"string\"], [\"USDC\"])),\n} as const satisfies Record<string, Hex>;\n\n/**\n * Compute Orderly's `accountId` — uniquely identifies a user+broker\n * tuple. Matches the off-chain formula used by the Orderly SDK so\n * deposits + future REST API calls reference the same account.\n *\n * accountId = keccak256(abi.encode(user, brokerHash))\n *\n * Note `abi.encode` (not `encodePacked`) — uses 32-byte left-padding.\n */\nexport function computeAccountId(\n user: Address,\n brokerHash: Hex,\n): Hex {\n return keccak256(\n encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"bytes32\" },\n ],\n [user, brokerHash],\n ),\n );\n}\n\n/**\n * Minimal Orderly Vault ABI — just the functions PAFI needs for\n * Scenario 3 (perp deposit). Full ABI is on Orderly's docs site.\n */\nexport const ORDERLY_VAULT_ABI = [\n // Deposit USDC into Orderly perp account. Emits LayerZero message\n // to the Orderly chain. `msg.value` MUST equal `getDepositFee(...)`.\n {\n type: \"function\",\n name: \"deposit\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"data\",\n type: \"tuple\",\n components: [\n { name: \"accountId\", type: \"bytes32\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"tokenHash\", type: \"bytes32\" },\n { name: \"tokenAmount\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [],\n },\n // Quote the LayerZero fee for a deposit message. Pass the same\n // VaultDepositFE struct you intend to send.\n {\n type: \"function\",\n name: \"getDepositFee\",\n stateMutability: \"view\",\n inputs: [\n { name: \"user\", type: \"address\" },\n {\n name: \"data\",\n type: \"tuple\",\n components: [\n { name: \"accountId\", type: \"bytes32\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"tokenHash\", type: \"bytes32\" },\n { name: \"tokenAmount\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n // Pre-flight check — is this brokerId whitelisted on this Vault?\n {\n type: \"function\",\n name: \"getAllowedBroker\",\n stateMutability: \"view\",\n inputs: [{ name: \"brokerHash\", type: \"bytes32\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n // Pre-flight check — what ERC-20 address does this token symbol\n // resolve to on this Vault?\n {\n type: \"function\",\n name: \"getAllowedToken\",\n stateMutability: \"view\",\n inputs: [{ name: \"tokenHash\", type: \"bytes32\" }],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n] as const;\n\n/** Struct mirror of `IOrderlyVault.VaultDepositFE` for type-safe builders. */\nexport interface VaultDepositFE {\n accountId: Hex;\n brokerHash: Hex;\n tokenHash: Hex;\n /** uint128 — USDC has 6 decimals. */\n tokenAmount: bigint;\n}\n","import { encodeFunctionData, erc20Abi, parseAbi } from \"viem\";\nimport type { Address } from \"viem\";\nimport type { Operation } from \"./types\";\n\n/**\n * ERC20Burnable extension — `burn(uint256 amount)` burns from msg.sender.\n * The EOA (via EIP-7702 delegation) is the `msg.sender` when a batch\n * runs — so this burns the user's balance without any role check.\n */\nconst ERC20_BURNABLE_ABI = parseAbi([\"function burn(uint256 amount)\"]);\n\n/**\n * Build an ERC-20 `transfer(to, amount)` operation. Used inside a batch\n * to move fee tokens from the user to the fee recipient atomically with\n * the main action.\n */\nexport function erc20TransferOp(\n token: Address,\n to: Address,\n amount: bigint,\n): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"transfer\",\n args: [to, amount],\n }),\n };\n}\n\n/**\n * Build an ERC-20 `approve(spender, amount)` operation. Used inside a\n * batch before a swap / deposit call so the AMM / protocol can pull\n * tokens from the user.\n */\nexport function erc20ApproveOp(\n token: Address,\n spender: Address,\n amount: bigint,\n): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n }),\n };\n}\n\n/**\n * Build an ERC-20 `burn(amount)` operation (OpenZeppelin ERC20Burnable\n * extension). Burns from `msg.sender`, which — via EIP-7702 — is the\n * user's EOA.\n *\n * Requires the PointToken contract to expose a public `burn(uint256)`\n * without a role check. See\n * [SDK_V1.4_TASKS.md §11 — PointToken.burn callable via batch].\n */\nexport function erc20BurnOp(token: Address, amount: bigint): Operation {\n return {\n target: token,\n value: 0n,\n data: encodeFunctionData({\n abi: ERC20_BURNABLE_ABI,\n functionName: \"burn\",\n args: [amount],\n }),\n };\n}\n\n/**\n * Build a raw call operation with caller-supplied calldata. Useful for\n * non-ERC-20 contracts (PoolManager.swap, PerpDEX.deposit, Relayer.mint)\n * where the encoding is specific to that protocol.\n */\nexport function rawCallOp(\n target: Address,\n data: `0x${string}`,\n value: bigint = 0n,\n): Operation {\n return { target, value, data };\n}\n","import { decodeFunctionData, encodeFunctionData, parseAbi } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { Operation } from \"./types\";\n\n/**\n * Standard BatchExecutor ABI — a contract that takes an array of calls\n * and invokes each one in sequence, reverting all if any fail.\n *\n * Function name is `executeBatch` (selector `0x34fcd5be`) to match\n * Pimlico's `Simple7702Account` — the EIP-7702 delegate impl PAFI\n * pins on Base mainnet as of v1.4 (replaced an earlier Coinbase Smart\n * Wallet v2 trial). The shorter `execute(Call[])` (selector\n * `0x3f707e6b`) only exists on legacy/standalone batch executor\n * contracts; calling it on a 7702 delegated EOA falls through to the\n * fallback function and reverts with \"account: not from EntryPoint\"\n * (AA23).\n */\nexport const BATCH_EXECUTOR_ABI = parseAbi([\n \"function executeBatch((address target, uint256 value, bytes data)[] calls)\",\n]);\n\n/**\n * Encode a batch of operations into calldata for\n * `BatchExecutor.executeBatch((address,uint256,bytes)[])`. The\n * resulting calldata goes into `UserOperation.callData`.\n *\n * When the EOA has an EIP-7702 delegation to a BatchExecutor, calling\n * this calldata against the EOA runs all operations with\n * `msg.sender = EOA` for each inner call.\n *\n * @param operations batch of calls, in execution order\n * @returns calldata bytes for `executeBatch((address,uint256,bytes)[])`\n */\nexport function encodeBatchExecute(operations: Operation[]): Hex {\n if (operations.length === 0) {\n throw new Error(\"encodeBatchExecute: operations array must not be empty\");\n }\n return encodeFunctionData({\n abi: BATCH_EXECUTOR_ABI,\n functionName: \"executeBatch\",\n args: [\n operations.map((op) => ({\n target: op.target,\n value: op.value,\n data: op.data,\n })),\n ],\n });\n}\n\n/**\n * Decode `BatchExecutor.executeBatch(calls[])` callData back into\n * individual `{ to, data, value }` objects.\n *\n * Used by issuer backends to convert a `PartialUserOperation.callData`\n * into the `calls[]` array returned to web/FE clients (which submit via\n * `permissionless.sendTransaction({ calls })`).\n */\nexport function decodeBatchExecuteCalls(\n callData: Hex,\n): Array<{ to: string; data: string; value: string }> {\n const { args } = decodeFunctionData({\n abi: BATCH_EXECUTOR_ABI,\n data: callData,\n });\n return (\n args[0] as ReadonlyArray<{ target: Address; value: bigint; data: Hex }>\n ).map((c) => ({\n to: c.target,\n data: c.data,\n value: c.value.toString(),\n }));\n}\n","import type { Address } from \"viem\";\nimport type { Operation, PartialUserOperation, UserOperation } from \"./types\";\nimport { encodeBatchExecute } from \"./batchExecute\";\n\n/**\n * Default gas limits — rough upper bounds for a 2-op batch on Base.\n * Bundler re-estimates before submission, so these are only used when\n * the caller doesn't supply their own.\n */\nconst DEFAULT_CALL_GAS_LIMIT = 500_000n;\nconst DEFAULT_VERIFICATION_GAS_LIMIT = 150_000n;\nconst DEFAULT_PRE_VERIFICATION_GAS = 50_000n;\n\nexport interface BuildPartialUserOpParams {\n /** User's EOA (with EIP-7702 delegation). */\n sender: Address;\n /** Batch of operations — encoded into callData via `encodeBatchExecute`. */\n operations: Operation[];\n /** EntryPoint nonce for this sender. Caller fetches from the EntryPoint contract. */\n nonce: bigint;\n /** Optional gas overrides; bundler re-estimates before submission. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n /** Optional fee overrides; bundler usually fills these. */\n feeOverrides?: {\n maxFeePerGas?: bigint;\n maxPriorityFeePerGas?: bigint;\n };\n}\n\n/**\n * Build a partial ERC-4337 UserOperation from a batch of operations.\n * Paymaster fields and signature are populated later:\n * 1. Call `PafiBackendClient.requestSponsorship()` → get paymaster fields\n * 2. Compute userOpHash and have the user sign it (via Privy)\n * 3. Attach `signature` → submit to bundler\n *\n * This function is a pure struct builder — no network calls.\n */\nexport function buildPartialUserOperation(\n params: BuildPartialUserOpParams,\n): PartialUserOperation {\n return {\n sender: params.sender,\n nonce: params.nonce,\n callData: encodeBatchExecute(params.operations),\n callGasLimit: params.gasLimits?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ??\n DEFAULT_VERIFICATION_GAS_LIMIT,\n preVerificationGas:\n params.gasLimits?.preVerificationGas ?? DEFAULT_PRE_VERIFICATION_GAS,\n maxFeePerGas: params.feeOverrides?.maxFeePerGas ?? 0n,\n maxPriorityFeePerGas: params.feeOverrides?.maxPriorityFeePerGas ?? 0n,\n };\n}\n\n/**\n * Assemble a full UserOperation once paymaster fields + signature are\n * known. Used after `PafiBackendClient.requestSponsorship()` and user\n * signing complete.\n */\nexport function assembleUserOperation(\n partial: PartialUserOperation,\n paymaster: {\n paymaster: Address;\n paymasterData: `0x${string}`;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n },\n signature: `0x${string}`,\n): UserOperation {\n return {\n ...partial,\n paymaster: paymaster.paymaster,\n paymasterData: paymaster.paymasterData,\n paymasterVerificationGasLimit: paymaster.paymasterVerificationGasLimit,\n paymasterPostOpGasLimit: paymaster.paymasterPostOpGasLimit,\n signature,\n };\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { erc20ApproveOp, erc20TransferOp, rawCallOp } from \"../userop/operations\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { Operation, PartialUserOperation } from \"../userop/types\";\n\n/**\n * Minimal ABI for the Orderly perp-deposit Relay (deployed at\n * `CONTRACT_ADDRESSES[chainId].orderlyRelay`).\n *\n * The Relay holds an ETH reserve and pays Orderly's LayerZero msg.value\n * out of it. Users only need USDC + the Relay-charged USDC fee — they\n * never hold ETH for msg.value, which unblocks the ERC-4337 sponsored\n * gas path for perp deposits (paymaster covers gas, NOT msg.value).\n */\nexport const ORDERLY_RELAY_ABI = [\n {\n type: \"function\",\n name: \"deposit\",\n stateMutability: \"nonpayable\",\n inputs: [\n {\n name: \"req\",\n type: \"tuple\",\n components: [\n { name: \"token\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"totalAmount\", type: \"uint128\" },\n { name: \"maxFee\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [],\n },\n {\n type: \"function\",\n name: \"quoteTokenFee\",\n stateMutability: \"view\",\n inputs: [\n {\n name: \"req\",\n type: \"tuple\",\n components: [\n { name: \"token\", type: \"address\" },\n { name: \"receiver\", type: \"address\" },\n { name: \"brokerHash\", type: \"bytes32\" },\n { name: \"totalAmount\", type: \"uint128\" },\n { name: \"maxFee\", type: \"uint128\" },\n ],\n },\n ],\n outputs: [{ name: \"\", type: \"uint128\" }],\n },\n] as const;\n\n/**\n * `Relay.DepositRequest` — the struct passed to `deposit()` and\n * `quoteTokenFee()`. The Relay pulls `totalAmount` of `token` from\n * `msg.sender`, computes a token-denominated fee (capped at `maxFee`)\n * to cover the LayerZero msg.value out of its ETH reserve, and forwards\n * `(totalAmount - tokenFee)` to Orderly Vault on behalf of `receiver`.\n */\nexport interface OrderlyRelayDepositRequest {\n /** ERC-20 to deposit (must be registered + enabled on the Relay). */\n token: Address;\n /** Orderly account owner — typically the user's EOA. */\n receiver: Address;\n /** Orderly broker hash (e.g. `BROKER_HASHES.woofi_pro`). */\n brokerHash: Hex;\n /** Total amount the user is sending to the Relay (raw token units, uint128). */\n totalAmount: bigint;\n /** Max acceptable token fee — slippage cap on the Relay's USD-pricing. */\n maxFee: bigint;\n}\n\nexport interface BuildPerpDepositViaRelayParams {\n /** User EOA (msg.sender via EIP-7702 delegation). */\n userAddress: Address;\n /** ERC-4337 account nonce. */\n aaNonce: bigint;\n /** Relay contract address — `getContractAddresses(chainId).orderlyRelay`. */\n relayAddress: Address;\n /** Deposit request (token, receiver, brokerHash, totalAmount, maxFee). */\n request: OrderlyRelayDepositRequest;\n\n /**\n * Optional USDC (input-token) gas-fee transfer prepended to the batch.\n * The user holds USDC at the start of the batch, so the fee comes out\n * of the same input token — no second-token requirement. Set both\n * `gasFeeUsdcRecipient` and `gasFeeUsdc` together for sponsored\n * flows (PAFI gas reimbursement). Pass `0n` / `undefined` for the\n * fallback path where the user pays ERC-4337 gas in ETH directly.\n *\n * v0.7 — input-token fee position rule: user holds USDC BEFORE\n * deposit (token-availability), so charge there. Replaces the old\n * `gasFeePt` / `gasFeePtRecipient` / `pointTokenAddress` triple from\n * v0.6.\n */\n gasFeeUsdc?: bigint;\n gasFeeUsdcRecipient?: Address;\n\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build a UserOp for Orderly perp deposit via the PAFI Relay.\n *\n * Sponsored ops: `[USDC.transfer(feeRecipient, gasFeeUsdc), USDC.approve(relay, total), Relay.deposit(req)]`\n * Fallback ops: `[ USDC.approve(relay, total), Relay.deposit(req)]`\n *\n * No `msg.value` — the Relay covers LayerZero out of its own ETH reserve.\n *\n * Fee position rule: user holds USDC at start of batch → fee transfer\n * runs FIRST in the same token. User must hold `totalAmount + gasFeeUsdc`\n * USDC; net deposit to Orderly is `totalAmount - relayTokenFee`.\n */\nexport function buildPerpDepositViaRelay(\n params: BuildPerpDepositViaRelayParams,\n): PartialUserOperation {\n if (params.request.totalAmount <= 0n) {\n throw new Error(\"buildPerpDepositViaRelay: totalAmount must be positive\");\n }\n if (params.request.maxFee < 0n) {\n throw new Error(\"buildPerpDepositViaRelay: maxFee cannot be negative\");\n }\n if (!params.relayAddress) {\n throw new Error(\"buildPerpDepositViaRelay: relayAddress required\");\n }\n\n const operations: Operation[] = [];\n\n // Optional USDC (input-token) gas fee transfer — sponsored path.\n // Position: BEFORE approve+deposit, because user holds USDC at this\n // point in the batch (token-availability rule).\n if (params.gasFeeUsdc && params.gasFeeUsdc > 0n) {\n if (!params.gasFeeUsdcRecipient) {\n throw new Error(\n \"buildPerpDepositViaRelay: gasFeeUsdcRecipient required when gasFeeUsdc > 0\",\n );\n }\n operations.push(\n erc20TransferOp(\n params.request.token,\n params.gasFeeUsdcRecipient,\n params.gasFeeUsdc,\n ),\n );\n }\n\n // USDC.approve(relay, totalAmount) — Relay pulls via transferFrom.\n operations.push(\n erc20ApproveOp(\n params.request.token,\n params.relayAddress,\n params.request.totalAmount,\n ),\n );\n\n // Relay.deposit(req) — Relay charges tokenFee, deposits the rest to Orderly.\n const depositCallData: Hex = encodeFunctionData({\n abi: ORDERLY_RELAY_ABI,\n functionName: \"deposit\",\n args: [\n {\n token: params.request.token,\n receiver: params.request.receiver,\n brokerHash: params.request.brokerHash,\n totalAmount: params.request.totalAmount,\n maxFee: params.request.maxFee,\n },\n ],\n });\n operations.push(rawCallOp(params.relayAddress, depositCallData));\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 800_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import type { Address, Hex } from \"viem\";\nexport { ENTRY_POINT_V07, ENTRY_POINT_V08 } from \"../constants\";\n\n/**\n * A single call inside a batch. `BatchExecutor.execute(Call[])` iterates\n * and invokes each one. When the batch runs via EIP-7702 delegation,\n * `msg.sender` for each call is the user's EOA.\n */\nexport interface Operation {\n target: Address;\n value: bigint;\n data: Hex;\n}\n\n/**\n * Paymaster fields attached to a UserOperation. Populated by the\n * PAFI sponsor-relayer (via PAFI Backend proxy) before the user signs.\n */\nexport interface PaymasterFields {\n paymaster: Address;\n paymasterData: Hex;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n}\n\n/**\n * Partial UserOp used during preparation — before paymaster fields are\n * attached or the user signs.\n */\nexport interface PartialUserOperation {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n}\n\n/**\n * Full ERC-4337 v0.7 UserOperation, ready for bundler submission.\n */\nexport interface UserOperation extends PartialUserOperation {\n paymaster: Address;\n paymasterData: Hex;\n paymasterVerificationGasLimit: bigint;\n paymasterPostOpGasLimit: bigint;\n signature: Hex;\n}\n\n/**\n * Receipt returned by a bundler after a UserOp lands on-chain.\n */\nexport interface UserOpReceipt {\n userOpHash: Hex;\n success: boolean;\n txHash: Hex;\n blockNumber: bigint;\n gasUsed: bigint;\n /** Effective gas cost paid (wei). */\n actualGasCost: bigint;\n}\n\n/**\n * Sentinel operation value used in tests + docs when `Operation.value`\n * is irrelevant (ERC-20 transfers, for example).\n */\nexport const ZERO_VALUE = 0n;\n","import type { Address, Hex } from \"viem\";\n\n/**\n * Serialize a fully assembled ERC-4337 v0.7 UserOperation into the\n * JSON-RPC wire format expected by `eth_sendUserOperation`.\n *\n * All numeric fields (nonce, gas limits, fees) are converted from bigint\n * to 0x-prefixed hex strings. Optional paymaster fields are included when\n * present, otherwise set to null.\n *\n * Use this on the **backend** (mobile submit path) right before calling\n * `PafiBackendClient.relayUserOperation()`.\n */\nexport function serializeUserOpToJsonRpc(\n userOp: {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n paymaster?: Address;\n paymasterVerificationGasLimit?: bigint;\n paymasterPostOpGasLimit?: bigint;\n paymasterData?: Hex;\n },\n signature: Hex,\n): Record<string, string | null> {\n const p = userOp;\n return {\n sender: p.sender,\n nonce: `0x${p.nonce.toString(16)}`,\n factory: null,\n factoryData: null,\n callData: p.callData,\n callGasLimit: `0x${p.callGasLimit.toString(16)}`,\n verificationGasLimit: `0x${p.verificationGasLimit.toString(16)}`,\n preVerificationGas: `0x${p.preVerificationGas.toString(16)}`,\n maxFeePerGas: `0x${p.maxFeePerGas.toString(16)}`,\n maxPriorityFeePerGas: `0x${p.maxPriorityFeePerGas.toString(16)}`,\n paymaster: p.paymaster ?? null,\n paymasterData: p.paymasterData ?? null,\n paymasterVerificationGasLimit:\n p.paymasterVerificationGasLimit != null\n ? `0x${p.paymasterVerificationGasLimit.toString(16)}`\n : null,\n paymasterPostOpGasLimit:\n p.paymasterPostOpGasLimit != null\n ? `0x${p.paymasterPostOpGasLimit.toString(16)}`\n : null,\n signature,\n };\n}\n","import {\n concat,\n hashTypedData,\n pad,\n toHex,\n type Address,\n type Hex,\n type TypedDataDomain,\n} from \"viem\";\nimport { ENTRY_POINT_V08 } from \"./types\";\n\nconst PACKED_USER_OPERATION_TYPES = {\n PackedUserOperation: [\n { name: \"sender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"initCode\", type: \"bytes\" },\n { name: \"callData\", type: \"bytes\" },\n { name: \"accountGasLimits\", type: \"bytes32\" },\n { name: \"preVerificationGas\", type: \"uint256\" },\n { name: \"gasFees\", type: \"bytes32\" },\n { name: \"paymasterAndData\", type: \"bytes\" },\n ],\n} as const;\n\nexport type PackedUserOperationMessage = {\n sender: Address;\n nonce: bigint;\n initCode: Hex;\n callData: Hex;\n accountGasLimits: Hex;\n preVerificationGas: bigint;\n gasFees: Hex;\n paymasterAndData: Hex;\n};\n\nexport type UserOpTypedData = {\n domain: TypedDataDomain;\n types: typeof PACKED_USER_OPERATION_TYPES;\n primaryType: \"PackedUserOperation\";\n message: PackedUserOperationMessage;\n};\n\n/**\n * Build the EIP-712 typed-data payload for an ERC-4337 v0.8 UserOp.\n *\n * The deployed Pimlico `Simple7702Account` (impl `0xe6Cae8...`) validates\n * the user's signature by calling `SignatureCheckerLib.isValidSignatureNow`\n * with the **raw** userOpHash (no EIP-191 prefix). For an EOA signer this\n * means `ecrecover(userOpHash, sig)` must equal the EOA address.\n *\n * Because `userOpHash` is itself the EIP-712 typed digest of the\n * `PackedUserOperation` struct, signing the typed data with\n * `eth_signTypedData_v4` produces a signature whose recover-from-raw-digest\n * == the userOpHash. That matches what the contract expects.\n *\n * Do NOT sign with `personal_sign` / `signMessage({ raw })` — that adds the\n * EIP-191 prefix, which the contract does not undo, so recovery returns a\n * different address and the bundler reverts with `AA24 signature error`.\n */\nexport function buildUserOpTypedData(\n userOp: {\n sender: Address;\n nonce: bigint;\n callData: Hex;\n callGasLimit: bigint;\n verificationGasLimit: bigint;\n preVerificationGas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n paymaster?: Address;\n paymasterVerificationGasLimit?: bigint;\n paymasterPostOpGasLimit?: bigint;\n paymasterData?: Hex;\n },\n chainId: number,\n): UserOpTypedData {\n const accountGasLimits = pack128(\n userOp.verificationGasLimit,\n userOp.callGasLimit,\n );\n const gasFees = pack128(userOp.maxPriorityFeePerGas, userOp.maxFeePerGas);\n\n const paymasterAndData: Hex = userOp.paymaster\n ? concat([\n userOp.paymaster,\n pad(toHex(userOp.paymasterVerificationGasLimit ?? 0n), { size: 16 }),\n pad(toHex(userOp.paymasterPostOpGasLimit ?? 0n), { size: 16 }),\n (userOp.paymasterData ?? \"0x\") as Hex,\n ])\n : \"0x\";\n\n return {\n domain: {\n name: \"ERC4337\",\n version: \"1\",\n chainId,\n verifyingContract: ENTRY_POINT_V08,\n },\n types: PACKED_USER_OPERATION_TYPES,\n primaryType: \"PackedUserOperation\",\n message: {\n sender: userOp.sender,\n nonce: userOp.nonce,\n initCode: \"0x\" as Hex,\n callData: userOp.callData,\n accountGasLimits,\n preVerificationGas: userOp.preVerificationGas,\n gasFees,\n paymasterAndData,\n },\n };\n}\n\n/**\n * EIP-712 typed digest of an ERC-4337 v0.8 UserOp. Equals on-chain\n * `EntryPoint.getUserOpHash(userOp)`.\n */\nexport function computeUserOpHash(\n userOp: Parameters<typeof buildUserOpTypedData>[0],\n chainId: number,\n): Hex {\n const td = buildUserOpTypedData(userOp, chainId);\n return hashTypedData(td);\n}\n\nfunction pack128(hi: bigint, lo: bigint): Hex {\n return `0x${((hi << 128n) | lo).toString(16).padStart(64, \"0\")}` as Hex;\n}\n","import { type Address, type Hex, getAddress } from \"viem\";\n\n/**\n * EIP-7702 delegate impls supported by the PAFI mobile prepare/submit\n * flow. Each impl exposes `executeBatch((address,uint256,bytes)[])`\n * (selector `0x34fcd5be`) so callData encoding is identical, but each\n * may use a slightly different dummy-signature pattern that Pimlico's\n * `pm_sponsorUserOperation` simulation accepts.\n *\n * Current primary impl is `simple7702` (Pimlico's `Simple7702Account`).\n * `batchExecutor` is retained for transition / back-compat with EOAs\n * that delegated to the earlier Coinbase Smart Wallet v2 BatchExecutor\n * (trialled before v1.4 — Pimlico became the canonical impl on\n * 2026-04-27 due to a Coinbase SignatureWrapper incompatibility that\n * caused AA23 0x3c10b94e during validateUserOp).\n */\nexport type DelegateImpl =\n | \"simple7702\" // Pimlico's `to7702SimpleSmartAccount` impl — current\n | \"batchExecutor\" // Legacy Coinbase Smart Wallet v2 BatchExecutor — transitional\n | \"unknown\";\n\n/**\n * Pimlico's `Simple7702Account` implementation address on Base mainnet —\n * the canonical PAFI delegation target as of v1.4 (2026-04-27).\n * Used by `permissionless.to7702SimpleSmartAccount`.\n */\nexport const SIMPLE_7702_IMPL_BASE_MAINNET =\n \"0xe6Cae83BdE06E4c305530e199D7217f42808555B\" as Address;\n\n/**\n * Legacy Coinbase Smart Wallet v2 BatchExecutor — PAFI's pre-v1.4\n * delegation target. Same on Base mainnet + Base Sepolia. Detected\n * here so EOAs that delegated to this address before the v1.4 cutover\n * still pass the impl check; new delegations should target\n * {@link SIMPLE_7702_IMPL_BASE_MAINNET} instead.\n */\nexport const BATCH_EXECUTOR_7702_IMPL =\n \"0x7702cb554e6bFb442cb743A7dF23154544a7176C\" as Address;\n\n/**\n * Standard ERC-4337 v0.7 ECDSA dummy signature — 65 bytes that\n * are well-formed (so signature recovery doesn't crash) but\n * obviously invalid (so they can't accidentally authorize a real\n * tx). Both Simple7702 and BatchExecutor accept this pattern as\n * the \"estimating\" signature during paymaster simulation.\n *\n * Source: viem-account-abstraction's default; matches what\n * `permissionless.toSimpleSmartAccount` and `to7702SimpleSmartAccount`\n * use for `getStubSignature()`.\n */\nexport const DUMMY_SIGNATURE_V07: Hex =\n \"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c\";\n\n/**\n * Map an EIP-7702 delegate target address to its `DelegateImpl` kind.\n * Returns `'unknown'` when the address isn't a recognised PAFI-supported\n * impl — caller should reject or fall back to a default behaviour.\n */\nexport function detectDelegateImpl(delegate: Address | null | undefined): DelegateImpl {\n if (!delegate) return \"unknown\";\n const addr = getAddress(delegate).toLowerCase();\n if (addr === SIMPLE_7702_IMPL_BASE_MAINNET.toLowerCase()) return \"simple7702\";\n if (addr === BATCH_EXECUTOR_7702_IMPL.toLowerCase()) return \"batchExecutor\";\n return \"unknown\";\n}\n\n/**\n * Return a dummy signature appropriate for a given delegate impl. Used\n * by sponsor-relayer's `pm_sponsorUserOperation` forwarding so Pimlico\n * can simulate validateUserOp without the user's actual signature\n * (which is supplied later via `personal_sign(userOpHash)`).\n *\n * Currently both Simple7702 and BatchExecutor use the same v0.7 ECDSA\n * dummy. Kept impl-keyed so future impls (Safe, Kernel, Biconomy) can\n * supply their own pattern (e.g. ERC-1271 stubs) without forcing a\n * sponsor-relayer redeploy.\n */\nexport function getDummySignatureFor7702(impl: DelegateImpl): Hex {\n // Same dummy works for both impls — both use ECDSA recovery on\n // userOpHash, both accept the v0.7 standard stub.\n void impl;\n return DUMMY_SIGNATURE_V07;\n}\n","import type { PaymasterConfig } from \"./types\";\n\n/**\n * @deprecated Since v0.7.1 — module-level paymaster config is unused\n * in production. The actual paymaster path runs through\n * `@pafi-dev/issuer/PafiBackendClient` (instantiated per-issuer with\n * its own config). Slated for removal in the next major bump (v1.0);\n * still exported through the v0.x line for back-compat. Migrate by\n * passing `PafiBackendClient` directly into your issuer adapter /\n * handler.\n */\nlet _config: PaymasterConfig | null = null;\n\nlet _deprecationWarned = false;\nfunction warnDeprecated(fn: string): void {\n if (_deprecationWarned) return;\n _deprecationWarned = true;\n // eslint-disable-next-line no-console\n console.warn(\n `[PAFI] DEPRECATION: \\`${fn}\\` from @pafi-dev/core/paymaster has been ` +\n \"deprecated since v0.7.1 and will be removed in the next major bump \" +\n \"(v1.0). Use `PafiBackendClient` from @pafi-dev/issuer/pafi-backend \" +\n \"instead.\",\n );\n}\n\n/**\n * @deprecated v0.7.1 — see file comment.\n *\n * Set the application-wide paymaster config. Safe to call multiple\n * times (later calls override earlier). Throws if required fields\n * are missing.\n */\nexport function setPaymasterConfig(config: PaymasterConfig): void {\n warnDeprecated(\"setPaymasterConfig\");\n if (!config.pafiBackendUrl) {\n throw new Error(\"setPaymasterConfig: pafiBackendUrl is required\");\n }\n if (!config.issuerId) {\n throw new Error(\"setPaymasterConfig: issuerId is required\");\n }\n if (!config.apiKey) {\n throw new Error(\"setPaymasterConfig: apiKey is required\");\n }\n if (!config.feeRecipient) {\n throw new Error(\"setPaymasterConfig: feeRecipient is required\");\n }\n _config = { ...config };\n}\n\n/**\n * @deprecated v0.7.1 — see file comment.\n */\nexport function getPaymasterConfig(): PaymasterConfig {\n warnDeprecated(\"getPaymasterConfig\");\n if (!_config) {\n throw new Error(\n \"PaymasterConfig not initialized — call setPaymasterConfig() at application boot before invoking any batch builder\",\n );\n }\n return _config;\n}\n\n/** Test helper — clear the singleton. */\nexport function _resetPaymasterConfigForTests(): void {\n _config = null;\n}\n\n/** Check whether paymaster config has been initialized. */\nexport function isPaymasterConfigured(): boolean {\n return _config !== null;\n}\n","import type { Address, PublicClient } from \"viem\";\n\n/**\n * Submission path chosen by `checkEthAndBranch`.\n * - `normal`: initiator has enough ETH; submit via `walletClient.writeContract`\n * or a plain `eth_sendRawTransaction`. No paymaster round-trip.\n * - `paymaster`: initiator doesn't have enough ETH; wrap the batch as a\n * UserOperation and route through PAFI Backend → PAFI sponsor-relayer\n * → Bundler.\n */\nexport type SubmissionPath = \"normal\" | \"paymaster\";\n\nexport interface CheckEthAndBranchParams {\n /** viem PublicClient bound to the target chain. */\n client: PublicClient;\n /** The address whose ETH balance we check. */\n initiator: Address;\n /** Estimated gas cost in wei for the upcoming tx. */\n estimatedGasWei: bigint;\n /**\n * Optional safety margin multiplier (basis points). Defaults to\n * 11_000 (110%) — the initiator needs 10% above the estimate to\n * qualify for the normal path. Prevents edge cases where gas price\n * spikes between estimation and submission cause a \"has enough\"\n * decision to fail at broadcast time.\n */\n marginBps?: number;\n}\n\nconst DEFAULT_MARGIN_BPS = 11_000;\n\n/**\n * Step 3 of the Generalized Flow ([SPONSORED_PATH_FLOW.md §2]):\n * choose between the normal path (initiator pays ETH directly) and the\n * paymaster path (bundler + PAFI sponsor-relayer).\n *\n * Intentionally synchronous in spirit — the only network call is\n * `getBalance`. Callers can parallelize it with other reads.\n */\nexport async function checkEthAndBranch(\n params: CheckEthAndBranchParams,\n): Promise<SubmissionPath> {\n const marginBps = params.marginBps ?? DEFAULT_MARGIN_BPS;\n const required =\n (params.estimatedGasWei * BigInt(marginBps)) / 10_000n;\n\n const balance = await params.client.getBalance({\n address: params.initiator,\n });\n\n return balance >= required ? \"normal\" : \"paymaster\";\n}\n","import type { Address, Hex, PublicClient } from \"viem\";\n\n/**\n * EIP-7702 delegation designator prefix: 0xef0100 + 20-byte implementation address.\n *\n * When an EOA has been delegated via EIP-7702, `eth_getCode` returns bytecode\n * that starts with this magic prefix followed by the 20-byte address of the\n * implementation contract (BatchExecutor).\n *\n * References: EIP-7702 §4.2 — \"delegation designator\"\n */\nconst EIP7702_MAGIC = \"0xef0100\" as const;\n\n/**\n * Parse the implementation address out of an EIP-7702 delegation designator.\n *\n * Returns `null` when:\n * - `code` is undefined / empty / `\"0x\"` (plain EOA, no code)\n * - `code` does not contain the EIP-7702 magic prefix (regular contract)\n *\n * @param code - bytecode returned by `eth_getCode` / `client.getCode()`\n * @returns the 20-byte implementation address (checksummed), or `null`\n *\n * @example\n * const code = await client.getCode({ address });\n * const impl = parseEip7702DelegatedAddress(code);\n * // null → not delegated\n * // '0x7702cb554e6bFb442cb743A7dF23154544a7176C' → delegated to BatchExecutor\n */\nexport function parseEip7702DelegatedAddress(\n code: Hex | string | null | undefined,\n): Address | null {\n if (!code || code === \"0x\" || code === \"0x0\") return null;\n const normalized = code.toLowerCase();\n const magic = EIP7702_MAGIC.toLowerCase();\n // Strict prefix + exact-length check per EIP-7702 §4.2. Bytecode of\n // a delegated EOA is exactly 23 bytes (`0xef0100` || 20-byte impl)\n // → 40 hex chars AFTER the magic prefix. Substring search would\n // false-positive on regular contract bytecode containing `ef0100`\n // mid-stream.\n if (!normalized.startsWith(magic)) return null;\n if (normalized.length !== magic.length + 40) return null;\n return `0x${normalized.slice(magic.length)}` as Address;\n}\n\n/**\n * Read the EIP-7702 delegation status of an EOA from the chain.\n *\n * @param client - viem PublicClient (any provider — only `eth_getCode` is called)\n * @param address - EOA address to inspect\n * @returns the implementation address the EOA is delegated to, or `null`\n *\n * @example\n * const impl = await checkDelegation(publicClient, userAddress);\n * if (impl === null) {\n * // show \"Setup Wallet\" button\n * } else {\n * // EOA already delegated; safe to send UserOps\n * }\n */\nexport async function checkDelegation(\n client: PublicClient,\n address: Address,\n): Promise<Address | null> {\n const code = await client.getCode({ address });\n return parseEip7702DelegatedAddress(code);\n}\n\n/**\n * Return `true` when the EOA at `address` is currently delegated to `target`.\n *\n * Useful for asserting that the delegation points specifically at the expected\n * BatchExecutor rather than some other implementation (e.g. old deployment).\n *\n * @example\n * import { BATCH_EXECUTOR_ADDRESS_BASE_MAINNET } from '@pafi-dev/core';\n * const ok = await isDelegatedTo(client, userAddress, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET);\n */\nexport async function isDelegatedTo(\n client: PublicClient,\n address: Address,\n target: Address,\n): Promise<boolean> {\n const impl = await checkDelegation(client, address);\n if (!impl) return false;\n return impl.toLowerCase() === target.toLowerCase();\n}\n","import type { Address, PublicClient } from \"viem\";\nimport type { PartialUserOperation } from \"../userop/types\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport { ENTRY_POINT_V08 } from \"../constants\";\n\n/**\n * Parameters for building a delegation-only UserOperation.\n *\n * This UserOp carries no calldata — its sole purpose is to anchor the\n * EIP-7702 authorization (signed externally via `signAuthorization`) into\n * a sponsored transaction so the user doesn't need native ETH to delegate.\n */\nexport interface BuildDelegationUserOpParams {\n /** User EOA to delegate. */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint. Pass 0n on first ever op. */\n aaNonce: bigint;\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build the minimal `PartialUserOperation` used to sponsor the one-time\n * EIP-7702 delegation.\n *\n * The caller must:\n * 1. Sign the EIP-7702 authorization via `signAuthorization()` (Privy hook).\n * 2. Pass the authorization as `authorization` alongside `calls` (or alone)\n * to `smartClient.sendTransaction()`.\n *\n * The permissionless SDK + Pimlico bundler handle the rest: they detect the\n * `authorization` field and submit an EIP-7702 type-4 transaction that sets\n * the EOA's bytecode to `0xef0100<batchExecutorAddress>`.\n *\n * This builder is a convenience wrapper — in practice you can also pass\n * `{ to: userAddress, value: 0n, data: '0x', authorization }` directly to\n * `smartClient.sendTransaction()` without calling this function at all.\n * Use it when you need a `PartialUserOperation` struct for inspection or\n * custom paymaster flows.\n *\n * @example\n * // Typical flow — no need to call this builder directly:\n * const nonce = await publicClient.getTransactionCount({ address, blockTag: 'pending' });\n * const authorization = await signAuthorization({ contractAddress: BATCH_EXECUTOR, chainId: 8453, nonce });\n * const txHash = await smartClient.sendTransaction({\n * to: address,\n * value: 0n,\n * data: '0x',\n * authorization,\n * paymasterContext: { sponsorshipPolicyId },\n * });\n */\nexport function buildDelegationUserOp(\n params: BuildDelegationUserOpParams,\n): PartialUserOperation {\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations: [\n {\n // Self-call with no data — triggers EIP-7702 delegation without\n // executing any inner logic. The BatchExecutor.execute([]) call with\n // an empty array would revert, so we target the EOA itself (which\n // forwards to BatchExecutor that then no-ops on empty input).\n target: params.userAddress,\n value: 0n,\n data: \"0x\",\n },\n ],\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 50_000n,\n verificationGasLimit: params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n\n/**\n * Fetch the AA nonce for a user EOA from the EntryPoint v0.7.\n *\n * Convenience helper so callers don't need to import the EntryPoint ABI\n * themselves when building the delegation UserOp.\n *\n * @param client - viem PublicClient\n * @param userAddress - EOA to query\n * @returns bigint nonce (0n on first-ever UserOp)\n */\nexport async function getAaNonce(\n client: PublicClient,\n userAddress: Address,\n): Promise<bigint> {\n const NONCE_ABI = [\n {\n inputs: [\n { name: \"sender\", type: \"address\" },\n { name: \"key\", type: \"uint192\" },\n ],\n name: \"getNonce\",\n outputs: [{ name: \"nonce\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n return client.readContract({\n address: ENTRY_POINT_V08,\n abi: NONCE_ABI,\n functionName: \"getNonce\",\n args: [userAddress, 0n],\n });\n}\n","import { concat, keccak256, toRlp, type Address, type Hex } from \"viem\";\n\n/**\n * EIP-7702 authorization tuple hash.\n *\n * keccak256(0x05 || rlp([chain_id, address, nonce]))\n *\n * The user signs this hash with a **raw secp256k1 sign** (no EIP-191 prefix).\n * On mobile, pass the result to the wallet's raw signing primitive.\n *\n * The resulting 65-byte signature is sent to `POST /delegate/submit` as `authSig`.\n *\n * Reference: EIP-7702 §3 — Authorization tuple\n */\nexport function computeAuthorizationHash(\n chainId: number,\n address: Address,\n nonce: bigint,\n): Hex {\n const rlpEncoded = toRlp([\n toMinimalHex(BigInt(chainId)),\n address,\n toMinimalHex(nonce),\n ]);\n return keccak256(concat([\"0x05\", rlpEncoded]));\n}\n\n/**\n * Check whether an EOA code string carries an EIP-7702 delegation to `target`.\n *\n * Sync alternative to `isDelegatedTo()` for callers that already have the\n * code from a prior `eth_getCode` call and don't want another RPC round-trip.\n *\n * Delegation designator format: 0xef0100 (3 bytes) || address (20 bytes)\n */\nexport function isDelegatedToTarget(\n code: string | null | undefined,\n target: Address,\n): boolean {\n if (!code || code === \"0x\") return false;\n const expected = `0xef0100${target.slice(2).toLowerCase()}`;\n return code.toLowerCase() === expected;\n}\n\n/** Minimal-length big-endian hex for RLP integer encoding (no leading zeros). */\nfunction toMinimalHex(n: bigint): Hex {\n if (n === 0n) return \"0x\";\n const hex = n.toString(16);\n return `0x${hex.length % 2 === 0 ? hex : \"0\" + hex}` as Hex;\n}\n","import type { Address, Hex } from \"viem\";\n\n/**\n * EIP-7702 authorization tuple in the JSON-RPC wire format that bundlers\n * (Pimlico, Stackup, etc.) accept on `eth_sendUserOperation`. All\n * numeric fields are 0x-prefixed hex strings.\n *\n * Constructed from the user's secp256k1 signature over\n * `keccak256(0x05 || rlp([chainId, address, nonce]))` — see\n * `computeAuthorizationHash`.\n */\nexport interface Eip7702AuthorizationJsonRpc {\n chainId: Hex;\n address: Address;\n nonce: Hex;\n r: Hex;\n s: Hex;\n yParity: Hex;\n}\n\n/**\n * Split a serialized 65-byte ECDSA signature (`r || s || v`) into the\n * `{ r, s, yParity }` triple required by EIP-7702 authorization tuples\n * and EIP-1559+ transactions.\n *\n * Accepts the legacy `v ∈ {27, 28}` form and converts to `yParity ∈ {0, 1}`\n * automatically. Already-normalized `v ∈ {0, 1}` passes through unchanged.\n *\n * @throws when the signature is not 65 bytes (130 hex chars).\n */\nexport function splitAuthorizationSig(authSig: Hex | string): {\n r: Hex;\n s: Hex;\n yParity: 0 | 1;\n} {\n const raw = authSig.startsWith(\"0x\")\n ? authSig.slice(2)\n : authSig;\n if (raw.length !== 130) {\n throw new Error(\n `splitAuthorizationSig: expected 65-byte signature (130 hex chars), got ${raw.length}`,\n );\n }\n const r = `0x${raw.slice(0, 64)}` as Hex;\n const s = `0x${raw.slice(64, 128)}` as Hex;\n const v = parseInt(raw.slice(128, 130), 16);\n const yParity: 0 | 1 = v === 27 ? 0 : v === 28 ? 1 : (v as 0 | 1);\n if (yParity !== 0 && yParity !== 1) {\n throw new Error(\n `splitAuthorizationSig: invalid recovery byte ${v} (expected 0/1/27/28)`,\n );\n }\n return { r, s, yParity };\n}\n\n/**\n * Build the JSON-RPC EIP-7702 authorization tuple from raw fields and a\n * 65-byte secp256k1 signature.\n *\n * The `authSig` is the user's signature over `computeAuthorizationHash(\n * chainId, address, nonce )` — typically obtained via\n * `wallet.signAuthorization(...)` on the client.\n */\nexport function buildEip7702Authorization(params: {\n chainId: number;\n address: Address;\n nonce: bigint;\n authSig: Hex | string;\n}): Eip7702AuthorizationJsonRpc {\n const { r, s, yParity } = splitAuthorizationSig(params.authSig);\n return {\n chainId: `0x${params.chainId.toString(16)}` as Hex,\n address: params.address,\n nonce: `0x${params.nonce.toString(16)}` as Hex,\n r,\n s,\n yParity: `0x${yParity}` as Hex,\n };\n}\n","import type { Address } from \"viem\";\n\n/**\n * Per-chain deployed contract addresses — v1.6 flow.\n *\n * ## Status (2026-05-07)\n *\n * Base mainnet (8453): v1.6 redeploy. PAFIHook removed entirely — fee on\n * mint now happens via `MintFeeWrapper` (single global instance, multi-PT).\n * `pafiHook` field kept as placeholder for back-compat with consumers that\n * still reference it; set to a deterministic dead address to make misuse\n * obvious.\n *\n * Base Sepolia (84532): entire row is placeholder — not in active use.\n *\n * ## What lives where\n *\n * pointToken — DEAD legacy field (per-issuer, not chain-level).\n * Each issuer's clone is configured via env or\n * resolved from PointTokenFactory at runtime. Set\n * to a deterministic dead address so misuse fails\n * loudly. Will be removed when downstream consumers\n * stop referencing it.\n * batchExecutor — EIP-7702 delegation target (Pimlico Simple7702Account)\n * usdt — MockERC20 used by Uniswap pools\n * issuerRegistry — registry of all issuers on this chain\n * mintingOracle — per-token mint cap enforcer (v1.6: per-token, not per-issuer)\n * mintFeeWrapper — v1.6 mint-time fee splitter (single global instance)\n * pafiHook — DEAD; v1.5 V4 swap fee removed in v1.6. Kept for ABI compat.\n *\n * PointTokenFactory + PointToken implementation addresses live in\n * separate exports below — they're only needed at provisioning /\n * observability time, not in the hot mint/burn path, so excluded from\n * the per-chain bundle.\n */\nexport interface ContractAddresses {\n pointToken: Address;\n batchExecutor: Address;\n usdt: Address;\n issuerRegistry: Address;\n mintingOracle: Address;\n /**\n * v1.6 — single-instance MintFeeWrapper that skims a fee on every\n * sig-gated mint and distributes across the registered recipient\n * list for the target PointToken. Issuers route mints through this\n * by passing `mintFeeWrapperAddress` to `prepareMint`.\n */\n mintFeeWrapper: Address;\n /**\n * @deprecated v1.5 PAFIHook (10% PT→USDT swap fee) was removed in\n * v1.6. Field kept as a dead placeholder so older consumers don't\n * crash on missing-property errors; do not use for new code.\n */\n pafiHook: Address;\n /** Chainlink ETH/USD price feed — used by FeeManager to convert gas cost to USDT. */\n chainlinkEthUsd: Address;\n /**\n * Orderly perp-deposit Relay — holds an ETH reserve to cover the\n * LayerZero msg.value, charges a USDC token-fee reimbursement.\n * Lets perp deposits ride the ERC-4337 sponsored gas path without\n * the user holding ETH for msg.value.\n */\n orderlyRelay: Address;\n /**\n * PAFI fee recipient — receives PT gas-reimbursement transfers from\n * the user on the sponsored path of every scenario (mint, burn,\n * swap, perp deposit). This is PAFI-controlled, NOT issuer-controlled,\n * because PAFI pays the ERC-4337 gas via the paymaster — issuers\n * shouldn't be able to redirect this fee to themselves.\n */\n pafiFeeRecipient: Address;\n /** Uniswap V4 UniversalRouter — swap entry point for the swap handler. */\n universalRouter: Address;\n}\n\nconst PLACEHOLDER_DEAD = (suffix: string): Address =>\n `0x000000000000000000000000000000000000${suffix.toLowerCase().padStart(4, \"0\")}` as Address;\n\nexport const CONTRACT_ADDRESSES: Record<number, ContractAddresses> = {\n // Base mainnet — v1.6 redeploy (2026-05-07)\n // registry: IssuerRegistry 0xAB1d1e117c41636f30bb10194Fe6B774B6Da9E01\n // factory: PointTokenFactory 0xA08274458b43E7D6F4ff61ddFe8A9852c6531085\n // oracle: MintingOracle 0x2f4cf8C5F8b41efC970c5b46a5d905CeA1f871a0\n // tokenImpl: PointToken (impl) 0xc41c3F8A0380c7760Ee1209d6d19C4b81dE994e4\n // mintFeeWrapper: MintFeeWrapper 0xD324EE2e3220B23d1b1BfbB85f5bC1EF2E917B93\n // mockUsdt: MockERC20 0x3F7e71B150e97316Bb9f363A32c19CcD36ac2382\n // batchExecutor: Pimlico Simple7702 0xe6Cae83BdE06E4c305530e199D7217f42808555B (unchanged from v1.5)\n //\n // pointToken: PER-ISSUER, not chain-level. Each issuer deploys their\n // own clone via PointTokenFactory.createToken() and tracks the address\n // separately (env var, DB, or factory readout). This field is a\n // historical leftover from v1.4 single-issuer days and has no SDK\n // consumer — kept as dead-zero so any code that mistakenly reads it\n // fails loudly instead of silently routing to a stale token.\n // Known clones (informational, NOT to be used as a default):\n // gg56 (Test Point / TPT) — 0x855c2046AD49AcF9B3B32557176FfCB1a1A38A22\n 8453: {\n pointToken: PLACEHOLDER_DEAD(\"dead\"),\n batchExecutor: \"0xe6Cae83BdE06E4c305530e199D7217f42808555B\",\n usdt: \"0x3F7e71B150e97316Bb9f363A32c19CcD36ac2382\",\n issuerRegistry: \"0xAB1d1e117c41636f30bb10194Fe6B774B6Da9E01\",\n mintingOracle: \"0x2f4cf8C5F8b41efC970c5b46a5d905CeA1f871a0\",\n mintFeeWrapper: \"0xD324EE2e3220B23d1b1BfbB85f5bC1EF2E917B93\",\n pafiHook: PLACEHOLDER_DEAD(\"dead\"),\n chainlinkEthUsd: \"0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70\",\n orderlyRelay: \"0xDA082DAce1522c185aeB5A713FcA6fa6B6E99e7f\",\n pafiFeeRecipient: \"0xa3F71eadEd101513a0151007590020dCFD7C495e\",\n universalRouter: \"0x6fF5693b99212Da76ad316178A184AB56D299b43\",\n },\n // Base Sepolia — not in active use; placeholders kept so the map\n // compiles for tooling that enumerates chains.\n 84532: {\n pointToken: PLACEHOLDER_DEAD(\"dead\"),\n batchExecutor: PLACEHOLDER_DEAD(\"de01\"),\n usdt: PLACEHOLDER_DEAD(\"dead\"),\n issuerRegistry: PLACEHOLDER_DEAD(\"dead\"),\n mintingOracle: PLACEHOLDER_DEAD(\"dead\"),\n mintFeeWrapper: PLACEHOLDER_DEAD(\"dead\"),\n pafiHook: PLACEHOLDER_DEAD(\"dead\"),\n chainlinkEthUsd: PLACEHOLDER_DEAD(\"de02\"),\n orderlyRelay: PLACEHOLDER_DEAD(\"de03\"),\n pafiFeeRecipient: PLACEHOLDER_DEAD(\"de04\"),\n universalRouter: PLACEHOLDER_DEAD(\"de05\"),\n },\n};\n\n/**\n * PointTokenFactory address — separate from `ContractAddresses` because\n * it's only used at provisioning time (issuer onboard + token creation),\n * not in the hot mint/burn path.\n */\nexport const POINT_TOKEN_FACTORY_ADDRESSES: Record<number, Address> = {\n 8453: \"0xA08274458b43E7D6F4ff61ddFe8A9852c6531085\",\n 84532: PLACEHOLDER_DEAD(\"dead\"),\n};\n\n/**\n * PointToken implementation address — the EIP-1167 clone target used\n * by PointTokenFactory. Exposed for observability / proxy verification;\n * consumers should never call this directly.\n */\nexport const POINT_TOKEN_IMPL_ADDRESSES: Record<number, Address> = {\n 8453: \"0xc41c3F8A0380c7760Ee1209d6d19C4b81dE994e4\",\n 84532: PLACEHOLDER_DEAD(\"dead\"),\n};\n\n/**\n * Lookup helper — throws if the chain isn't in the map so callers fail\n * loudly on misconfiguration instead of silently using `undefined`.\n */\nexport function getContractAddresses(chainId: number): ContractAddresses {\n const addrs = CONTRACT_ADDRESSES[chainId];\n if (!addrs) {\n throw new Error(\n `getContractAddresses: no addresses for chainId ${chainId}. ` +\n `Supported: ${Object.keys(CONTRACT_ADDRESSES).join(\", \")}`,\n );\n }\n return addrs;\n}\n","import type {\n Address,\n Hex,\n PublicClient,\n WalletClient,\n TransactionReceipt,\n} from \"viem\";\nimport { getContractAddresses } from \"../contracts/real/addresses\";\nimport { parseEip7702DelegatedAddress } from \"./checkDelegation\";\n\n/**\n * Privy-style EIP-7702 authorization signer. Matches the shape returned\n * by `useSign7702Authorization()` from `@privy-io/react-auth` /\n * `@privy-io/expo`. Pass it via `params.signAuthorization` and the\n * helper takes care of the rest.\n *\n * The signer MUST be the user's Privy embedded wallet — external\n * wallets (MetaMask, WalletConnect, …) cannot produce raw secp256k1\n * EIP-7702 authorizations.\n */\nexport type SignAuthorizationFn = (args: {\n contractAddress: Address;\n chainId: number;\n nonce: number;\n}) => Promise<{\n contractAddress?: Address;\n address?: Address;\n chainId: number;\n nonce: number;\n r: Hex | string;\n s: Hex | string;\n // Privy returns `v` as bigint, viem types it as bigint, some SDKs as\n // string/number. Accept all and ignore — we use yParity directly.\n v?: bigint | string | number;\n // Privy returns 0 | 1 (number); some SDKs return '0x0' / '0x1' (hex\n // string). Accept both shapes — `delegateDirect` normalizes\n // internally.\n yParity: number | string;\n}>;\n\n/**\n * Authorization tuple in the shape `walletClient.sendTransaction`\n * expects on its `authorizationList` field. Mirrors viem's\n * `SignedAuthorization` so callers can also build it manually.\n */\nexport interface SignedAuthorization {\n contractAddress: Address;\n chainId: number;\n nonce: number;\n r: Hex;\n s: Hex;\n yParity: 0 | 1;\n}\n\nexport interface DelegateDirectParams {\n /** User EOA — must equal `walletClient.account.address`. */\n userAddress: Address;\n chainId: number;\n /** viem PublicClient — used for `getCode` + `getTransactionCount`. */\n publicClient: PublicClient;\n /** viem WalletClient (or any sender that exposes `sendTransaction`). */\n walletClient: WalletClient;\n /**\n * Privy hook that produces the EIP-7702 authorization signature.\n * Pass `useSign7702Authorization().signAuthorization` directly.\n */\n signAuthorization: SignAuthorizationFn;\n /**\n * Override the impl the EOA delegates to. Defaults to\n * `getContractAddresses(chainId).batchExecutor` (Pimlico\n * Simple7702Account on Base mainnet — the canonical PAFI delegate\n * target).\n */\n contractAddress?: Address;\n /**\n * When the user already has a 7702 delegation pointing at the\n * expected impl, skip the tx and return early. Default `true`.\n * Set `false` to force re-delegate even if status check passes.\n */\n skipIfAlreadyDelegated?: boolean;\n /**\n * Wait for the transaction receipt before returning. Default\n * `true` — caller usually wants to know \"delegation completed\"\n * before proceeding to claim/redeem flows.\n */\n waitForReceipt?: boolean;\n /** Optional onWarning hook for non-fatal warnings (logger surface). */\n onWarning?: (msg: string) => void;\n}\n\nexport interface DelegateDirectResult {\n /** `'sent'` when a tx was broadcast; `'already-delegated'` when skipped. */\n status: \"sent\" | \"already-delegated\";\n /** Transaction hash. `undefined` on `already-delegated`. */\n txHash?: Hex;\n /** Receipt — present when `waitForReceipt` AND status is `'sent'`. */\n receipt?: TransactionReceipt;\n /** EIP-7702 authorization tuple actually sent. */\n authorization: SignedAuthorization;\n /** Impl address user delegated to. */\n delegatedTo: Address;\n}\n\n/**\n * One-shot helper for the FE-direct EIP-7702 delegation path —\n * **no AA, no paymaster, no PAFI sponsor-relayer**. The user EOA\n * pays gas in ETH and broadcasts a single type-4 transaction with the\n * authorization attached.\n *\n * Use this when:\n * - The FE already has a Privy embedded wallet ready and the user\n * has a small ETH balance for gas (~$0.01–0.10 on Base).\n * - You don't want to depend on `permissionless` / Pimlico bundlers\n * / sponsor-relayer for the one-time delegation step.\n * - You're testing or running a self-hosted dev environment without\n * the full PAFI infra.\n *\n * Flow:\n * 1. Read on-chain code; short-circuit if already delegated to the\n * expected impl (`skipIfAlreadyDelegated`).\n * 2. Read EOA tx nonce (pending).\n * 3. Call `signAuthorization` (Privy hook) → r/s/yParity.\n * 4. Send EIP-7702 type-4 tx with `authorizationList: [auth]` and\n * `to: userAddress, data: '0x'` (no-op self-call; the work is\n * bundling the authorization).\n * 5. Wait for receipt (optional).\n *\n * Caller's `signAuthorization` MUST be wired to the user's Privy\n * embedded wallet — external wallets (MetaMask, …) do NOT support\n * raw secp256k1 EIP-7702 sign.\n *\n * @example\n * ```ts\n * import { useSign7702Authorization, useWallets } from \"@privy-io/react-auth\";\n * import { delegateDirect } from \"@pafi-dev/core\";\n * import { createWalletClient, custom } from \"viem\";\n * import { base } from \"viem/chains\";\n *\n * function DelegateButton() {\n * const { wallets } = useWallets();\n * const { signAuthorization } = useSign7702Authorization();\n * const wallet = wallets.find(w => w.walletClientType === \"privy\"); // embedded\n *\n * async function handleClick() {\n * const provider = await wallet.getEthereumProvider();\n * const walletClient = createWalletClient({\n * account: wallet.address,\n * chain: base,\n * transport: custom(provider),\n * });\n *\n * const result = await delegateDirect({\n * userAddress: wallet.address as `0x${string}`,\n * chainId: 8453,\n * publicClient,\n * walletClient,\n * signAuthorization,\n * });\n *\n * if (result.status === \"already-delegated\") {\n * console.log(\"Already delegated to\", result.delegatedTo);\n * } else {\n * console.log(\"Delegated! tx:\", result.txHash);\n * }\n * }\n * }\n * ```\n */\nexport async function delegateDirect(\n params: DelegateDirectParams,\n): Promise<DelegateDirectResult> {\n const target =\n params.contractAddress ??\n (getContractAddresses(params.chainId).batchExecutor as Address);\n\n // 1. Short-circuit if already delegated to the expected impl.\n if (params.skipIfAlreadyDelegated !== false) {\n const code = await params.publicClient.getCode({\n address: params.userAddress,\n });\n const current = parseEip7702DelegatedAddress(code);\n if (current && current.toLowerCase() === target.toLowerCase()) {\n // Build a no-op authorization placeholder for the response —\n // we didn't actually sign one because we skipped.\n return {\n status: \"already-delegated\",\n delegatedTo: current,\n authorization: {\n contractAddress: target,\n chainId: params.chainId,\n nonce: 0,\n r: \"0x\" as Hex,\n s: \"0x\" as Hex,\n yParity: 0,\n },\n };\n }\n }\n\n // 2. Read EOA tx nonce (pending — covers any in-flight sends).\n const nonce = await params.publicClient.getTransactionCount({\n address: params.userAddress,\n blockTag: \"pending\",\n });\n\n // 3. Sign authorization via Privy hook.\n const raw = await params.signAuthorization({\n contractAddress: target,\n chainId: params.chainId,\n nonce,\n });\n\n // Normalize to viem's SignedAuthorization shape. Privy returns\n // `yParity` as either `0/1` (number) or `'0x0'/'0x1'` (hex string)\n // depending on SDK version — handle both.\n const yParityRaw = raw.yParity;\n const yParityNum =\n typeof yParityRaw === \"number\"\n ? yParityRaw\n : String(yParityRaw) === \"1\" || String(yParityRaw) === \"0x1\"\n ? 1\n : 0;\n const yParity: 0 | 1 = yParityNum === 1 ? 1 : 0;\n\n const authorization: SignedAuthorization = {\n contractAddress: target,\n chainId: params.chainId,\n nonce,\n r: normalizeHex32(raw.r),\n s: normalizeHex32(raw.s),\n yParity,\n };\n\n // 4. Send EIP-7702 type-4 tx. viem auto-encodes when\n // `authorizationList` is supplied. Self-call (data: '0x') is a\n // no-op — the work is the authorization itself.\n const account = params.walletClient.account;\n if (!account) {\n throw new Error(\n \"delegateDirect: walletClient has no account attached — cannot send tx\",\n );\n }\n\n // Cast to bypass viem's strict generic chain inference; runtime\n // shape matches `EIP7702Transaction` regardless of declared chain.\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: \"0x\" as Hex,\n authorizationList: [authorization],\n })) as Hex;\n\n // 5. Wait for receipt (optional).\n const waitForReceipt = params.waitForReceipt !== false;\n let receipt: TransactionReceipt | undefined;\n if (waitForReceipt) {\n try {\n receipt = await params.publicClient.waitForTransactionReceipt({\n hash: txHash,\n });\n } catch (err) {\n params.onWarning?.(\n `delegateDirect: tx ${txHash} sent but receipt fetch failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return {\n status: \"sent\",\n txHash,\n receipt,\n authorization,\n delegatedTo: target,\n };\n}\n\n/**\n * Normalize a hex r/s component to exactly `0x` + 64 hex chars\n * (32 bytes). Privy occasionally returns less-than-32-byte values\n * when the leading byte is zero; viem's `authorizationList` expects\n * full-width hex.\n */\nfunction normalizeHex32(value: Hex | string | undefined): Hex {\n if (!value) return \"0x\" as Hex;\n const stripped = value.replace(/^0x/i, \"\");\n return (\"0x\" + stripped.padStart(64, \"0\")) as Hex;\n}\n","import { http } from \"viem\";\nimport type { HttpTransport } from \"viem\";\n\n/**\n * Parameters for `createPafiProxyTransport`.\n */\nexport interface PafiProxyTransportParams {\n /**\n * Full URL of the PAFI sponsor-relayer Pimlico proxy endpoint.\n * @example \"https://sponsor-relayer.pacificfinance.org/pimlico\"\n * @example \"http://localhost:4000/pimlico\"\n */\n proxyUrl: string;\n\n /**\n * Called on every request to get the current Privy identity token.\n * Use a getter (or a ref's `.current`) so the transport always sends\n * the latest token without needing to be rebuilt when it rotates.\n *\n * @example () => identityTokenRef.current\n * @example () => privyHook.identityToken\n */\n getIdentityToken: () => string | null | undefined;\n\n /**\n * Issuer ID sent as `X-Issuer-Id` header.\n * sponsor-relayer uses this to look up per-issuer rate limits and policy.\n * Obtain from PAFI team during onboarding.\n */\n issuerId: string;\n}\n\n/**\n * Create a viem `HttpTransport` that proxies all Pimlico JSON-RPC calls\n * through the PAFI sponsor-relayer (`POST /pimlico`).\n *\n * The transport:\n * - Sets `Authorization: Bearer <identityToken>` on every request\n * - Sets `X-Issuer-Id: <issuerId>` on every request\n * - Reads the identity token lazily via `getIdentityToken()` so it is\n * always fresh without rebuilding the SmartAccountClient on each rotation\n *\n * Pass the returned transport to both `createPimlicoClient` and\n * `createSmartAccountClient` so ALL Pimlico RPC calls (paymaster + bundler)\n * go through the proxy with auth headers attached.\n *\n * @example\n * ```ts\n * import { createPafiProxyTransport, BATCH_EXECUTOR_ADDRESS_BASE_MAINNET } from '@pafi-dev/core';\n * import { createSmartAccountClient } from 'permissionless';\n * import { createPimlicoClient } from 'permissionless/clients/pimlico';\n * import { useIdentityToken } from '@privy-io/react-auth';\n *\n * const { identityToken } = useIdentityToken();\n * const identityTokenRef = useRef<string | null>(null);\n * useEffect(() => { identityTokenRef.current = identityToken; }, [identityToken]);\n *\n * const proxyTransport = createPafiProxyTransport({\n * proxyUrl: process.env.NEXT_PUBLIC_PIMLICO_PROXY_URL!,\n * getIdentityToken: () => identityTokenRef.current,\n * issuerId: process.env.NEXT_PUBLIC_ISSUER_ID!,\n * });\n *\n * const pimlicoClient = createPimlicoClient({ chain: base, transport: proxyTransport });\n * const smartClient = createSmartAccountClient({\n * client: publicClient,\n * chain: base,\n * account,\n * paymaster: pimlicoClient,\n * bundlerTransport: proxyTransport,\n * });\n * ```\n */\nexport function createPafiProxyTransport(\n params: PafiProxyTransportParams,\n): HttpTransport {\n const { proxyUrl, getIdentityToken, issuerId } = params;\n\n return http(proxyUrl, {\n fetchOptions: {},\n // fetchFn intercepts every fetch call the viem http transport makes,\n // injecting the auth headers before the request leaves the browser.\n fetchFn: (input: RequestInfo | URL, init?: RequestInit) => {\n const headers = new Headers(init?.headers);\n const token = getIdentityToken();\n if (token) {\n headers.set(\"authorization\", `Bearer ${token}`);\n }\n headers.set(\"x-issuer-id\", issuerId);\n return fetch(input, { ...init, headers });\n },\n });\n}\n","import type { Hex } from \"viem\";\n\n/**\n * Minimal interface for any smart-account client capable of submitting\n * transactions. Deliberately duck-typed so the SDK does not need a hard\n * dependency on permissionless — any client with this shape works.\n */\nexport interface SmartAccountSender {\n sendTransaction(params: Record<string, unknown>): Promise<Hex>;\n}\n\n/**\n * HTTP statuses returned by the PAFI sponsor-relayer / Pimlico proxy\n * that mean \"paymaster declined sponsorship, retrying without it is a\n * sensible UX.\" 401/403/429/503 only — NOT 4xx/5xx generally (a\n * generic 500 could be anything).\n */\nconst PAYMASTER_HTTP_STATUSES = new Set([401, 403, 429, 503]);\n\n/**\n * Word-boundary patterns matching paymaster-layer failures. Use\n * regex (not substring) so arbitrary error text containing the\n * digits \"503\" / \"403\" / etc. (transit IDs, addresses, log lines)\n * doesn't false-positive.\n *\n * - `\\bAA3[1-4]\\b` — ERC-4337 paymaster validation codes (AA31..AA34)\n * - `\\bpaymaster\\b` — Pimlico / sponsor-relayer plain text\n * - `\\bsponsorship\\b` — Pimlico declines\n * - `\\bpm_\\w+` — JSON-RPC method (pm_getPaymasterData, pm_sponsorUserOperation)\n * - `\\brate ?limit\\b` — generic rate limiter\n * - `\\bunauthorized\\b` — auth failure (also caught by HTTP status check below)\n */\nconst PAYMASTER_PATTERNS: RegExp[] = [\n /\\bAA3[1-4]\\b/i,\n /\\bpaymaster\\b/i,\n /\\bsponsorship\\b/i,\n /\\bpm_\\w+/i,\n /\\brate ?limit\\b/i,\n /\\bunauthorized\\b/i,\n];\n\ninterface MaybeHttpError {\n status?: number;\n statusCode?: number;\n response?: { status?: number };\n cause?: { status?: number };\n message?: string;\n}\n\n/**\n * Returns true when `err` originates from the **paymaster layer** rather\n * than the contract or bundler layer. Covers:\n *\n * - ERC-4337 AA3x validation errors (AA31–AA34, word-boundary match)\n * - Pimlico sponsorship rejections (`pm_*` methods, \"sponsorship\" / \"paymaster\")\n * - PAFI proxy HTTP errors — checked via typed `status` / `statusCode`\n * field when present, NOT substring match\n * - Generic \"rate limit\" / \"unauthorized\" strings\n *\n * Use this to decide whether retrying without a paymaster makes sense.\n * Contract reverts (AA23, AA24, AA25) and bundler errors are NOT matched.\n */\nexport function isPaymasterError(err: unknown): boolean {\n if (err == null || typeof err !== \"object\") return false;\n const e = err as MaybeHttpError;\n\n // 1. Typed HTTP status check — strict integer match, no substring drift.\n const status =\n e.status ?? e.statusCode ?? e.response?.status ?? e.cause?.status;\n if (typeof status === \"number\" && PAYMASTER_HTTP_STATUSES.has(status)) {\n return true;\n }\n\n // 2. Word-boundary regex against the error message. Avoids false\n // positives from arbitrary strings containing the digits \"503\"\n // or substrings like \"403\" inside a hex address.\n const msg = e.message ?? String(err);\n return PAYMASTER_PATTERNS.some((re) => re.test(msg));\n}\n\nexport interface SendWithPaymasterFallbackParams {\n /** Smart-account client with paymaster configured — tried first. */\n primaryClient: SmartAccountSender;\n /**\n * Smart-account client without paymaster — used when `primaryClient`\n * throws a paymaster error. User pays gas from their ETH balance.\n * Pass `null` or `undefined` to disable fallback (error re-thrown as-is).\n */\n fallbackClient: SmartAccountSender | null | undefined;\n /** Transaction params forwarded verbatim to `sendTransaction`. */\n txParams: Record<string, unknown>;\n /**\n * Optional alternate `txParams` used **only on the fallback attempt**.\n * Lets callers strip operator-fee transfers from the calldata when the\n * paymaster refuses — there's no point charging a \"PAFI gas\n * reimbursement\" fee in PT/USDC if PAFI didn't actually sponsor the\n * gas. When omitted, the same `txParams` is reused for both attempts.\n */\n txParamsFallback?: Record<string, unknown>;\n /**\n * Called just before the fallback attempt so the caller can log or\n * update UI. Receives the error message from the failed primary attempt.\n */\n onFallback?: (errorMessage: string) => void;\n}\n\n/**\n * Submit a UserOp with paymaster sponsorship, falling back to user-paid gas\n * if the paymaster refuses.\n *\n * Flow:\n * 1. Call `primaryClient.sendTransaction(txParams)`.\n * 2. If it throws and `isPaymasterError` returns true, call `onFallback` then\n * retry with `fallbackClient` (no paymaster — user pays gas).\n * 3. All other errors (contract revert, bundler rejection, network) are\n * re-thrown immediately without a retry.\n *\n * @example\n * ```ts\n * import { sendWithPaymasterFallback } from '@pafi-dev/core';\n *\n * const txHash = await sendWithPaymasterFallback({\n * primaryClient: smartClientWithPaymaster,\n * fallbackClient: smartClientNoPaymaster,\n * txParams: { calls, paymasterContext: { sponsorshipPolicyId } },\n * onFallback: (msg) => addLog(`Paymaster refused (${msg}) — you will pay gas.`),\n * });\n * ```\n */\nexport async function sendWithPaymasterFallback(\n params: SendWithPaymasterFallbackParams,\n): Promise<Hex> {\n const { primaryClient, fallbackClient, txParams, txParamsFallback, onFallback } = params;\n try {\n return await primaryClient.sendTransaction(txParams);\n } catch (err) {\n if (isPaymasterError(err) && fallbackClient) {\n const msg = (err as any)?.message ?? String(err);\n onFallback?.(msg);\n return await fallbackClient.sendTransaction(txParamsFallback ?? txParams);\n }\n throw err;\n }\n}\n","import { parseAbi } from \"viem\";\nimport type { Address, PublicClient } from \"viem\";\nimport { PAFI_SUBGRAPH_URL } from \"../subgraph/pools\";\nimport { getContractAddresses } from \"../contracts/real/addresses\";\nimport { OracleStaleError } from \"../errors\";\n\n/**\n * Operator-fee quoter — pure on-chain + subgraph reads, no issuer\n * backend involvement.\n *\n * Computes the PT amount the user must transfer to PAFI's fee\n * recipient to reimburse the ERC-4337 gas cost of a sponsored UserOp:\n *\n * nativeWei = gasUnits × gasPrice\n * premium = nativeWei × premiumBps / 10_000\n * feeInUsdt = premium × ethPriceUsd / 10^(18+8-6) // Chainlink\n * feeInPt = feeInUsdt × ptPerUsdt_18dec / 10^(18-6) // V4 pool spot\n *\n * Used by the SDK Direct path so callers don't need to hit any\n * issuer-specific endpoint to figure out the fee. The sponsor-relayer\n * `FeeValidatorService` runs the same quote server-side with a 5%\n * tolerance window — minor drift between client and server is\n * accepted.\n *\n * @example\n * ```ts\n * import { quoteOperatorFeePt } from \"@pafi-dev/core\";\n *\n * const fee = await quoteOperatorFeePt({\n * provider: publicClient,\n * chainId: 8453,\n * pointTokenAddress: POINT_TOKEN,\n * });\n *\n * await trading.handleSwap({\n * ...,\n * gasFeePt: fee,\n * feeRecipient: getContractAddresses(8453).pafiFeeRecipient,\n * });\n * ```\n */\n\nconst CHAINLINK_ABI = parseAbi([\n \"function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80)\",\n]);\n\n// Base ETH/USD heartbeat — feed updates hourly or on 0.5% deviation.\nconst CHAINLINK_MAX_AGE_S = 3_600n;\n\nconst POOL_PRICE_QUERY = `\n query GetPoolPrice($id: ID!) {\n pafiToken(id: $id) {\n pool {\n token0 { id }\n token1 { id }\n token0Price\n token1Price\n }\n }\n }\n`;\n\ninterface GraphQLPriceResponse {\n data?: {\n pafiToken: {\n pool: {\n token0: { id: string };\n token1: { id: string };\n token0Price: string;\n token1Price: string;\n } | null;\n } | null;\n };\n errors?: { message: string }[];\n}\n\n/**\n * Per-scenario gas budgets (callGasLimit + verificationGas + preVerify)\n * used by `quoteOperatorFee*`. Defaults are calibrated against the\n * actual UserOps the issuer + trading SDKs build:\n *\n * mint — `RelayService.prepareMint` callGasLimit 300k → 500k margin\n * burn — `RelayService.prepareBurn` 300k → 500k margin\n * swap — `buildSwapUserOp` callGasLimit 700k (UR.execute heavy)\n * perp-deposit — `buildPerpDepositViaRelay` 800k (LayerZero msg)\n * delegate — minimal no-op self-call, 200k margin\n *\n * Pass an explicit `gasUnits` to override.\n */\nexport type FeeScenario =\n | \"mint\"\n | \"burn\"\n | \"swap\"\n | \"perp-deposit\"\n | \"delegate\";\n\nexport const SCENARIO_GAS_UNITS: Record<FeeScenario, bigint> = {\n mint: 500_000n,\n burn: 500_000n,\n swap: 700_000n,\n \"perp-deposit\": 800_000n,\n delegate: 200_000n,\n};\n\nexport interface QuoteOperatorFeePtConfig {\n provider: PublicClient;\n chainId: number;\n pointTokenAddress: Address;\n /**\n * Scenario tag — picks default `gasUnits` from `SCENARIO_GAS_UNITS`.\n * Ignored when `gasUnits` is explicit. Default `\"mint\"` for back-\n * compat (matches the legacy 500_000 constant).\n */\n scenario?: FeeScenario;\n /**\n * ERC-4337 gas units the UserOp will consume on chain. Defaults to\n * `SCENARIO_GAS_UNITS[scenario]`, falling back to 500_000n. Pass a\n * tighter number when you have a Pimlico estimate to feed in.\n */\n gasUnits?: bigint;\n /**\n * Premium applied on top of raw gas cost in basis points. Default\n * 12_000 (= 1.2×, 20% buffer to cover oracle drift + paymaster\n * overhead). Same default the issuer SDK's `FeeManager` uses.\n */\n premiumBps?: number;\n /** Chainlink ETH/USD feed override. Defaults to chain's address. */\n chainlinkFeedAddress?: Address;\n /** Subgraph URL override. Defaults to `PAFI_SUBGRAPH_URL`. */\n subgraphUrl?: string;\n /** USDT token decimals. Default 6 (USDC/USDT on Base/Ethereum). */\n usdtDecimals?: number;\n /**\n * Opt-in fallback prices used when Chainlink / subgraph is\n * unavailable. Default `false` — throw `OracleStaleError`. Set\n * `true` AND configure `fallbackEthPriceUsd` / `fallbackPtPriceUsdt`\n * to absorb oracle outages instead of surfacing them.\n *\n * When fallback fires, callers SHOULD observe via `onFallback` so\n * production can flag the under-priced quote (e.g. show \"fee priced\n * against stale oracle\" banner in FE; alert on-call).\n */\n allowStaleFallback?: boolean;\n /** Fallback ETH price (USD) when Chainlink is unreachable. Only used when `allowStaleFallback: true`. Default 3000. */\n fallbackEthPriceUsd?: number;\n /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Only used when `allowStaleFallback: true`. Default 0.1. */\n fallbackPtPriceUsdt?: number;\n /**\n * Observability hook fired when the quoter falls back to stale\n * prices. Callers SHOULD wire this to their alert pipeline (Sentry,\n * Datadog, PagerDuty) so under-priced quotes don't go unnoticed.\n * When omitted, falls back to `console.warn` (kept for back-compat\n * but invisible in most prod log shippers).\n */\n onFallback?: (info: FallbackInfo) => void;\n fetchImpl?: typeof fetch;\n}\n\n/**\n * Detail surfaced via `onFallback` when the quoter substitutes a\n * stale-fallback price. Callers can format this into a UI banner or\n * log line.\n */\nexport interface FallbackInfo {\n /** Which oracle failed. */\n source: \"chainlink\" | \"subgraph\";\n /** Underlying reason from the oracle call (e.g. RPC error message). */\n reason: string;\n /** The fallback value that was used (in source-native units). */\n fallbackValue: number;\n}\n\n/**\n * Subset of `QuoteOperatorFeePtConfig` that doesn't need the V4 pool\n * step — used by `quoteOperatorFeeUsdt` (FE cashout-preview / `/gas-fee`\n * replacement). No `pointTokenAddress`, no `subgraphUrl`, no PT-side\n * fallback.\n */\nexport interface QuoteOperatorFeeUsdtConfig {\n provider: PublicClient;\n chainId: number;\n /** See `QuoteOperatorFeePtConfig.scenario`. v0.7.4. */\n scenario?: FeeScenario;\n gasUnits?: bigint;\n premiumBps?: number;\n chainlinkFeedAddress?: Address;\n usdtDecimals?: number;\n /**\n * Opt-in fallback price when Chainlink is unavailable. Default\n * `false` — throw `OracleStaleError`.\n */\n allowStaleFallback?: boolean;\n fallbackEthPriceUsd?: number;\n /** See QuoteOperatorFeePtConfig.onFallback. */\n onFallback?: (info: FallbackInfo) => void;\n}\n\nconst DEFAULT_GAS_UNITS = 500_000n;\nconst DEFAULT_PREMIUM_BPS = 12_000;\nconst DEFAULT_USDT_DECIMALS = 6;\n\n/**\n * Operator fee quoted in USDT raw units (default 6 decimals). Returns\n * the same value the legacy `GET /gas-fee` endpoint produced —\n * `withPremium_wei × ethPrice / 10^(18 + 8 - usdtDecimals)`. Does NOT\n * convert to PT, so no V4 subgraph call needed; pure on-chain\n * Chainlink read + RPC `getGasPrice`.\n *\n * Use this on the FE for the cashout preview screen (or anywhere a\n * USDT-denominated estimate is wanted) instead of round-tripping the\n * issuer backend's `/gas-fee` endpoint.\n *\n * @example\n * ```ts\n * import { quoteOperatorFeeUsdt } from \"@pafi-dev/core\";\n * const gasFeeUsdt = await quoteOperatorFeeUsdt({\n * provider, chainId: 8453,\n * });\n * // gasFeeUsdt is a bigint in 6-decimal USDT raw units\n * ```\n */\nexport async function quoteOperatorFeeUsdt(\n config: QuoteOperatorFeeUsdtConfig,\n): Promise<bigint> {\n const {\n provider,\n chainId,\n scenario = \"mint\",\n gasUnits = SCENARIO_GAS_UNITS[scenario] ?? DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\n allowStaleFallback = false,\n fallbackEthPriceUsd = 3_000,\n } = config;\n\n const chainlinkFeedAddress =\n config.chainlinkFeedAddress ??\n getContractAddresses(chainId).chainlinkEthUsd;\n\n const gasPrice = await provider.getGasPrice();\n const nativeCost = gasPrice * gasUnits;\n const withPremium = (nativeCost * BigInt(premiumBps)) / 10_000n;\n\n const ethPrice8dec = await getEthPrice8dec(\n provider,\n chainlinkFeedAddress,\n allowStaleFallback ? fallbackEthPriceUsd : null,\n config.onFallback,\n );\n\n // feeUsdt_<usdtDec> = withPremium_wei × ethPrice_8dec / 10^(18 + 8 - usdtDec)\n const denomExp = 18 + 8 - usdtDecimals;\n return (withPremium * ethPrice8dec) / 10n ** BigInt(denomExp);\n}\n\nexport async function quoteOperatorFeePt(\n config: QuoteOperatorFeePtConfig,\n): Promise<bigint> {\n const {\n provider,\n chainId,\n pointTokenAddress,\n scenario = \"mint\",\n gasUnits = SCENARIO_GAS_UNITS[scenario] ?? DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n subgraphUrl = PAFI_SUBGRAPH_URL,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\n allowStaleFallback = false,\n fallbackEthPriceUsd = 3_000,\n fallbackPtPriceUsdt = 0.1,\n fetchImpl = globalThis.fetch,\n } = config;\n\n const chainlinkFeedAddress =\n config.chainlinkFeedAddress ??\n getContractAddresses(chainId).chainlinkEthUsd;\n\n const gasPrice = await provider.getGasPrice();\n const nativeCost = gasPrice * gasUnits;\n const withPremium = (nativeCost * BigInt(premiumBps)) / 10_000n;\n\n const [ethPrice8dec, ptPerUsdt18dec] = await Promise.all([\n getEthPrice8dec(\n provider,\n chainlinkFeedAddress,\n allowStaleFallback ? fallbackEthPriceUsd : null,\n config.onFallback,\n ),\n getPtPerUsdt18dec(\n fetchImpl,\n subgraphUrl,\n pointTokenAddress,\n allowStaleFallback ? fallbackPtPriceUsdt : null,\n config.onFallback,\n ),\n ]);\n\n // feeInUsdt_<usdtDec> = withPremium_wei × ethPrice_8dec / 10^(18+8-usdtDec)\n // feeInPt_18dec = feeInUsdt × ptPerUsdt_18dec / 10^(18-usdtDec)\n // combined = withPremium × ethPrice × ptPerUsdt / 10^(18+8-usdtDec + 18-usdtDec)\n // = / 10^(44 - 2·usdtDec)\n // For usdtDecimals=6: 10^(44-12) = 10^32. But ptPerUsdt is already 18-scaled\n // so we subtract another 18: 10^(32-18) = 10^14? No — let me redo cleanly.\n //\n // Working in fractional units to keep it readable:\n // eth_human = withPremium / 10^18\n // usdt_human = eth_human × ethPriceFloat\n // pt_human = usdt_human × ptPerUsdtFloat\n // pt_18dec = pt_human × 10^18\n //\n // Substituting bigint scales:\n // ethPrice_8dec = ethPriceFloat × 10^8\n // ptPerUsdt_18dec = ptPerUsdtFloat × 10^18 (PT raw per 1 *human* USDT)\n //\n // pt_18dec = (withPremium / 10^18) × (ethPrice_8dec / 10^8)\n // × (ptPerUsdt_18dec / 10^18) × 10^18\n // = withPremium × ethPrice_8dec × ptPerUsdt_18dec / 10^26\n return (withPremium * ethPrice8dec * ptPerUsdt18dec) / 10n ** 26n;\n}\n\n/**\n * Fetch ETH/USD from Chainlink. When the feed is unavailable or stale,\n * either:\n * - fallback is `null` → throw `OracleStaleError` (default, v0.7.1+).\n * - fallback is a number → return `Math.round(fallback * 1e8)` after\n * `console.warn`. Caller opted in via `allowStaleFallback: true`.\n */\nasync function getEthPrice8dec(\n provider: PublicClient,\n feed: Address,\n fallback: number | null,\n onFallback?: (info: FallbackInfo) => void,\n): Promise<bigint> {\n try {\n const result = await provider.readContract({\n address: feed,\n abi: CHAINLINK_ABI,\n functionName: \"latestRoundData\",\n });\n const answer = result[1];\n const updatedAt = result[3];\n\n if (answer <= 0n) throw new Error(\"Chainlink: non-positive price\");\n\n const ageS = BigInt(Math.floor(Date.now() / 1000)) - updatedAt;\n if (ageS > CHAINLINK_MAX_AGE_S) {\n throw new Error(`Chainlink: price stale by ${ageS}s`);\n }\n\n return answer;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n if (fallback === null) {\n throw new OracleStaleError(\"chainlink\", reason);\n }\n if (onFallback) {\n onFallback({ source: \"chainlink\", reason, fallbackValue: fallback });\n } else {\n // Back-compat: default to console.warn when caller hasn't wired\n // an observability hook. Production callers SHOULD pass\n // `onFallback` to surface the fallback in their alert pipeline.\n // eslint-disable-next-line no-console\n console.warn(\n \"[quoteOperatorFee] Chainlink unavailable, using opt-in fallback:\",\n reason,\n );\n }\n return BigInt(Math.round(fallback * 1e8));\n }\n}\n\n/**\n * Fetch PT/USDT price from PAFI subgraph. When subgraph is unavailable\n * either:\n * - `fallbackPtPriceUsdt` is `null` → throw `OracleStaleError`\n * (default, v0.7.1+).\n * - is a number → fall back to `1 / fallback` after `console.warn`.\n */\nasync function getPtPerUsdt18dec(\n fetchImpl: typeof fetch,\n subgraphUrl: string,\n pointTokenAddress: Address,\n fallbackPtPriceUsdt: number | null,\n onFallback?: (info: FallbackInfo) => void,\n): Promise<bigint> {\n try {\n const response = await fetchImpl(subgraphUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: POOL_PRICE_QUERY,\n variables: { id: pointTokenAddress.toLowerCase() },\n }),\n });\n\n if (!response.ok) throw new Error(`subgraph HTTP ${response.status}`);\n\n const json = (await response.json()) as GraphQLPriceResponse;\n if (json.errors?.length) {\n throw new Error(json.errors.map((e) => e.message).join(\"; \"));\n }\n\n const pool = json.data?.pafiToken?.pool;\n if (!pool) throw new Error(\"pafiToken or pool not found\");\n\n // Subgraph V4 returns HUMAN-readable price ratios (decimals already\n // applied). For pool {token0=USDT, token1=PT}:\n // token0Price = USDT_human per 1 PT_human (e.g. \"2.0015\")\n // token1Price = PT_human per 1 USDT_human (e.g. \"0.4996\")\n //\n // We want `ptPerUsdt_18dec` = PT_raw per 1 USDT_human, i.e. the price\n // in PT-raw units per one human USDT. That's:\n // PT_human_per_USDT_human × 10^18 = PT_raw_per_USDT_human\n //\n // So always pick the price string that's \"PT per USDT in human\":\n // isPtToken0 → token0Price is \"PT/USDT_other\" but we have USDT here\n // (PT is token0, token1 is USDT) → token0Price is\n // USDT_human per 1 PT_human → invert\n // !isPtToken0 → token1Price is PT_human per 1 USDT_human → use as-is\n //\n // (Older comment claiming subgraph returns raw ratio + the\n // 10^24 / raw formula was wrong — it returned values off by ~10^11\n // for the typical 18/6 decimals split, making operator fee in PT\n // effectively zero.)\n const isPtToken0 =\n pool.token0.id.toLowerCase() === pointTokenAddress.toLowerCase();\n\n let ptPerUsdtHumanStr: string;\n if (isPtToken0) {\n // token0Price = USDT_human per 1 PT_human → invert to PT/USDT\n const usdtPerPtHuman = Number(pool.token0Price);\n if (!Number.isFinite(usdtPerPtHuman) || usdtPerPtHuman <= 0) {\n throw new Error(`invalid pool token0Price from subgraph: ${pool.token0Price}`);\n }\n ptPerUsdtHumanStr = (1 / usdtPerPtHuman).toFixed(18);\n } else {\n // token1Price = PT_human per 1 USDT_human → use directly\n ptPerUsdtHumanStr = pool.token1Price;\n if (!ptPerUsdtHumanStr || Number(ptPerUsdtHumanStr) <= 0) {\n throw new Error(`invalid pool token1Price from subgraph: ${ptPerUsdtHumanStr}`);\n }\n }\n\n const ptPerUsdt18dec = parseBigDecimalTo18(ptPerUsdtHumanStr);\n if (ptPerUsdt18dec === 0n) {\n throw new Error(`pool price parsed to zero: ${ptPerUsdtHumanStr}`);\n }\n return ptPerUsdt18dec;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n if (fallbackPtPriceUsdt === null) {\n throw new OracleStaleError(\"subgraph\", reason);\n }\n if (onFallback) {\n onFallback({\n source: \"subgraph\",\n reason,\n fallbackValue: fallbackPtPriceUsdt,\n });\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n \"[quoteOperatorFeePt] subgraph unavailable, using opt-in fallback:\",\n reason,\n );\n }\n const ptPerUsdtHuman = 1 / fallbackPtPriceUsdt;\n return parseBigDecimalTo18(ptPerUsdtHuman.toFixed(18));\n }\n}\n\nfunction parseBigDecimalTo18(s: string): bigint {\n const SCALE = 18;\n const [whole = \"0\", frac = \"\"] = s.split(\".\");\n const padded = (frac + \"0\".repeat(SCALE)).slice(0, SCALE);\n return BigInt(whole + padded);\n}\n","import { isAddress } from \"viem\";\nimport type { Address } from \"viem\";\nimport type { PoolKey } from \"../types\";\n\n/**\n * PAFI-hosted subgraph endpoint — single source of truth across all SDK packages.\n *\n * v3 (deployed 2026-05-08) indexes the v1.6 contract redeploy starting at\n * block 45683465 — IssuerRegistry/PointTokenFactory/MintingOracle/MintFeeWrapper\n * (single global wrapper instance, replaces v1.5 PAFIHook). Schema additions:\n * `MintFeeWrapper`, `MintFeeConfig`, `FeeRecipient`, `MintWithFeeEvent`,\n * `FeeDistribution`. v2 endpoint is kept live as rollback for ~1 week before\n * removal.\n */\nexport const PAFI_SUBGRAPH_URL =\n \"https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v3\";\n\nconst POOL_QUERY = `\n query GetPoolForPointToken($id: ID!) {\n pafiToken(id: $id) {\n id\n pool {\n id\n feeTier\n tickSpacing\n hooks\n token0 { id }\n token1 { id }\n }\n }\n }\n`;\n\ninterface GraphQLResponse {\n data?: {\n pafiToken: {\n id: string;\n pool: {\n id: string;\n feeTier: string;\n tickSpacing: string;\n hooks: string;\n token0: { id: string };\n token1: { id: string };\n } | null;\n } | null;\n };\n errors?: { message: string }[];\n}\n\nfunction sortCurrencies(a: Address, b: Address): [Address, Address] {\n return a.toLowerCase() < b.toLowerCase() ? [a, b] : [b, a];\n}\n\n/**\n * Fetch the Uniswap V4 pool(s) for a PAFI PointToken from the subgraph.\n *\n * Browser and Node compatible — uses globalThis.fetch. Returns an empty\n * array (never throws) when the token has no pool yet or the subgraph is\n * unreachable, so callers can show \"quote unavailable\" without crashing.\n *\n * @param chainId - Chain ID (reserved for multi-subgraph routing; currently unused)\n * @param pointTokenAddress - The PointToken contract address\n * @param subgraphUrl - Override the default PAFI subgraph URL\n */\nexport async function fetchPafiPools(\n _chainId: number,\n pointTokenAddress: Address,\n subgraphUrl: string = PAFI_SUBGRAPH_URL,\n): Promise<PoolKey[]> {\n let response: Response;\n try {\n response = await fetch(subgraphUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query: POOL_QUERY,\n variables: { id: pointTokenAddress.toLowerCase() },\n }),\n });\n } catch (err) {\n console.warn(\"[fetchPafiPools] subgraph unreachable:\", (err as Error).message);\n return [];\n }\n\n if (!response.ok) {\n console.warn(`[fetchPafiPools] subgraph returned ${response.status}`);\n return [];\n }\n\n const json = (await response.json()) as GraphQLResponse;\n if (json.errors && json.errors.length > 0) {\n console.warn(\n \"[fetchPafiPools] subgraph errors:\",\n json.errors.map((e) => e.message).join(\"; \"),\n );\n return [];\n }\n\n const pool = json.data?.pafiToken?.pool;\n if (!pool) return [];\n\n if (\n !isAddress(pool.hooks) ||\n !isAddress(pool.token0.id) ||\n !isAddress(pool.token1.id) ||\n !Number.isFinite(Number(pool.feeTier)) ||\n !Number.isFinite(Number(pool.tickSpacing))\n ) {\n console.error(\"[fetchPafiPools] invalid pool data in subgraph response — skipping\");\n return [];\n }\n\n const [currency0, currency1] = sortCurrencies(\n pool.token0.id as Address,\n pool.token1.id as Address,\n );\n\n return [{\n currency0,\n currency1,\n fee: Number(pool.feeTier),\n tickSpacing: Number(pool.tickSpacing),\n hooks: pool.hooks as Address,\n }];\n}\n","import { getContractAddresses } from \"./addresses\";\n\n// Derived from addresses.ts — single source of truth.\n// Update addresses.ts when SC team redeploys; these follow automatically.\nexport const BATCH_EXECUTOR_ADDRESS_BASE_MAINNET = getContractAddresses(8453).batchExecutor;\nexport const BATCH_EXECUTOR_ADDRESS_BASE_SEPOLIA = getContractAddresses(84532).batchExecutor;\n\n// The ABI itself is fully real — re-exported from userop/ for\n// convenience so consumers don't need two imports.\nexport { BATCH_EXECUTOR_ABI } from \"../../userop/batchExecute\";\n","/**\n * PAFI HTTP service URLs by chainId. Mirrors the `getContractAddresses`\n * pattern: SDK ships with the URL for each supported chain so issuers\n * don't pass URLs as env vars / constructor args.\n *\n * When PAFI changes URLs (rebrand, re-host, environment migration),\n * bump the SDK version and re-publish. Issuers pin a version, get the\n * URLs that match.\n *\n * No env override is provided on purpose — different environments use\n * different SDK versions (e.g. an `@pafi-dev/issuer-dev` channel for\n * staging). This keeps issuer integration to chainId + creds only.\n */\nexport interface PafiServiceUrls {\n /**\n * sponsor-relayer base URL (paymaster proxy). PafiBackendClient\n * appends `/paymaster/sponsor`, `/bundler/receipt`, etc.\n */\n sponsorRelayer: string;\n\n /**\n * issuer-api base URL. SettlementClient appends\n * `/issuers/:issuerId/redemption-policy`.\n */\n issuerApi: string;\n}\n\n/**\n * Per-chain URL map. URLs follow the pattern\n * `https://<host>/api/<service>` so Kong gateway can route by path.\n *\n * NOTE: placeholder URLs — Phi will swap in real prod/staging hosts\n * once the deploy targets are finalized. SDK version bump captures\n * the change.\n */\nexport const PAFI_SERVICE_URLS: Record<number, PafiServiceUrls> = {\n // Base mainnet\n 8453: {\n sponsorRelayer: \"https://api-dev.pacificfinance.org/api/sponsor\",\n issuerApi: \"https://api-dev.pacificfinance.org/api/issuer\",\n },\n // Base sepolia\n 84532: {\n sponsorRelayer: \"https://api-dev.pacificfinance.org/api/sponsor\",\n issuerApi: \"https://api-dev.pacificfinance.org/api/issuer\",\n },\n};\n\nexport function getPafiServiceUrls(chainId: number): PafiServiceUrls {\n const urls = PAFI_SERVICE_URLS[chainId];\n if (!urls) {\n throw new Error(\n `getPafiServiceUrls: no PAFI service URLs for chainId ${chainId}. ` +\n `Supported: ${Object.keys(PAFI_SERVICE_URLS).join(\", \")}`,\n );\n }\n return urls;\n}\n","import type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\n\nconst DEFAULT_WIDTH = 900;\nconst DEFAULT_HEIGHT = 700;\nconst DEFAULT_NAME = \"pafi-web\";\n\n/**\n * Web browser popup adapter. Opens the given URL in a centered\n * `window.open()` popup, polls for close, and optionally forwards\n * `postMessage` events back to the caller.\n *\n * Runtime requirement: `window.open` must exist. Throws if called\n * under Node / SSR / React Native — use `setPafiWebModalAdapter()` to\n * provide a platform-specific adapter in those environments.\n *\n * ## Popup blocking\n *\n * Browsers block `window.open()` unless it happens inside a user\n * gesture (click handler). Callers MUST wire this into a direct click\n * handler — wrapping it in a `setTimeout` or async await before the\n * open call will trigger the blocker.\n */\nexport function openWebPopup(\n url: string,\n options: ModalOpenOptions = {},\n): PafiWebModalHandle {\n if (typeof window === \"undefined\" || typeof window.open !== \"function\") {\n throw new Error(\n \"openWebPopup: `window.open` is not available in this runtime. \" +\n \"Register a platform adapter via setPafiWebModalAdapter() instead.\",\n );\n }\n\n const width = options.width ?? DEFAULT_WIDTH;\n const height = options.height ?? DEFAULT_HEIGHT;\n const name = options.windowName ?? DEFAULT_NAME;\n\n // Center on the screen — works in all major browsers. Falls back\n // gracefully if `screen.availWidth`/`screenX` are unavailable.\n const screenW = window.screen?.availWidth ?? window.innerWidth;\n const screenH = window.screen?.availHeight ?? window.innerHeight;\n const left = Math.max(0, Math.floor((screenW - width) / 2));\n const top = Math.max(0, Math.floor((screenH - height) / 2));\n\n const features = [\n `width=${width}`,\n `height=${height}`,\n `left=${left}`,\n `top=${top}`,\n \"resizable=yes\",\n \"scrollbars=yes\",\n \"noopener=no\", // we need opener.postMessage to work\n ].join(\",\");\n\n const popup = window.open(url, name, features);\n if (!popup) {\n throw new Error(\n \"openWebPopup: popup was blocked. Ensure this call runs inside a user gesture (click handler).\",\n );\n }\n\n // Set up state + listeners --------------------------------------------\n\n let closed = false;\n let pollId: ReturnType<typeof setInterval> | null = null;\n let messageListener: ((e: MessageEvent) => void) | null = null;\n\n const dispose = (): void => {\n if (closed) return;\n closed = true;\n if (pollId !== null) {\n clearInterval(pollId);\n pollId = null;\n }\n if (messageListener) {\n window.removeEventListener(\"message\", messageListener);\n messageListener = null;\n }\n options.onClose?.();\n };\n\n // Poll every 500ms for popup close — there's no `close` event.\n // Stops when `popup.closed` flips to true OR our handle is closed.\n pollId = setInterval(() => {\n if (popup.closed) {\n dispose();\n }\n }, 500);\n\n // Wire postMessage filtering by origin — secure-by-default. An\n // empty `allowedOrigins` would silently reject every message (UI\n // hangs forever waiting for a callback that never arrives), so we\n // throw at construction to surface misconfiguration at startup.\n if (options.onMessage) {\n const allowed = options.allowedOrigins ?? [];\n if (allowed.length === 0) {\n throw new Error(\n \"openPafiWebModal: `allowedOrigins` is empty/missing while `onMessage` \" +\n \"is supplied. The popup-message listener would silently reject every \" +\n \"message — caller must explicitly whitelist PAFI Web's host (e.g. \" +\n \"`['https://app.pacificfinance.org']`) before any payload reaches the \" +\n \"callback. To accept any origin (insecure), pass an explicit list \" +\n \"containing '*' or omit `onMessage` entirely.\",\n );\n }\n const onMessage = options.onMessage;\n messageListener = (event: MessageEvent): void => {\n if (event.source !== popup) return;\n // Allow caller-side wildcard explicitly opt-in; never silently allow.\n if (!allowed.includes(\"*\") && !allowed.includes(event.origin)) return;\n onMessage(event.data, event.origin);\n };\n window.addEventListener(\"message\", messageListener);\n }\n\n // Handle object -------------------------------------------------------\n\n return {\n get isOpen(): boolean {\n return !closed && !popup.closed;\n },\n close(): void {\n if (closed) return;\n try {\n popup.close();\n } catch {\n // Some browsers block close() unless the popup was opened by\n // the same document. Dispose our listeners anyway.\n }\n dispose();\n },\n focus(): void {\n if (closed || popup.closed) return;\n try {\n popup.focus();\n } catch {\n // No-op on failure — focus is best-effort.\n }\n },\n postMessage(data: unknown): void {\n if (closed || popup.closed) return;\n try {\n // targetOrigin '*' is fine here because the caller owns the\n // data being sent. For security on the receiving side, the\n // PAFI Web page should check event.origin itself.\n popup.postMessage(data, \"*\");\n } catch {\n // No-op.\n }\n },\n };\n}\n\n/**\n * The web popup packaged as a {@link PafiWebModalAdapter} so callers\n * can register it explicitly (e.g. in a test harness).\n */\nexport const webPopupAdapter: PafiWebModalAdapter = {\n open(url, options) {\n return openWebPopup(url, options);\n },\n};\n","import { openWebPopup } from \"./webPopup\";\nimport type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\n\nexport type {\n ModalOpenOptions,\n PafiWebModalAdapter,\n PafiWebModalHandle,\n} from \"./types\";\nexport { openWebPopup, webPopupAdapter } from \"./webPopup\";\n\n/**\n * Module-level adapter registry — allows platform consumers (React\n * Native, Electron, Tauri, etc.) to plug in their own handoff\n * implementation without forking the SDK.\n *\n * Callers set this once at app boot; `openPafiWebModal()` below uses\n * whatever is registered, or falls back to the web popup adapter\n * when `window.open` is available.\n */\nlet registeredAdapter: PafiWebModalAdapter | null = null;\n\n/**\n * Register the adapter used by `openPafiWebModal()`. Typically called\n * once during app initialization — mobile apps register a\n * SFSafariViewController / Chrome Custom Tabs adapter, desktop apps\n * can leave it unset (web popup is the default).\n *\n * Pass `null` to unregister and fall back to the default.\n */\nexport function setPafiWebModalAdapter(\n adapter: PafiWebModalAdapter | null,\n): void {\n registeredAdapter = adapter;\n}\n\n/**\n * Return the currently registered adapter, or `null` when none is set.\n * Useful for tests that want to snapshot-and-restore the adapter.\n */\nexport function getPafiWebModalAdapter(): PafiWebModalAdapter | null {\n return registeredAdapter;\n}\n\n/**\n * Open PAFI Web in the host platform's appropriate UX:\n *\n * - Browser (window.open): centered popup, 900×700 by default\n * - React Native (with adapter registered): SFSafariViewController\n * / Chrome Custom Tabs via `react-native-inappbrowser-reborn` or\n * `expo-web-browser`\n * - Desktop (with adapter registered): custom BrowserWindow / new tab\n *\n * Resolution order:\n * 1. If an adapter was registered via `setPafiWebModalAdapter()`, use it.\n * 2. Else if `window.open` is available, use the built-in web popup.\n * 3. Else throw with a clear error pointing at the adapter registry.\n *\n * @example\n * ```ts\n * // User clicks \"Trade on PAFI\" button\n * button.addEventListener('click', async () => {\n * const modal = await openPafiWebModal('https://app.pacificfinance.org', {\n * allowedOrigins: ['https://app.pacificfinance.org'],\n * onMessage: (data, origin) => {\n * if (typeof data === 'object' && data && 'txHash' in data) {\n * console.log('Swap confirmed:', data.txHash);\n * modal.close();\n * }\n * },\n * onClose: () => {\n * console.log('User closed modal');\n * },\n * });\n * });\n * ```\n */\nexport async function openPafiWebModal(\n url: string,\n options: ModalOpenOptions = {},\n): Promise<PafiWebModalHandle> {\n if (!url || typeof url !== \"string\") {\n throw new Error(\"openPafiWebModal: `url` is required\");\n }\n\n if (registeredAdapter) {\n return Promise.resolve(registeredAdapter.open(url, options));\n }\n\n if (typeof window !== \"undefined\" && typeof window.open === \"function\") {\n return openWebPopup(url, options);\n }\n\n throw new Error(\n \"openPafiWebModal: no adapter registered and `window.open` is unavailable. \" +\n \"Call `setPafiWebModalAdapter()` with a platform-specific adapter (e.g. SFSafariViewController on iOS) during app boot.\",\n );\n}\n"],"mappings":"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","names":["http","encodeFunctionData","erc20Abi","encodeFunctionData","parseAbi","encodeFunctionData","encodeFunctionData","encodeFunctionData","concat","keccak256","parseAbi","parseAbi","http"]}
|