@pafi-dev/core 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -257
- package/dist/index.cjs +23 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -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/transport/proxyTransport.ts","../src/transport/paymasterFallback.ts","../src/fee/operatorFeeQuoter.ts","../src/subgraph/pools.ts","../src/contracts/real/addresses.ts","../src/contracts/real/batchExecutor.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","export 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","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, erc20Abi } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { erc20ApproveOp, 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 PT gas-fee transfer prepended to the batch. Set both\n * `gasFeePtRecipient` and `gasFeePt` together for sponsored flows\n * (PAFI gas reimbursement). Pass `0n` / `undefined` for the fallback\n * path where the user pays ERC-4337 gas in ETH directly.\n */\n pointTokenAddress?: Address;\n gasFeePt?: bigint;\n gasFeePtRecipient?: 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: `[PT.transfer(feeRecipient, gasFeePt), 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 */\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 PT gas fee transfer (sponsored path).\n if (params.gasFeePt && params.gasFeePt > 0n) {\n if (!params.pointTokenAddress) {\n throw new Error(\n \"buildPerpDepositViaRelay: pointTokenAddress required when gasFeePt > 0\",\n );\n }\n if (!params.gasFeePtRecipient) {\n throw new Error(\n \"buildPerpDepositViaRelay: gasFeePtRecipient required when gasFeePt > 0\",\n );\n }\n operations.push({\n target: params.pointTokenAddress,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"transfer\",\n args: [params.gasFeePtRecipient, params.gasFeePt],\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 * Module-level paymaster config. Read by batch builders (via\n * `getPaymasterConfig()`) and by `@pafi/issuer` `RelayService` when\n * building UserOps.\n *\n * Consumers call `setPaymasterConfig()` once at application boot. All\n * subsequent helpers that need the feeRecipient / issuer identity /\n * backend URL pull from here.\n *\n * This is global state by design — making every batch builder take a\n * config param would clutter every call site. The alternative (a\n * context/service) has more ceremony than this flow justifies.\n */\nlet _config: PaymasterConfig | null = null;\n\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 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 * Get the current paymaster config. Throws if `setPaymasterConfig()`\n * has not been called yet — this surfaces boot-order bugs early\n * instead of failing with \"paymaster.feeRecipient is undefined\" at\n * the point of use.\n */\nexport function getPaymasterConfig(): PaymasterConfig {\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 const idx = normalized.indexOf(magic);\n if (idx === -1) return null;\n const raw = normalized.slice(idx + magic.length, idx + magic.length + 40);\n if (raw.length !== 40) return null;\n return `0x${raw}` 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 { 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 * 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)\n * - Pimlico sponsorship rejections (`pm_*` methods, \"sponsorship\" messages)\n * - PAFI proxy HTTP errors (401, 403, 429, 503)\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 const msg = ((err as any)?.message ?? String(err)).toLowerCase();\n return (\n msg.includes(\"paymaster\") ||\n msg.includes(\"sponsorship\") ||\n msg.includes(\"aa31\") ||\n msg.includes(\"aa32\") ||\n msg.includes(\"aa33\") ||\n msg.includes(\"aa34\") ||\n msg.includes(\"pm_\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"unauthorized\") ||\n msg.includes(\"403\") ||\n msg.includes(\"429\") ||\n msg.includes(\"503\")\n );\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\";\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\nexport interface QuoteOperatorFeePtConfig {\n provider: PublicClient;\n chainId: number;\n pointTokenAddress: Address;\n /**\n * ERC-4337 gas units the UserOp will consume on chain. Default\n * 500_000n covers the common scenarios (mint, swap, perp deposit\n * via Relay) with margin. Pass a tighter number when you have a\n * 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 /** Fallback ETH price (USD) when Chainlink is unreachable. Default 3000. */\n fallbackEthPriceUsd?: number;\n /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Default 0.1. */\n fallbackPtPriceUsdt?: number;\n fetchImpl?: typeof fetch;\n}\n\nconst DEFAULT_GAS_UNITS = 500_000n;\nconst DEFAULT_PREMIUM_BPS = 12_000;\nconst DEFAULT_USDT_DECIMALS = 6;\n\nexport async function quoteOperatorFeePt(\n config: QuoteOperatorFeePtConfig,\n): Promise<bigint> {\n const {\n provider,\n chainId,\n pointTokenAddress,\n gasUnits = DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n subgraphUrl = PAFI_SUBGRAPH_URL,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\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(provider, chainlinkFeedAddress, fallbackEthPriceUsd),\n getPtPerUsdt18dec(\n fetchImpl,\n subgraphUrl,\n pointTokenAddress,\n fallbackPtPriceUsdt,\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\nasync function getEthPrice8dec(\n provider: PublicClient,\n feed: Address,\n fallback: number,\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 console.warn(\n \"[quoteOperatorFeePt] Chainlink unavailable, using fallback:\",\n (err as Error).message,\n );\n return BigInt(Math.round(fallback * 1e8));\n }\n}\n\nasync function getPtPerUsdt18dec(\n fetchImpl: typeof fetch,\n subgraphUrl: string,\n pointTokenAddress: Address,\n fallbackPtPriceUsdt: number,\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 ratio of *raw* token amounts. Whichever\n // field corresponds to PT, its value equals USDT_raw / PT_raw.\n // To get ptPerUsdt_18dec (= PT raw per 1 human-readable USDT):\n // ptPerUsdt_18dec = 10^(USDT_DEC + 18) / parseBigDecimalTo18(price)\n const isPtToken0 =\n pool.token0.id.toLowerCase() === pointTokenAddress.toLowerCase();\n const priceStr = isPtToken0 ? pool.token0Price : pool.token1Price;\n\n if (!priceStr || Number(priceStr) <= 0) {\n throw new Error(`invalid pool price from subgraph: ${priceStr}`);\n }\n\n const raw = parseBigDecimalTo18(priceStr);\n if (raw === 0n) {\n throw new Error(`pool price parsed to zero: ${priceStr}`);\n }\n return 10n ** 24n / raw;\n } catch (err) {\n console.warn(\n \"[quoteOperatorFeePt] subgraph unavailable, using fallback:\",\n (err as Error).message,\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/** PAFI-hosted subgraph endpoint — single source of truth across all SDK packages. */\nexport const PAFI_SUBGRAPH_URL =\n \"https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v2\";\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 type { Address } from \"viem\";\n\n/**\n * Per-chain deployed contract addresses — v1.4 flow.\n *\n * ## Status (2026-04-22)\n *\n * Base mainnet (8453): **all real**. BatchExecutor now points at the\n * canonical Coinbase Smart Wallet v2 contract which PAFI reuses as the\n * EIP-7702 delegation target (no per-app deploy required — one\n * contract, every issuer).\n *\n * Base Sepolia (84532): entire row is placeholder — not in active use.\n *\n * ## What lives where\n *\n * pointToken — live POINT instance (clone of PointToken impl)\n * batchExecutor — EIP-7702 delegation target (Coinbase Smart Wallet v2)\n * usdt — MockERC20 used by Uniswap pools\n * issuerRegistry — registry of all issuers on this chain\n * mintingOracle — per-issuer mint cap enforcer\n * pafiHook — Uniswap V4 hook enforcing the 10% PT→USDT fee\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 * Uniswap V4 hook that enforces the 10% fee on PT→USDT swaps\n * (USDT→PT is free). FE reads this to build `PoolKey.hooks` when\n * constructing a swap; quoters + routers need it to resolve the\n * correct pool.\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 — SC-delivered (2026-04-21, 2026-04-22)\n // registry: IssuerRegistry 0xda2D3338CF70F462Ac175F5f2edfa45660CA4f31\n // factory: PointTokenFactory 0x36c0BAb2faBE45EfA6d13001143e43A266Af673B\n // oracle: MintingOracle 0xD85165939C700E51c8a45099316C6482634C2Ab9\n // tokenImpl: PointToken (impl) 0x2e6FB1B0C1A51abb83eC974890126a64eC02E995\n // mockUsdt: MockERC20 0x5d313485Ba59C3bb91e1A9C0C11782F0b83d5dcd\n // POINT: PointToken instance 0x7d25E7156E51F865D522fd3ef257a6B5DD41b97e\n // batchExecutor: Coinbase SW v2 0x7702cb554e6bFb442cb743A7dF23154544a7176C\n // pafiHook: PAFIHook (V4, 10%) 0x870cAF9882d3160602AaC1769C2B264A2d8EC044\n 8453: {\n pointToken: \"0x7d25E7156E51F865D522fd3ef257a6B5DD41b97e\",\n batchExecutor: \"0x7702cb554e6bFb442cb743A7dF23154544a7176C\",\n usdt: \"0x5d313485Ba59C3bb91e1A9C0C11782F0b83d5dcd\",\n issuerRegistry: \"0xda2D3338CF70F462Ac175F5f2edfa45660CA4f31\",\n mintingOracle: \"0xD85165939C700E51c8a45099316C6482634C2Ab9\",\n pafiHook: \"0x870cAF9882d3160602AaC1769C2B264A2d8EC044\",\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 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: \"0x36c0BAb2faBE45EfA6d13001143e43A266Af673B\",\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: \"0x2e6FB1B0C1A51abb83eC974890126a64eC02E995\",\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 { 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","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 or missing `allowedOrigins` rejects ALL messages; the\n // caller must explicitly whitelist PAFI Web's host(s) before any\n // payload is delivered. This prevents a compromised popup (via\n // opener leak or redirect) from impersonating PAFI Web.\n if (options.onMessage) {\n const allowed = options.allowedOrigins ?? [];\n const onMessage = options.onMessage;\n messageListener = (event: MessageEvent): void => {\n if (event.source !== popup) return;\n if (!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","erc20Abi","encodeFunctionData","erc20Abi","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/transport/proxyTransport.ts","../src/transport/paymasterFallback.ts","../src/fee/operatorFeeQuoter.ts","../src/subgraph/pools.ts","../src/contracts/real/addresses.ts","../src/contracts/real/batchExecutor.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","export 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","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, erc20Abi } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { erc20ApproveOp, 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 PT gas-fee transfer prepended to the batch. Set both\n * `gasFeePtRecipient` and `gasFeePt` together for sponsored flows\n * (PAFI gas reimbursement). Pass `0n` / `undefined` for the fallback\n * path where the user pays ERC-4337 gas in ETH directly.\n */\n pointTokenAddress?: Address;\n gasFeePt?: bigint;\n gasFeePtRecipient?: 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: `[PT.transfer(feeRecipient, gasFeePt), 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 */\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 PT gas fee transfer (sponsored path).\n if (params.gasFeePt && params.gasFeePt > 0n) {\n if (!params.pointTokenAddress) {\n throw new Error(\n \"buildPerpDepositViaRelay: pointTokenAddress required when gasFeePt > 0\",\n );\n }\n if (!params.gasFeePtRecipient) {\n throw new Error(\n \"buildPerpDepositViaRelay: gasFeePtRecipient required when gasFeePt > 0\",\n );\n }\n operations.push({\n target: params.pointTokenAddress,\n value: 0n,\n data: encodeFunctionData({\n abi: erc20Abi,\n functionName: \"transfer\",\n args: [params.gasFeePtRecipient, params.gasFeePt],\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 * Module-level paymaster config. Read by batch builders (via\n * `getPaymasterConfig()`) and by `@pafi/issuer` `RelayService` when\n * building UserOps.\n *\n * Consumers call `setPaymasterConfig()` once at application boot. All\n * subsequent helpers that need the feeRecipient / issuer identity /\n * backend URL pull from here.\n *\n * This is global state by design — making every batch builder take a\n * config param would clutter every call site. The alternative (a\n * context/service) has more ceremony than this flow justifies.\n */\nlet _config: PaymasterConfig | null = null;\n\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 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 * Get the current paymaster config. Throws if `setPaymasterConfig()`\n * has not been called yet — this surfaces boot-order bugs early\n * instead of failing with \"paymaster.feeRecipient is undefined\" at\n * the point of use.\n */\nexport function getPaymasterConfig(): PaymasterConfig {\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 const idx = normalized.indexOf(magic);\n if (idx === -1) return null;\n const raw = normalized.slice(idx + magic.length, idx + magic.length + 40);\n if (raw.length !== 40) return null;\n return `0x${raw}` 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 { 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 * 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)\n * - Pimlico sponsorship rejections (`pm_*` methods, \"sponsorship\" messages)\n * - PAFI proxy HTTP errors (401, 403, 429, 503)\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 const msg = ((err as any)?.message ?? String(err)).toLowerCase();\n return (\n msg.includes(\"paymaster\") ||\n msg.includes(\"sponsorship\") ||\n msg.includes(\"aa31\") ||\n msg.includes(\"aa32\") ||\n msg.includes(\"aa33\") ||\n msg.includes(\"aa34\") ||\n msg.includes(\"pm_\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"unauthorized\") ||\n msg.includes(\"403\") ||\n msg.includes(\"429\") ||\n msg.includes(\"503\")\n );\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\";\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\nexport interface QuoteOperatorFeePtConfig {\n provider: PublicClient;\n chainId: number;\n pointTokenAddress: Address;\n /**\n * ERC-4337 gas units the UserOp will consume on chain. Default\n * 500_000n covers the common scenarios (mint, swap, perp deposit\n * via Relay) with margin. Pass a tighter number when you have a\n * 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 /** Fallback ETH price (USD) when Chainlink is unreachable. Default 3000. */\n fallbackEthPriceUsd?: number;\n /** Fallback PT price (USDT per 1 PT) when subgraph is unreachable. Default 0.1. */\n fallbackPtPriceUsdt?: number;\n fetchImpl?: typeof fetch;\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 gasUnits?: bigint;\n premiumBps?: number;\n chainlinkFeedAddress?: Address;\n usdtDecimals?: number;\n fallbackEthPriceUsd?: number;\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 gasUnits = DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\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 fallbackEthPriceUsd,\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 gasUnits = DEFAULT_GAS_UNITS,\n premiumBps = DEFAULT_PREMIUM_BPS,\n subgraphUrl = PAFI_SUBGRAPH_URL,\n usdtDecimals = DEFAULT_USDT_DECIMALS,\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(provider, chainlinkFeedAddress, fallbackEthPriceUsd),\n getPtPerUsdt18dec(\n fetchImpl,\n subgraphUrl,\n pointTokenAddress,\n fallbackPtPriceUsdt,\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\nasync function getEthPrice8dec(\n provider: PublicClient,\n feed: Address,\n fallback: number,\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 console.warn(\n \"[quoteOperatorFeePt] Chainlink unavailable, using fallback:\",\n (err as Error).message,\n );\n return BigInt(Math.round(fallback * 1e8));\n }\n}\n\nasync function getPtPerUsdt18dec(\n fetchImpl: typeof fetch,\n subgraphUrl: string,\n pointTokenAddress: Address,\n fallbackPtPriceUsdt: number,\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 ratio of *raw* token amounts. Whichever\n // field corresponds to PT, its value equals USDT_raw / PT_raw.\n // To get ptPerUsdt_18dec (= PT raw per 1 human-readable USDT):\n // ptPerUsdt_18dec = 10^(USDT_DEC + 18) / parseBigDecimalTo18(price)\n const isPtToken0 =\n pool.token0.id.toLowerCase() === pointTokenAddress.toLowerCase();\n const priceStr = isPtToken0 ? pool.token0Price : pool.token1Price;\n\n if (!priceStr || Number(priceStr) <= 0) {\n throw new Error(`invalid pool price from subgraph: ${priceStr}`);\n }\n\n const raw = parseBigDecimalTo18(priceStr);\n if (raw === 0n) {\n throw new Error(`pool price parsed to zero: ${priceStr}`);\n }\n return 10n ** 24n / raw;\n } catch (err) {\n console.warn(\n \"[quoteOperatorFeePt] subgraph unavailable, using fallback:\",\n (err as Error).message,\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/** PAFI-hosted subgraph endpoint — single source of truth across all SDK packages. */\nexport const PAFI_SUBGRAPH_URL =\n \"https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v2\";\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 type { Address } from \"viem\";\n\n/**\n * Per-chain deployed contract addresses — v1.4 flow.\n *\n * ## Status (2026-04-22)\n *\n * Base mainnet (8453): **all real**. BatchExecutor now points at the\n * canonical Coinbase Smart Wallet v2 contract which PAFI reuses as the\n * EIP-7702 delegation target (no per-app deploy required — one\n * contract, every issuer).\n *\n * Base Sepolia (84532): entire row is placeholder — not in active use.\n *\n * ## What lives where\n *\n * pointToken — live POINT instance (clone of PointToken impl)\n * batchExecutor — EIP-7702 delegation target (Coinbase Smart Wallet v2)\n * usdt — MockERC20 used by Uniswap pools\n * issuerRegistry — registry of all issuers on this chain\n * mintingOracle — per-issuer mint cap enforcer\n * pafiHook — Uniswap V4 hook enforcing the 10% PT→USDT fee\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 * Uniswap V4 hook that enforces the 10% fee on PT→USDT swaps\n * (USDT→PT is free). FE reads this to build `PoolKey.hooks` when\n * constructing a swap; quoters + routers need it to resolve the\n * correct pool.\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 — SC-delivered (2026-04-21, 2026-04-22)\n // registry: IssuerRegistry 0xda2D3338CF70F462Ac175F5f2edfa45660CA4f31\n // factory: PointTokenFactory 0x36c0BAb2faBE45EfA6d13001143e43A266Af673B\n // oracle: MintingOracle 0xD85165939C700E51c8a45099316C6482634C2Ab9\n // tokenImpl: PointToken (impl) 0x2e6FB1B0C1A51abb83eC974890126a64eC02E995\n // mockUsdt: MockERC20 0x5d313485Ba59C3bb91e1A9C0C11782F0b83d5dcd\n // POINT: PointToken instance 0x7d25E7156E51F865D522fd3ef257a6B5DD41b97e\n // batchExecutor: Coinbase SW v2 0x7702cb554e6bFb442cb743A7dF23154544a7176C\n // pafiHook: PAFIHook (V4, 10%) 0x870cAF9882d3160602AaC1769C2B264A2d8EC044\n 8453: {\n pointToken: \"0x7d25E7156E51F865D522fd3ef257a6B5DD41b97e\",\n batchExecutor: \"0x7702cb554e6bFb442cb743A7dF23154544a7176C\",\n usdt: \"0x5d313485Ba59C3bb91e1A9C0C11782F0b83d5dcd\",\n issuerRegistry: \"0xda2D3338CF70F462Ac175F5f2edfa45660CA4f31\",\n mintingOracle: \"0xD85165939C700E51c8a45099316C6482634C2Ab9\",\n pafiHook: \"0x870cAF9882d3160602AaC1769C2B264A2d8EC044\",\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 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: \"0x36c0BAb2faBE45EfA6d13001143e43A266Af673B\",\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: \"0x2e6FB1B0C1A51abb83eC974890126a64eC02E995\",\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 { 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","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 or missing `allowedOrigins` rejects ALL messages; the\n // caller must explicitly whitelist PAFI Web's host(s) before any\n // payload is delivered. This prevents a compromised popup (via\n // opener leak or redirect) from impersonating PAFI Web.\n if (options.onMessage) {\n const allowed = options.allowedOrigins ?? [];\n const onMessage = options.onMessage;\n messageListener = (event: MessageEvent): void => {\n if (event.source !== popup) return;\n if (!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","erc20Abi","encodeFunctionData","erc20Abi","concat","keccak256","parseAbi","parseAbi","http"]}
|