@pafi-dev/core 0.3.0-beta.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -1084
- package/dist/auth/index.cjs +16 -2
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +93 -2
- package/dist/auth/index.d.ts +93 -2
- package/dist/auth/index.js +17 -3
- package/dist/{chunk-KJKDLD7N.cjs → chunk-2PY5RNVS.cjs} +11 -11
- package/dist/{chunk-KJKDLD7N.cjs.map → chunk-2PY5RNVS.cjs.map} +1 -1
- package/dist/{chunk-DMW67WBU.cjs → chunk-52SZJDFT.cjs} +6 -2
- package/dist/chunk-52SZJDFT.cjs.map +1 -0
- package/dist/{chunk-Z2V525IS.cjs → chunk-ARZSGP5Y.cjs} +6 -6
- package/dist/{chunk-Z2V525IS.cjs.map → chunk-ARZSGP5Y.cjs.map} +1 -1
- package/dist/{chunk-GWLEEXM4.cjs → chunk-FNJZUNK3.cjs} +90 -2
- package/dist/chunk-FNJZUNK3.cjs.map +1 -0
- package/dist/{chunk-I2P3TIP7.js → chunk-N5M3BLOV.js} +2 -2
- package/dist/{chunk-73CQTNLB.js → chunk-S5CCEO4O.js} +6 -2
- package/dist/{chunk-73CQTNLB.js.map → chunk-S5CCEO4O.js.map} +1 -1
- package/dist/{chunk-W23EJNYG.js → chunk-T6Y32SNK.js} +12 -2
- package/dist/chunk-T6Y32SNK.js.map +1 -0
- package/dist/{chunk-O4SMTUOY.js → chunk-W6VULMCO.js} +90 -2
- package/dist/chunk-W6VULMCO.js.map +1 -0
- package/dist/{chunk-DUY7Z2AI.js → chunk-WTWG6QXP.js} +2 -2
- package/dist/{chunk-EDR5SFJN.cjs → chunk-YU7MFR6Y.cjs} +12 -2
- package/dist/chunk-YU7MFR6Y.cjs.map +1 -0
- package/dist/eip712/index.cjs +3 -3
- package/dist/eip712/index.js +2 -2
- package/dist/{index-B7pGBych.d.cts → index-BEx-Q1bW.d.cts} +23 -40
- package/dist/{index-B06IJlHe.d.ts → index-r4xCdQO7.d.ts} +23 -40
- package/dist/index.cjs +178 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +211 -26
- package/dist/index.d.ts +211 -26
- package/dist/index.js +176 -35
- package/dist/index.js.map +1 -1
- package/dist/quoting/index.cjs +3 -3
- package/dist/quoting/index.js +2 -2
- package/dist/swap/index.cjs +3 -2
- package/dist/swap/index.cjs.map +1 -1
- package/dist/swap/index.d.cts +1 -1
- package/dist/swap/index.d.ts +1 -1
- package/dist/swap/index.js +2 -1
- package/package.json +1 -1
- package/dist/chunk-DMW67WBU.cjs.map +0 -1
- package/dist/chunk-EDR5SFJN.cjs.map +0 -1
- package/dist/chunk-GWLEEXM4.cjs.map +0 -1
- package/dist/chunk-O4SMTUOY.js.map +0 -1
- package/dist/chunk-W23EJNYG.js.map +0 -1
- /package/dist/{chunk-I2P3TIP7.js.map → chunk-N5M3BLOV.js.map} +0 -0
- /package/dist/{chunk-DUY7Z2AI.js.map → chunk-WTWG6QXP.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/chunk-FNJZUNK3.cjs","../src/auth/loginMessage.ts","../src/auth/sponsorAuth.ts"],"names":[],"mappings":"AAAA;ACAA,4BAAiE;AAIjE,IAAM,gBAAA,EAAkB,GAAA;AACxB,IAAM,kBAAA,EAAoB,gCAAA;AASnB,SAAS,kBAAA,CAAmB,MAAA,EAAoC;AACrE,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAA;AAAA,IACA,UAAA,EAAY,iBAAA;AAAA,IACZ,QAAA,EAAU,eAAA;AAAA,IACV,SAAA,kBAAW,IAAI,IAAA,CAAK,CAAA;AAAA,IACpB,cAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,EACF,EAAA,EAAI,MAAA;AAEJ,EAAA,GAAA,CAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA;AAClE,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,oCAAoC,CAAA;AAChE,EAAA,GAAA,CAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,kCAAkC,CAAA;AAE5D,EAAA,MAAM,YAAA,EAAc,8BAAA,OAAkB,CAAA;AAEtC,EAAA,MAAM,MAAA,EAAkB,CAAC,CAAA;AACzB,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA;AACA,EAAA;AACA,EAAA;AACP,EAAA;AACI,IAAA;AACA,IAAA;AACR,EAAA;AACW,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACP,EAAA;AACI,IAAA;AACR,EAAA;AACI,EAAA;AACI,IAAA;AACR,EAAA;AACI,EAAA;AACI,IAAA;AACR,EAAA;AAEO,EAAA;AACT;AAOgB;AACR,EAAA;AACI,EAAA;AACE,IAAA;AACZ,EAAA;AAEM,EAAA;AACA,EAAA;AACJ,IAAA;AACF,EAAA;AACK,EAAA;AACO,IAAA;AACZ,EAAA;AACM,EAAA;AAEA,EAAA;AACD,EAAA;AACO,IAAA;AACZ,EAAA;AACM,EAAA;AAGF,EAAA;AACM,EAAA;AACE,IAAA;AACZ,EAAA;AACA,EAAA;AAEI,EAAA;AAEA,EAAA;AACF,IAAA;AACA,IAAA;AACU,IAAA;AACF,MAAA;AACR,IAAA;AACA,IAAA;AACF,EAAA;AAEM,EAAA;AACC,EAAA;AACC,IAAA;AACF,IAAA;AACE,IAAA;AACF,IAAA;AACI,MAAA;AACR,IAAA;AACM,IAAA;AACA,IAAA;AACC,IAAA;AACT,EAAA;AAEY,EAAA;AACN,EAAA;AACA,EAAA;AACM,EAAA;AACA,IAAA;AACZ,EAAA;AACM,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACJ,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACI,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACG,EAAA;AACT;AAQA;AAIQ,EAAA;AACA,EAAA;AACK,IAAA;AACT,IAAA;AACA,IAAA;AACD,EAAA;AACU,EAAA;AACA,IAAA;AACX,EAAA;AAEM,EAAA;AACG,EAAA;AACX;AAMM;AACJ,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD;AAEQ;AACK,EAAA;AACA,EAAA;AACL,EAAA;AACT;AAES;AACD,EAAA;AACF,EAAA;AACQ,IAAA;AACZ,EAAA;AACO,EAAA;AACT;AAES;AAIK,EAAA;AACA,EAAA;AACD,EAAA;AACb;ADlDc;AACA;AE7JL;AAGI;AAEA;AACX,EAAA;AACU,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACV,EAAA;AACF;AAkBgB;AACP,EAAA;AACC,IAAA;AACG,IAAA;AACT,IAAA;AACA,IAAA;AACF,EAAA;AACF;AAES;AACA,EAAA;AACI,IAAA;AACD,IAAA;AACR,IAAA;AACO,IAAA;AACP,IAAA;AACU,IAAA;AACA,IAAA;AACZ,EAAA;AACF;AAEgB;AACP,EAAA;AACG,IAAA;AACD,IAAA;AACP,IAAA;AACS,IAAA;AACX,EAAA;AACF;AAEgB;AACP,EAAA;AACT;AAEA;AAIU,EAAA;AAED,EAAA;AACI,IAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AACH;AAEA;AAKQ,EAAA;AACM,EAAA;AACD,IAAA;AACX,EAAA;AAEI,EAAA;AACO,IAAA;AACX,EAAA;AAEI,EAAA;AACA,EAAA;AACM,IAAA;AAER,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AACK,EAAA;AACG,IAAA;AACX,EAAA;AAEI,EAAA;AACO,IAAA;AACX,EAAA;AAES,EAAA;AACX;AFyHc;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/chunk-FNJZUNK3.cjs","sourcesContent":[null,"import { getAddress, verifyMessage, recoverMessageAddress } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { LoginMessageParams, VerifyLoginResult } from \"./types\";\n\nconst DEFAULT_VERSION = \"1\";\nconst DEFAULT_STATEMENT = \"Sign in with Ethereum to PAFI.\";\n\n/**\n * Build an EIP-4361 login message string.\n *\n * The output is a deterministic plain-text message that the wallet signs via\n * `personal_sign`. The same message can be parsed back with\n * {@link parseLoginMessage} and verified with {@link verifyLoginMessage}.\n */\nexport function createLoginMessage(params: LoginMessageParams): string {\n const {\n domain,\n address,\n chainId,\n nonce,\n uri,\n statement = DEFAULT_STATEMENT,\n version = DEFAULT_VERSION,\n issuedAt = new Date(),\n expirationTime,\n notBefore,\n requestId,\n } = params;\n\n if (!domain) throw new Error(\"createLoginMessage: domain required\");\n if (!nonce) throw new Error(\"createLoginMessage: nonce required\");\n if (!uri) throw new Error(\"createLoginMessage: uri required\");\n\n const checksummed = getAddress(address);\n\n const lines: string[] = [];\n lines.push(`${domain} wants you to sign in with your Ethereum account:`);\n lines.push(checksummed);\n lines.push(\"\");\n if (statement) {\n lines.push(statement);\n lines.push(\"\");\n }\n lines.push(`URI: ${uri}`);\n lines.push(`Version: ${version}`);\n lines.push(`Chain ID: ${chainId}`);\n lines.push(`Nonce: ${nonce}`);\n lines.push(`Issued At: ${issuedAt.toISOString()}`);\n if (expirationTime) {\n lines.push(`Expiration Time: ${expirationTime.toISOString()}`);\n }\n if (notBefore) {\n lines.push(`Not Before: ${notBefore.toISOString()}`);\n }\n if (requestId) {\n lines.push(`Request ID: ${requestId}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Parse a login message string built by {@link createLoginMessage} back into\n * its structured fields. Throws if the message does not match the expected\n * EIP-4361 layout.\n */\nexport function parseLoginMessage(message: string): LoginMessageParams {\n const lines = message.split(\"\\n\");\n if (lines.length < 7) {\n throw new Error(\"parseLoginMessage: message too short\");\n }\n\n const headerLine = lines[0] ?? \"\";\n const headerMatch = headerLine.match(\n /^(?<domain>.+) wants you to sign in with your Ethereum account:$/,\n );\n if (!headerMatch || !headerMatch.groups) {\n throw new Error(\"parseLoginMessage: invalid header line\");\n }\n const domain = headerMatch.groups[\"domain\"]!;\n\n const addressLine = lines[1] ?? \"\";\n if (!/^0x[0-9a-fA-F]{40}$/.test(addressLine)) {\n throw new Error(\"parseLoginMessage: invalid address line\");\n }\n const address = getAddress(addressLine);\n\n // After address: blank line, optional statement + blank line, then key:value lines.\n let cursor = 2;\n if (lines[cursor] !== \"\") {\n throw new Error(\"parseLoginMessage: missing blank line after address\");\n }\n cursor++;\n\n let statement: string | undefined;\n // Statement is present if the next line is not a known key.\n if (cursor < lines.length && !looksLikeKeyValue(lines[cursor]!)) {\n statement = lines[cursor];\n cursor++;\n if (lines[cursor] !== \"\") {\n throw new Error(\"parseLoginMessage: missing blank line after statement\");\n }\n cursor++;\n }\n\n const fields = new Map<string, string>();\n for (; cursor < lines.length; cursor++) {\n const line = lines[cursor]!;\n if (line === \"\") continue;\n const idx = line.indexOf(\": \");\n if (idx === -1) {\n throw new Error(`parseLoginMessage: malformed field line: \"${line}\"`);\n }\n const key = line.slice(0, idx);\n const value = line.slice(idx + 2);\n fields.set(key, value);\n }\n\n const uri = requireField(fields, \"URI\");\n const version = requireField(fields, \"Version\");\n const chainId = Number(requireField(fields, \"Chain ID\"));\n if (!Number.isInteger(chainId)) {\n throw new Error(\"parseLoginMessage: Chain ID is not an integer\");\n }\n const nonce = requireField(fields, \"Nonce\");\n const issuedAt = new Date(requireField(fields, \"Issued At\"));\n const expirationTime = optionalDate(fields, \"Expiration Time\");\n const notBefore = optionalDate(fields, \"Not Before\");\n const requestId = fields.get(\"Request ID\");\n\n const result: LoginMessageParams = {\n domain,\n address,\n chainId,\n nonce,\n uri,\n version,\n issuedAt,\n };\n if (statement !== undefined) result.statement = statement;\n if (expirationTime !== undefined) result.expirationTime = expirationTime;\n if (notBefore !== undefined) result.notBefore = notBefore;\n if (requestId !== undefined) result.requestId = requestId;\n return result;\n}\n\n/**\n * Verify that a login message was signed by the address embedded in the\n * message. Returns `{ valid, address }` where `address` is the recovered\n * signer (checksummed). Does NOT check expiration / not-before / nonce\n * consumption — those are the AuthService's responsibility.\n */\nexport async function verifyLoginMessage(\n message: string,\n signature: Hex,\n): Promise<VerifyLoginResult> {\n const parsed = parseLoginMessage(message);\n const valid = await verifyMessage({\n address: parsed.address,\n message,\n signature,\n });\n if (valid) {\n return { valid: true, address: parsed.address };\n }\n // Recover anyway so callers can log the mismatch.\n const recovered = await recoverMessageAddress({ message, signature });\n return { valid: false, address: getAddress(recovered) as Address };\n}\n\n// -------------------------------------------------------------------------\n// helpers\n// -------------------------------------------------------------------------\n\nconst KNOWN_KEYS = new Set([\n \"URI\",\n \"Version\",\n \"Chain ID\",\n \"Nonce\",\n \"Issued At\",\n \"Expiration Time\",\n \"Not Before\",\n \"Request ID\",\n]);\n\nfunction looksLikeKeyValue(line: string): boolean {\n const idx = line.indexOf(\": \");\n if (idx === -1) return false;\n return KNOWN_KEYS.has(line.slice(0, idx));\n}\n\nfunction requireField(fields: Map<string, string>, key: string): string {\n const value = fields.get(key);\n if (value === undefined) {\n throw new Error(`parseLoginMessage: missing required field \"${key}\"`);\n }\n return value;\n}\n\nfunction optionalDate(\n fields: Map<string, string>,\n key: string,\n): Date | undefined {\n const raw = fields.get(key);\n if (raw === undefined) return undefined;\n return new Date(raw);\n}\n","import { keccak256, recoverTypedDataAddress } from \"viem\";\nimport type { Address, Hex, WalletClient } from \"viem\";\n\nexport const SPONSOR_AUTH_DOMAIN_NAME = \"PafiSponsorAuth\";\n\nexport const SPONSOR_AUTH_TYPES = {\n SponsorAuth: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"sender\", type: \"address\" },\n { name: \"callDataHash\", type: \"bytes32\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"expiresAt\", type: \"uint256\" },\n { name: \"scenario\", type: \"string\" },\n { name: \"issuerId\", type: \"string\" },\n ],\n} as const;\n\nexport interface SponsorAuthPayload {\n chainId: number;\n sender: Address;\n callDataHash: Hex;\n nonce: bigint;\n expiresAt: number;\n scenario: string;\n issuerId: string;\n}\n\nexport interface SponsorAuthVerifyResult {\n ok: boolean;\n recoveredAddress?: Address;\n reason?: \"EXPIRED\" | \"INVALID_SIGNER\" | \"INVALID_SIGNATURE_FORMAT\";\n}\n\nexport function buildSponsorAuthDomain(chainId: number) {\n return {\n name: SPONSOR_AUTH_DOMAIN_NAME,\n version: \"1\",\n chainId,\n verifyingContract: \"0x0000000000000000000000000000000000000000\" as Address,\n };\n}\n\nfunction buildMessage(payload: SponsorAuthPayload) {\n return {\n chainId: BigInt(payload.chainId),\n sender: payload.sender,\n callDataHash: payload.callDataHash,\n nonce: payload.nonce,\n expiresAt: BigInt(payload.expiresAt),\n scenario: payload.scenario,\n issuerId: payload.issuerId,\n };\n}\n\nexport function buildSponsorAuthTypedData(payload: SponsorAuthPayload) {\n return {\n domain: buildSponsorAuthDomain(payload.chainId),\n types: SPONSOR_AUTH_TYPES,\n primaryType: \"SponsorAuth\" as const,\n message: buildMessage(payload),\n };\n}\n\nexport function computeCallDataHash(callData: Hex): Hex {\n return keccak256(callData);\n}\n\nexport async function signSponsorAuth(\n wallet: WalletClient,\n payload: SponsorAuthPayload,\n): Promise<Hex> {\n const { domain, types, primaryType, message } =\n buildSponsorAuthTypedData(payload);\n return wallet.signTypedData({\n account: wallet.account!,\n domain,\n types,\n primaryType,\n message,\n });\n}\n\nexport async function verifySponsorAuth(\n payload: SponsorAuthPayload,\n signature: Hex,\n expectedSigner: Address,\n): Promise<SponsorAuthVerifyResult> {\n const nowSec = Math.floor(Date.now() / 1000);\n if (payload.expiresAt < nowSec) {\n return { ok: false, reason: \"EXPIRED\" };\n }\n\n if (signature.length < 132) {\n return { ok: false, reason: \"INVALID_SIGNATURE_FORMAT\" };\n }\n\n let recovered: Address;\n try {\n const { domain, types, primaryType, message } =\n buildSponsorAuthTypedData(payload);\n recovered = await recoverTypedDataAddress({\n domain,\n types,\n primaryType,\n message,\n signature,\n });\n } catch {\n return { ok: false, reason: \"INVALID_SIGNATURE_FORMAT\" };\n }\n\n if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) {\n return { ok: false, reason: \"INVALID_SIGNER\", recoveredAddress: recovered };\n }\n\n return { ok: true, recoveredAddress: recovered };\n}\n"]}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
COMMON_POOLS,
|
|
6
6
|
POINT_TOKEN_POOLS,
|
|
7
7
|
V4_QUOTER_ADDRESSES
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-S5CCEO4O.js";
|
|
9
9
|
|
|
10
10
|
// src/quoting/routes.ts
|
|
11
11
|
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
@@ -133,4 +133,4 @@ export {
|
|
|
133
133
|
quoteBestRoute,
|
|
134
134
|
findBestQuote
|
|
135
135
|
};
|
|
136
|
-
//# sourceMappingURL=chunk-
|
|
136
|
+
//# sourceMappingURL=chunk-N5M3BLOV.js.map
|
|
@@ -66,6 +66,8 @@ var COMMON_POOLS = {
|
|
|
66
66
|
var POINT_TOKEN_POOLS = {
|
|
67
67
|
// chainId → pointTokenAddress → PoolKey[]
|
|
68
68
|
};
|
|
69
|
+
var ENTRY_POINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
70
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
69
71
|
|
|
70
72
|
export {
|
|
71
73
|
mintRequestTypes,
|
|
@@ -76,6 +78,8 @@ export {
|
|
|
76
78
|
UNIVERSAL_ROUTER_ADDRESSES,
|
|
77
79
|
COMMON_TOKENS,
|
|
78
80
|
COMMON_POOLS,
|
|
79
|
-
POINT_TOKEN_POOLS
|
|
81
|
+
POINT_TOKEN_POOLS,
|
|
82
|
+
ENTRY_POINT_V07,
|
|
83
|
+
PERMIT2_ADDRESS
|
|
80
84
|
};
|
|
81
|
-
//# sourceMappingURL=chunk-
|
|
85
|
+
//# sourceMappingURL=chunk-S5CCEO4O.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts"],"sourcesContent":["import type { Address } from \"viem\";\nimport type { ChainConfig, PoolKey } from \"./types\";\n\n// -------------------------------------------------------------------------\n// EIP-712 type definitions for viem\n// -------------------------------------------------------------------------\n\nexport const mintRequestTypes = {\n MintRequest: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\nexport const burnRequestTypes = {\n BurnRequest: [\n { name: \"from\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\nexport const receiverConsentTypes = {\n ReceiverConsent: [\n { name: \"onBehalfOf\", type: \"address\" },\n { name: \"originalReceiver\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"extData\", type: \"bytes\" },\n ],\n} as const;\n\n// -------------------------------------------------------------------------\n// Chain-indexed constants — add entries here as new chains are supported\n// -------------------------------------------------------------------------\n\nexport const SUPPORTED_CHAINS: Record<number, ChainConfig> = {\n 8453: { name: \"Base\" },\n};\n\nexport const V4_QUOTER_ADDRESSES: Record<number, Address> = {\n 8453: \"0x0d5e0f971ed27fbff6c2837bf31316121532048d\",\n};\n\nexport const UNIVERSAL_ROUTER_ADDRESSES: Record<number, Address> = {\n 8453: \"0x6ff5693b99212da76ad316178a184ab56d299b43\",\n};\n\nexport const COMMON_TOKENS: Record<number, Record<string, Address>> = {\n // Base\n 8453: {\n WETH: \"0x4200000000000000000000000000000000000006\",\n USDC: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n USDT: \"0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2\",\n },\n};\n\nexport const COMMON_POOLS: Record<number, PoolKey[]> = {\n // Base — existing Uniswap V4 pools\n 8453: [\n // WETH/USDC 0.3%\n {\n currency0: \"0x4200000000000000000000000000000000000006\",\n currency1: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n fee: 3000,\n tickSpacing: 60,\n hooks: \"0x0000000000000000000000000000000000000000\",\n },\n // WETH/USDC 0.05%\n {\n currency0: \"0x4200000000000000000000000000000000000006\",\n currency1: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n fee: 500,\n tickSpacing: 10,\n hooks: \"0x0000000000000000000000000000000000000000\",\n },\n ],\n};\n\nexport const POINT_TOKEN_POOLS: Record<number, Record<Address, PoolKey[]>> = {\n // chainId → pointTokenAddress → PoolKey[]\n};\n"],"mappings":";AAOO,IAAM,mBAAmB;AAAA,EAC9B,aAAa;AAAA,IACX,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,IAC9B,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,EACtC;AACF;AAEO,IAAM,mBAAmB;AAAA,EAC9B,aAAa;AAAA,IACX,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,EACtC;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC,iBAAiB;AAAA,IACf,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,IACtC,EAAE,MAAM,oBAAoB,MAAM,UAAU;AAAA,IAC5C,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,IACpC,EAAE,MAAM,WAAW,MAAM,QAAQ;AAAA,EACnC;AACF;AAMO,IAAM,mBAAgD;AAAA,EAC3D,MAAM,EAAE,MAAM,OAAO;AACvB;AAEO,IAAM,sBAA+C;AAAA,EAC1D,MAAM;AACR;AAEO,IAAM,6BAAsD;AAAA,EACjE,MAAM;AACR;AAEO,IAAM,gBAAyD;AAAA;AAAA,EAEpE,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAEO,IAAM,eAA0C;AAAA;AAAA,EAErD,MAAM;AAAA;AAAA,IAEJ;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,aAAa;AAAA,MACb,OAAO;AAAA,IACT;AAAA;AAAA,IAEA;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,aAAa;AAAA,MACb,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,IAAM,oBAAgE;AAAA;AAE7E;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts"],"sourcesContent":["import type { Address } from \"viem\";\nimport type { ChainConfig, PoolKey } from \"./types\";\n\n// -------------------------------------------------------------------------\n// EIP-712 type definitions for viem\n// -------------------------------------------------------------------------\n\nexport const mintRequestTypes = {\n MintRequest: [\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\nexport const burnRequestTypes = {\n BurnRequest: [\n { name: \"from\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\nexport const receiverConsentTypes = {\n ReceiverConsent: [\n { name: \"onBehalfOf\", type: \"address\" },\n { name: \"originalReceiver\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"extData\", type: \"bytes\" },\n ],\n} as const;\n\n// -------------------------------------------------------------------------\n// Chain-indexed constants — add entries here as new chains are supported\n// -------------------------------------------------------------------------\n\nexport const SUPPORTED_CHAINS: Record<number, ChainConfig> = {\n 8453: { name: \"Base\" },\n};\n\nexport const V4_QUOTER_ADDRESSES: Record<number, Address> = {\n 8453: \"0x0d5e0f971ed27fbff6c2837bf31316121532048d\",\n};\n\nexport const UNIVERSAL_ROUTER_ADDRESSES: Record<number, Address> = {\n 8453: \"0x6ff5693b99212da76ad316178a184ab56d299b43\",\n};\n\nexport const COMMON_TOKENS: Record<number, Record<string, Address>> = {\n // Base\n 8453: {\n WETH: \"0x4200000000000000000000000000000000000006\",\n USDC: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n USDT: \"0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2\",\n },\n};\n\nexport const COMMON_POOLS: Record<number, PoolKey[]> = {\n // Base — existing Uniswap V4 pools\n 8453: [\n // WETH/USDC 0.3%\n {\n currency0: \"0x4200000000000000000000000000000000000006\",\n currency1: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n fee: 3000,\n tickSpacing: 60,\n hooks: \"0x0000000000000000000000000000000000000000\",\n },\n // WETH/USDC 0.05%\n {\n currency0: \"0x4200000000000000000000000000000000000006\",\n currency1: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n fee: 500,\n tickSpacing: 10,\n hooks: \"0x0000000000000000000000000000000000000000\",\n },\n ],\n};\n\nexport const POINT_TOKEN_POOLS: Record<number, Record<Address, PoolKey[]>> = {\n // chainId → pointTokenAddress → PoolKey[]\n};\n\n// -------------------------------------------------------------------------\n// Protocol constants — chain-agnostic (same address on every EVM chain)\n// -------------------------------------------------------------------------\n\n/** ERC-4337 v0.7 EntryPoint — deployed deterministically across all EVM chains. */\nexport const ENTRY_POINT_V07: Address = \"0x0000000071727De22E5E9d8BAf0edAc6f37da032\";\n\n/** Permit2 — Uniswap's universal approval contract, same address on all EVM chains. */\nexport const PERMIT2_ADDRESS: Address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\";\n"],"mappings":";AAOO,IAAM,mBAAmB;AAAA,EAC9B,aAAa;AAAA,IACX,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,IAC9B,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,EACtC;AACF;AAEO,IAAM,mBAAmB;AAAA,EAC9B,aAAa;AAAA,IACX,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,EACtC;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC,iBAAiB;AAAA,IACf,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,IACtC,EAAE,MAAM,oBAAoB,MAAM,UAAU;AAAA,IAC5C,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,UAAU;AAAA,IACpC,EAAE,MAAM,WAAW,MAAM,QAAQ;AAAA,EACnC;AACF;AAMO,IAAM,mBAAgD;AAAA,EAC3D,MAAM,EAAE,MAAM,OAAO;AACvB;AAEO,IAAM,sBAA+C;AAAA,EAC1D,MAAM;AACR;AAEO,IAAM,6BAAsD;AAAA,EACjE,MAAM;AACR;AAEO,IAAM,gBAAyD;AAAA;AAAA,EAEpE,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAEO,IAAM,eAA0C;AAAA;AAAA,EAErD,MAAM;AAAA;AAAA,IAEJ;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,aAAa;AAAA,MACb,OAAO;AAAA,IACT;AAAA;AAAA,IAEA;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,aAAa;AAAA,MACb,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,IAAM,oBAAgE;AAAA;AAE7E;AAOO,IAAM,kBAA2B;AAGjC,IAAM,kBAA2B;","names":[]}
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
permit2Abi,
|
|
4
4
|
universalRouterAbi
|
|
5
5
|
} from "./chunk-2PIXFXA2.js";
|
|
6
|
+
import {
|
|
7
|
+
PERMIT2_ADDRESS
|
|
8
|
+
} from "./chunk-S5CCEO4O.js";
|
|
6
9
|
|
|
7
10
|
// src/swap/approval.ts
|
|
8
11
|
import { encodeFunctionData } from "viem";
|
|
@@ -292,12 +295,19 @@ function buildSwapWithGasDeduction(params) {
|
|
|
292
295
|
functionName: "execute",
|
|
293
296
|
args: [commands, inputs, params.deadline]
|
|
294
297
|
});
|
|
298
|
+
const permit2ApproveData = buildPermit2ApprovalCalldata(
|
|
299
|
+
params.pointTokenAddress,
|
|
300
|
+
params.universalRouterAddress,
|
|
301
|
+
params.amountIn,
|
|
302
|
+
Number(params.deadline)
|
|
303
|
+
);
|
|
295
304
|
const operations = [
|
|
296
305
|
erc20ApproveOp(
|
|
297
306
|
params.pointTokenAddress,
|
|
298
|
-
|
|
307
|
+
PERMIT2_ADDRESS,
|
|
299
308
|
params.amountIn
|
|
300
309
|
),
|
|
310
|
+
rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),
|
|
301
311
|
rawCallOp(params.universalRouterAddress, swapCallData)
|
|
302
312
|
];
|
|
303
313
|
if (params.gasFeePt > 0n) {
|
|
@@ -348,4 +358,4 @@ export {
|
|
|
348
358
|
rawCallOp,
|
|
349
359
|
buildSwapWithGasDeduction
|
|
350
360
|
};
|
|
351
|
-
//# sourceMappingURL=chunk-
|
|
361
|
+
//# sourceMappingURL=chunk-T6Y32SNK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/swap/approval.ts","../src/swap/universalRouter.ts","../src/errors.ts","../src/swap/simulate.ts","../src/swap/buildSwapWithGasDeduction.ts","../src/userop/batchExecute.ts","../src/userop/buildUserOperation.ts","../src/userop/operations.ts"],"sourcesContent":["import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex, PublicClient } from \"viem\";\nimport { erc20Abi } from \"../abi/erc20\";\nimport { permit2Abi } from \"../abi/permit2\";\n\nexport async function checkAllowance(\n client: PublicClient,\n token: Address,\n owner: Address,\n spender: Address,\n): Promise<bigint> {\n return client.readContract({\n address: token,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner, spender],\n });\n}\n\n/**\n * Encode an ERC-20 approve(spender, amount) call.\n */\nexport function buildErc20ApprovalCalldata(\n spender: Address,\n amount: bigint,\n): Hex {\n return encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n });\n}\n\n/**\n * Encode a Permit2 approve(token, spender, amount, expiration) call.\n */\nexport function buildPermit2ApprovalCalldata(\n token: Address,\n spender: Address,\n amount: bigint,\n expiration: number,\n): Hex {\n return encodeFunctionData({\n abi: permit2Abi,\n functionName: \"approve\",\n args: [token, spender, amount, expiration],\n });\n}\n","import { encodeAbiParameters, encodePacked } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { PathKey, QuoteResult } from \"../types\";\n\n// -------------------------------------------------------------------------\n// V4 UniversalRouter command / action constants\n// Reference: https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/Actions.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V4 swap */\nexport const V4_SWAP = 0x10 as const;\n\n/** V4 actions */\nexport const SWAP_EXACT_IN_SINGLE = 0x06 as const;\nexport const SWAP_EXACT_IN = 0x07 as const;\nexport const SETTLE_ALL = 0x0c as const;\nexport const TAKE_ALL = 0x0f as const;\n\n// -------------------------------------------------------------------------\n// ABI type strings matching Uniswap's V4Planner encoding\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\n//\n// IMPORTANT: PathKey.fee is uint256 in the V4 Router ABI (not uint24).\n// -------------------------------------------------------------------------\n\n// PathKey components for V4 Router ABI encoding.\n// IMPORTANT: fee is uint256 in the V4 Router (not uint24 as in PoolKey).\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\nconst PATH_KEY_ABI_COMPONENTS = [\n { name: \"intermediateCurrency\", type: \"address\" },\n { name: \"fee\", type: \"uint256\" },\n { name: \"tickSpacing\", type: \"int24\" },\n { name: \"hooks\", type: \"address\" },\n { name: \"hookData\", type: \"bytes\" },\n] as const;\n\nconst EXACT_INPUT_PARAMS_ABI = [\n { name: \"currencyIn\", type: \"address\" },\n {\n name: \"path\",\n type: \"tuple[]\",\n components: PATH_KEY_ABI_COMPONENTS,\n },\n { name: \"amountIn\", type: \"uint128\" },\n { name: \"amountOutMinimum\", type: \"uint128\" },\n] as const;\n\n/**\n * Build the calldata inputs[0] (the V4_SWAP command payload) for\n * UniversalRouter.execute.\n *\n * Actions encoded: SWAP_EXACT_IN → SETTLE_ALL → TAKE_ALL\n *\n * Encoding matches the Uniswap V4 SDK's V4Planner — each action's params\n * are individually ABI-encoded, then wrapped together with the action bytes.\n */\nexport function buildV4SwapInput(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): Hex {\n const actions = encodePacked(\n [\"uint8\", \"uint8\", \"uint8\"],\n [SWAP_EXACT_IN, SETTLE_ALL, TAKE_ALL],\n );\n\n // Param 0: ExactInputParams — encoded as a single tuple so the CalldataDecoder\n // can locate it via a single offset pointer. fee is uint256 per V4 Router spec.\n const swapParam = encodeAbiParameters(\n [{ name: \"swap\", type: \"tuple\", components: EXACT_INPUT_PARAMS_ABI }],\n [\n {\n currencyIn,\n path: path.map((p) => ({\n intermediateCurrency: p.intermediateCurrency,\n fee: BigInt(p.fee),\n tickSpacing: p.tickSpacing,\n hooks: p.hooks,\n hookData: p.hookData,\n })),\n amountIn,\n amountOutMinimum: minAmountOut,\n },\n ],\n );\n\n // Param 1: SETTLE_ALL { currency, maxAmount }\n const settleParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint256\" },\n ],\n [currencyIn, amountIn],\n );\n\n // Param 2: TAKE_ALL { currency, minAmount }\n const takeParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"minAmount\", type: \"uint256\" },\n ],\n [outputCurrency, minAmountOut],\n );\n\n return encodeAbiParameters(\n [\n { name: \"actions\", type: \"bytes\" },\n { name: \"params\", type: \"bytes[]\" },\n ],\n [actions, [swapParam, settleParam, takeParam]],\n );\n}\n\n/**\n * Build the full commands + inputs args for UniversalRouter.execute.\n */\nexport function buildUniversalRouterExecuteArgs(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V4_SWAP]);\n const inputs: Hex[] = [\n buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build UniversalRouter execute args from a quote result.\n *\n * Takes the output of `findBestQuote` / `quoteBestRoute` and produces\n * ready-to-use `{ commands, inputs }` for `UniversalRouter.execute`.\n *\n * @param quote - Quote result containing the path\n * @param currencyIn - Input token address\n * @param currencyOut - Output token address\n * @param amountIn - Exact input amount (same value passed to the quoter)\n * @param minAmountOut - Minimum acceptable output (caller applies slippage)\n *\n * @deprecated Since v1.4 — the Issuer App no longer handles swaps.\n * For the new PT→USDT batch call on PAFI Web (Scenario 4 with\n * EIP-7702 gas deduction), use `buildSwapWithGasDeduction()` (v1.5).\n * This helper is kept for legacy v0.2.x consumers; will be removed in v2.0.\n */\nexport function buildSwapFromQuote(params: {\n quote: QuoteResult;\n currencyIn: Address;\n currencyOut: Address;\n amountIn: bigint;\n minAmountOut: bigint;\n}): { commands: Hex; inputs: Hex[] } {\n return buildUniversalRouterExecuteArgs(\n params.currencyIn,\n params.quote.path,\n params.amountIn,\n params.minAmountOut,\n params.currencyOut,\n );\n}\n","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 type { Address, Hex, PublicClient } from \"viem\";\nimport { universalRouterAbi } from \"../abi/universalRouter\";\nimport { SimulationError } from \"../errors\";\n\nexport interface SwapSimulationResult {\n success: boolean;\n gasEstimate: bigint;\n}\n\n/**\n * Simulate a UniversalRouter.execute swap call via eth_call (no gas spent).\n *\n * Runs the full V4 swap flow — token transfer via Permit2, swap via\n * PoolManager, output settlement — without submitting a transaction.\n * If the simulation reverts, throws a `SimulationError` with the reason.\n *\n * @param client - viem PublicClient\n * @param routerAddress - UniversalRouter contract address\n * @param commands - Packed command bytes (from buildSwapFromQuote)\n * @param inputs - Encoded inputs per command (from buildSwapFromQuote)\n * @param deadline - Unix timestamp after which the tx expires\n * @param from - Address that will execute the swap\n */\nexport async function simulateSwap(\n client: PublicClient,\n routerAddress: Address,\n commands: Hex,\n inputs: Hex[],\n deadline: bigint,\n from: Address,\n): Promise<SwapSimulationResult> {\n try {\n const gasEstimate = await client.estimateContractGas({\n address: routerAddress,\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, deadline],\n account: from,\n });\n\n return { success: true, gasEstimate };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Unknown simulation error\";\n throw new SimulationError(\"swap\", message);\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { universalRouterAbi } from \"../abi/universalRouter\";\nimport type { PathKey } from \"../types\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { PartialUserOperation } from \"../userop/types\";\nimport {\n erc20ApproveOp,\n erc20TransferOp,\n rawCallOp,\n} from \"../userop/operations\";\nimport type { Operation } from \"../userop/types\";\nimport { buildUniversalRouterExecuteArgs } from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\nimport { PERMIT2_ADDRESS } from \"../constants\";\n\n/**\n * v1.5 — Scenario 4: Swap PT → USDT on PAFI Web with gas fee\n * deducted in PT from the user's balance.\n *\n * Builds an unsigned `PartialUserOperation` that packages up to four\n * inner calls into a single `BatchExecutor.execute(calls[])`:\n *\n * 1. `PT.approve(Permit2, amountIn)` — grant Permit2 ERC-20 allowance\n * 2. `Permit2.approve(PT, router, amountIn, deadline)` — authorize\n * the UniversalRouter to pull PT via Permit2\n * 3. `UniversalRouter.execute(commands, inputs, deadline)` — V4 swap\n * PT → USDT; user receives ≥ `minAmountOut` USDT\n * 4. `PT.transfer(feeRecipient, gasFeePt)` — pay the operator back\n * for sponsoring the gas, in PT (omitted when `gasFeePt` is 0)\n *\n * The user's wallet must hold `amountIn + gasFeePt` PT before the\n * UserOp runs. All inner calls execute atomically via EIP-7702\n * delegation (`msg.sender = user`), so a reverting swap unwinds\n * the approvals and fee transfer too.\n *\n * ## Fee model\n *\n * The gas fee is a separate `transfer` after the swap — it does NOT\n * come out of the USDT output, because that output goes straight to\n * the user's wallet with no intermediate hook.\n *\n * If the FE wants \"user receives exactly X USDT after gas\":\n * 1. Quote PT→USDT for candidate `amountIn` values\n * 2. Pick an `amountIn` where `minAmountOut ≈ X`\n * 3. Separately compute `gasFeePt` from the operator's rate\n * 4. Ensure user's PT balance ≥ `amountIn + gasFeePt`\n *\n * ## Order of operations\n *\n * Fee transfer is last so a reverting swap also refunds the fee\n * (atomic batch revert semantics).\n */\nexport interface BuildSwapWithGasDeductionParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** PT token address being swapped. */\n pointTokenAddress: Address;\n /** Destination currency (typically USDT). */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** PT units to swap. User's balance must be ≥ `amountIn + gasFeePt`. */\n amountIn: bigint;\n /**\n * Minimum USDT to accept out of the swap. Caller applies slippage\n * (typically ~0.5-1%) against a fresh quote. Sub-minimum swap reverts.\n */\n minAmountOut: bigint;\n\n /** V4 pool path for the swap. Single-hop = 1 PathKey. */\n swapPath: PathKey[];\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /** PT amount transferred to `feeRecipient` as gas fee recovery. */\n gasFeePt: bigint;\n /** Where the gas fee lands — typically the operator or fee collector. */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative; tune down for cheaper UserOps. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for Scenario 4. Returns a\n * `PartialUserOperation` — caller attaches paymaster sponsorship (via\n * `POST /api/paymaster/sponsor`), adds the user's UserOp-hash\n * signature, and submits to the Bundler.\n *\n * @throws when `amountIn` or `gasFeePt` is not positive, or when\n * `swapPath` is empty (at least one PathKey required).\n */\nexport function buildSwapWithGasDeduction(\n params: BuildSwapWithGasDeductionParams,\n): PartialUserOperation {\n if (params.amountIn <= 0n) {\n throw new Error(\"buildSwapWithGasDeduction: amountIn must be positive\");\n }\n if (params.minAmountOut < 0n) {\n throw new Error(\n \"buildSwapWithGasDeduction: minAmountOut must be non-negative\",\n );\n }\n if (params.gasFeePt < 0n) {\n throw new Error(\n \"buildSwapWithGasDeduction: gasFeePt must be non-negative\",\n );\n }\n if (params.swapPath.length === 0) {\n throw new Error(\n \"buildSwapWithGasDeduction: swapPath must contain at least one PathKey\",\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgs(\n params.pointTokenAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n params.outputTokenAddress,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.pointTokenAddress,\n params.universalRouterAddress,\n params.amountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [\n erc20ApproveOp(\n params.pointTokenAddress,\n PERMIT2_ADDRESS,\n params.amountIn,\n ),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n ];\n\n if (params.gasFeePt > 0n) {\n operations.push(\n erc20TransferOp(\n params.pointTokenAddress,\n params.feeRecipient,\n params.gasFeePt,\n ),\n );\n }\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 700_000n,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import { encodeFunctionData, parseAbi } from \"viem\";\nimport type { 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 * Compatible with OpenZeppelin `Account.execute(Call[])`, Biconomy\n * `executeBatch`, Safe `MultiSend`, and most EIP-7702 delegation\n * targets. The exact deployed address is supplied by the infra team\n * (see [V1.4_V1.5_READINESS.md B2]).\n */\nexport const BATCH_EXECUTOR_ABI = parseAbi([\n \"function execute((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: \"execute\",\n args: [\n operations.map((op) => ({\n target: op.target,\n value: op.value,\n data: op.data,\n })),\n ],\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, 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"],"mappings":"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","names":["encodeFunctionData","encodeFunctionData","encodeFunctionData","erc20Abi","parseAbi","encodeFunctionData"]}
|
|
@@ -155,9 +155,97 @@ function optionalDate(fields, key) {
|
|
|
155
155
|
return new Date(raw);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
// src/auth/sponsorAuth.ts
|
|
159
|
+
import { keccak256, recoverTypedDataAddress } from "viem";
|
|
160
|
+
var SPONSOR_AUTH_DOMAIN_NAME = "PafiSponsorAuth";
|
|
161
|
+
var SPONSOR_AUTH_TYPES = {
|
|
162
|
+
SponsorAuth: [
|
|
163
|
+
{ name: "chainId", type: "uint256" },
|
|
164
|
+
{ name: "sender", type: "address" },
|
|
165
|
+
{ name: "callDataHash", type: "bytes32" },
|
|
166
|
+
{ name: "nonce", type: "uint256" },
|
|
167
|
+
{ name: "expiresAt", type: "uint256" },
|
|
168
|
+
{ name: "scenario", type: "string" },
|
|
169
|
+
{ name: "issuerId", type: "string" }
|
|
170
|
+
]
|
|
171
|
+
};
|
|
172
|
+
function buildSponsorAuthDomain(chainId) {
|
|
173
|
+
return {
|
|
174
|
+
name: SPONSOR_AUTH_DOMAIN_NAME,
|
|
175
|
+
version: "1",
|
|
176
|
+
chainId,
|
|
177
|
+
verifyingContract: "0x0000000000000000000000000000000000000000"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function buildMessage(payload) {
|
|
181
|
+
return {
|
|
182
|
+
chainId: BigInt(payload.chainId),
|
|
183
|
+
sender: payload.sender,
|
|
184
|
+
callDataHash: payload.callDataHash,
|
|
185
|
+
nonce: payload.nonce,
|
|
186
|
+
expiresAt: BigInt(payload.expiresAt),
|
|
187
|
+
scenario: payload.scenario,
|
|
188
|
+
issuerId: payload.issuerId
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function buildSponsorAuthTypedData(payload) {
|
|
192
|
+
return {
|
|
193
|
+
domain: buildSponsorAuthDomain(payload.chainId),
|
|
194
|
+
types: SPONSOR_AUTH_TYPES,
|
|
195
|
+
primaryType: "SponsorAuth",
|
|
196
|
+
message: buildMessage(payload)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function computeCallDataHash(callData) {
|
|
200
|
+
return keccak256(callData);
|
|
201
|
+
}
|
|
202
|
+
async function signSponsorAuth(wallet, payload) {
|
|
203
|
+
const { domain, types, primaryType, message } = buildSponsorAuthTypedData(payload);
|
|
204
|
+
return wallet.signTypedData({
|
|
205
|
+
account: wallet.account,
|
|
206
|
+
domain,
|
|
207
|
+
types,
|
|
208
|
+
primaryType,
|
|
209
|
+
message
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async function verifySponsorAuth(payload, signature, expectedSigner) {
|
|
213
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
214
|
+
if (payload.expiresAt < nowSec) {
|
|
215
|
+
return { ok: false, reason: "EXPIRED" };
|
|
216
|
+
}
|
|
217
|
+
if (signature.length < 132) {
|
|
218
|
+
return { ok: false, reason: "INVALID_SIGNATURE_FORMAT" };
|
|
219
|
+
}
|
|
220
|
+
let recovered;
|
|
221
|
+
try {
|
|
222
|
+
const { domain, types, primaryType, message } = buildSponsorAuthTypedData(payload);
|
|
223
|
+
recovered = await recoverTypedDataAddress({
|
|
224
|
+
domain,
|
|
225
|
+
types,
|
|
226
|
+
primaryType,
|
|
227
|
+
message,
|
|
228
|
+
signature
|
|
229
|
+
});
|
|
230
|
+
} catch {
|
|
231
|
+
return { ok: false, reason: "INVALID_SIGNATURE_FORMAT" };
|
|
232
|
+
}
|
|
233
|
+
if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) {
|
|
234
|
+
return { ok: false, reason: "INVALID_SIGNER", recoveredAddress: recovered };
|
|
235
|
+
}
|
|
236
|
+
return { ok: true, recoveredAddress: recovered };
|
|
237
|
+
}
|
|
238
|
+
|
|
158
239
|
export {
|
|
159
240
|
createLoginMessage,
|
|
160
241
|
parseLoginMessage,
|
|
161
|
-
verifyLoginMessage
|
|
242
|
+
verifyLoginMessage,
|
|
243
|
+
SPONSOR_AUTH_DOMAIN_NAME,
|
|
244
|
+
SPONSOR_AUTH_TYPES,
|
|
245
|
+
buildSponsorAuthDomain,
|
|
246
|
+
buildSponsorAuthTypedData,
|
|
247
|
+
computeCallDataHash,
|
|
248
|
+
signSponsorAuth,
|
|
249
|
+
verifySponsorAuth
|
|
162
250
|
};
|
|
163
|
-
//# sourceMappingURL=chunk-
|
|
251
|
+
//# sourceMappingURL=chunk-W6VULMCO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/loginMessage.ts","../src/auth/sponsorAuth.ts"],"sourcesContent":["import { getAddress, verifyMessage, recoverMessageAddress } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { LoginMessageParams, VerifyLoginResult } from \"./types\";\n\nconst DEFAULT_VERSION = \"1\";\nconst DEFAULT_STATEMENT = \"Sign in with Ethereum to PAFI.\";\n\n/**\n * Build an EIP-4361 login message string.\n *\n * The output is a deterministic plain-text message that the wallet signs via\n * `personal_sign`. The same message can be parsed back with\n * {@link parseLoginMessage} and verified with {@link verifyLoginMessage}.\n */\nexport function createLoginMessage(params: LoginMessageParams): string {\n const {\n domain,\n address,\n chainId,\n nonce,\n uri,\n statement = DEFAULT_STATEMENT,\n version = DEFAULT_VERSION,\n issuedAt = new Date(),\n expirationTime,\n notBefore,\n requestId,\n } = params;\n\n if (!domain) throw new Error(\"createLoginMessage: domain required\");\n if (!nonce) throw new Error(\"createLoginMessage: nonce required\");\n if (!uri) throw new Error(\"createLoginMessage: uri required\");\n\n const checksummed = getAddress(address);\n\n const lines: string[] = [];\n lines.push(`${domain} wants you to sign in with your Ethereum account:`);\n lines.push(checksummed);\n lines.push(\"\");\n if (statement) {\n lines.push(statement);\n lines.push(\"\");\n }\n lines.push(`URI: ${uri}`);\n lines.push(`Version: ${version}`);\n lines.push(`Chain ID: ${chainId}`);\n lines.push(`Nonce: ${nonce}`);\n lines.push(`Issued At: ${issuedAt.toISOString()}`);\n if (expirationTime) {\n lines.push(`Expiration Time: ${expirationTime.toISOString()}`);\n }\n if (notBefore) {\n lines.push(`Not Before: ${notBefore.toISOString()}`);\n }\n if (requestId) {\n lines.push(`Request ID: ${requestId}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Parse a login message string built by {@link createLoginMessage} back into\n * its structured fields. Throws if the message does not match the expected\n * EIP-4361 layout.\n */\nexport function parseLoginMessage(message: string): LoginMessageParams {\n const lines = message.split(\"\\n\");\n if (lines.length < 7) {\n throw new Error(\"parseLoginMessage: message too short\");\n }\n\n const headerLine = lines[0] ?? \"\";\n const headerMatch = headerLine.match(\n /^(?<domain>.+) wants you to sign in with your Ethereum account:$/,\n );\n if (!headerMatch || !headerMatch.groups) {\n throw new Error(\"parseLoginMessage: invalid header line\");\n }\n const domain = headerMatch.groups[\"domain\"]!;\n\n const addressLine = lines[1] ?? \"\";\n if (!/^0x[0-9a-fA-F]{40}$/.test(addressLine)) {\n throw new Error(\"parseLoginMessage: invalid address line\");\n }\n const address = getAddress(addressLine);\n\n // After address: blank line, optional statement + blank line, then key:value lines.\n let cursor = 2;\n if (lines[cursor] !== \"\") {\n throw new Error(\"parseLoginMessage: missing blank line after address\");\n }\n cursor++;\n\n let statement: string | undefined;\n // Statement is present if the next line is not a known key.\n if (cursor < lines.length && !looksLikeKeyValue(lines[cursor]!)) {\n statement = lines[cursor];\n cursor++;\n if (lines[cursor] !== \"\") {\n throw new Error(\"parseLoginMessage: missing blank line after statement\");\n }\n cursor++;\n }\n\n const fields = new Map<string, string>();\n for (; cursor < lines.length; cursor++) {\n const line = lines[cursor]!;\n if (line === \"\") continue;\n const idx = line.indexOf(\": \");\n if (idx === -1) {\n throw new Error(`parseLoginMessage: malformed field line: \"${line}\"`);\n }\n const key = line.slice(0, idx);\n const value = line.slice(idx + 2);\n fields.set(key, value);\n }\n\n const uri = requireField(fields, \"URI\");\n const version = requireField(fields, \"Version\");\n const chainId = Number(requireField(fields, \"Chain ID\"));\n if (!Number.isInteger(chainId)) {\n throw new Error(\"parseLoginMessage: Chain ID is not an integer\");\n }\n const nonce = requireField(fields, \"Nonce\");\n const issuedAt = new Date(requireField(fields, \"Issued At\"));\n const expirationTime = optionalDate(fields, \"Expiration Time\");\n const notBefore = optionalDate(fields, \"Not Before\");\n const requestId = fields.get(\"Request ID\");\n\n const result: LoginMessageParams = {\n domain,\n address,\n chainId,\n nonce,\n uri,\n version,\n issuedAt,\n };\n if (statement !== undefined) result.statement = statement;\n if (expirationTime !== undefined) result.expirationTime = expirationTime;\n if (notBefore !== undefined) result.notBefore = notBefore;\n if (requestId !== undefined) result.requestId = requestId;\n return result;\n}\n\n/**\n * Verify that a login message was signed by the address embedded in the\n * message. Returns `{ valid, address }` where `address` is the recovered\n * signer (checksummed). Does NOT check expiration / not-before / nonce\n * consumption — those are the AuthService's responsibility.\n */\nexport async function verifyLoginMessage(\n message: string,\n signature: Hex,\n): Promise<VerifyLoginResult> {\n const parsed = parseLoginMessage(message);\n const valid = await verifyMessage({\n address: parsed.address,\n message,\n signature,\n });\n if (valid) {\n return { valid: true, address: parsed.address };\n }\n // Recover anyway so callers can log the mismatch.\n const recovered = await recoverMessageAddress({ message, signature });\n return { valid: false, address: getAddress(recovered) as Address };\n}\n\n// -------------------------------------------------------------------------\n// helpers\n// -------------------------------------------------------------------------\n\nconst KNOWN_KEYS = new Set([\n \"URI\",\n \"Version\",\n \"Chain ID\",\n \"Nonce\",\n \"Issued At\",\n \"Expiration Time\",\n \"Not Before\",\n \"Request ID\",\n]);\n\nfunction looksLikeKeyValue(line: string): boolean {\n const idx = line.indexOf(\": \");\n if (idx === -1) return false;\n return KNOWN_KEYS.has(line.slice(0, idx));\n}\n\nfunction requireField(fields: Map<string, string>, key: string): string {\n const value = fields.get(key);\n if (value === undefined) {\n throw new Error(`parseLoginMessage: missing required field \"${key}\"`);\n }\n return value;\n}\n\nfunction optionalDate(\n fields: Map<string, string>,\n key: string,\n): Date | undefined {\n const raw = fields.get(key);\n if (raw === undefined) return undefined;\n return new Date(raw);\n}\n","import { keccak256, recoverTypedDataAddress } from \"viem\";\nimport type { Address, Hex, WalletClient } from \"viem\";\n\nexport const SPONSOR_AUTH_DOMAIN_NAME = \"PafiSponsorAuth\";\n\nexport const SPONSOR_AUTH_TYPES = {\n SponsorAuth: [\n { name: \"chainId\", type: \"uint256\" },\n { name: \"sender\", type: \"address\" },\n { name: \"callDataHash\", type: \"bytes32\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"expiresAt\", type: \"uint256\" },\n { name: \"scenario\", type: \"string\" },\n { name: \"issuerId\", type: \"string\" },\n ],\n} as const;\n\nexport interface SponsorAuthPayload {\n chainId: number;\n sender: Address;\n callDataHash: Hex;\n nonce: bigint;\n expiresAt: number;\n scenario: string;\n issuerId: string;\n}\n\nexport interface SponsorAuthVerifyResult {\n ok: boolean;\n recoveredAddress?: Address;\n reason?: \"EXPIRED\" | \"INVALID_SIGNER\" | \"INVALID_SIGNATURE_FORMAT\";\n}\n\nexport function buildSponsorAuthDomain(chainId: number) {\n return {\n name: SPONSOR_AUTH_DOMAIN_NAME,\n version: \"1\",\n chainId,\n verifyingContract: \"0x0000000000000000000000000000000000000000\" as Address,\n };\n}\n\nfunction buildMessage(payload: SponsorAuthPayload) {\n return {\n chainId: BigInt(payload.chainId),\n sender: payload.sender,\n callDataHash: payload.callDataHash,\n nonce: payload.nonce,\n expiresAt: BigInt(payload.expiresAt),\n scenario: payload.scenario,\n issuerId: payload.issuerId,\n };\n}\n\nexport function buildSponsorAuthTypedData(payload: SponsorAuthPayload) {\n return {\n domain: buildSponsorAuthDomain(payload.chainId),\n types: SPONSOR_AUTH_TYPES,\n primaryType: \"SponsorAuth\" as const,\n message: buildMessage(payload),\n };\n}\n\nexport function computeCallDataHash(callData: Hex): Hex {\n return keccak256(callData);\n}\n\nexport async function signSponsorAuth(\n wallet: WalletClient,\n payload: SponsorAuthPayload,\n): Promise<Hex> {\n const { domain, types, primaryType, message } =\n buildSponsorAuthTypedData(payload);\n return wallet.signTypedData({\n account: wallet.account!,\n domain,\n types,\n primaryType,\n message,\n });\n}\n\nexport async function verifySponsorAuth(\n payload: SponsorAuthPayload,\n signature: Hex,\n expectedSigner: Address,\n): Promise<SponsorAuthVerifyResult> {\n const nowSec = Math.floor(Date.now() / 1000);\n if (payload.expiresAt < nowSec) {\n return { ok: false, reason: \"EXPIRED\" };\n }\n\n if (signature.length < 132) {\n return { ok: false, reason: \"INVALID_SIGNATURE_FORMAT\" };\n }\n\n let recovered: Address;\n try {\n const { domain, types, primaryType, message } =\n buildSponsorAuthTypedData(payload);\n recovered = await recoverTypedDataAddress({\n domain,\n types,\n primaryType,\n message,\n signature,\n });\n } catch {\n return { ok: false, reason: \"INVALID_SIGNATURE_FORMAT\" };\n }\n\n if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) {\n return { ok: false, reason: \"INVALID_SIGNER\", recoveredAddress: recovered };\n }\n\n return { ok: true, recoveredAddress: recovered };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
burnRequestTypes,
|
|
3
3
|
mintRequestTypes,
|
|
4
4
|
receiverConsentTypes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-S5CCEO4O.js";
|
|
6
6
|
|
|
7
7
|
// src/eip712/domain.ts
|
|
8
8
|
function buildDomain(config) {
|
|
@@ -140,4 +140,4 @@ export {
|
|
|
140
140
|
signReceiverConsent,
|
|
141
141
|
verifyReceiverConsent
|
|
142
142
|
};
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
143
|
+
//# sourceMappingURL=chunk-WTWG6QXP.js.map
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
var _chunkIPXARZ6Fcjs = require('./chunk-IPXARZ6F.cjs');
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
var _chunk52SZJDFTcjs = require('./chunk-52SZJDFT.cjs');
|
|
9
|
+
|
|
7
10
|
// src/swap/approval.ts
|
|
8
11
|
var _viem = require('viem');
|
|
9
12
|
async function checkAllowance(client, token, owner, spender) {
|
|
@@ -292,12 +295,19 @@ function buildSwapWithGasDeduction(params) {
|
|
|
292
295
|
functionName: "execute",
|
|
293
296
|
args: [commands, inputs, params.deadline]
|
|
294
297
|
});
|
|
298
|
+
const permit2ApproveData = buildPermit2ApprovalCalldata(
|
|
299
|
+
params.pointTokenAddress,
|
|
300
|
+
params.universalRouterAddress,
|
|
301
|
+
params.amountIn,
|
|
302
|
+
Number(params.deadline)
|
|
303
|
+
);
|
|
295
304
|
const operations = [
|
|
296
305
|
erc20ApproveOp(
|
|
297
306
|
params.pointTokenAddress,
|
|
298
|
-
|
|
307
|
+
_chunk52SZJDFTcjs.PERMIT2_ADDRESS,
|
|
299
308
|
params.amountIn
|
|
300
309
|
),
|
|
310
|
+
rawCallOp(_chunk52SZJDFTcjs.PERMIT2_ADDRESS, permit2ApproveData),
|
|
301
311
|
rawCallOp(params.universalRouterAddress, swapCallData)
|
|
302
312
|
];
|
|
303
313
|
if (params.gasFeePt > 0n) {
|
|
@@ -348,4 +358,4 @@ function buildSwapWithGasDeduction(params) {
|
|
|
348
358
|
|
|
349
359
|
|
|
350
360
|
exports.PafiSDKError = PafiSDKError; exports.ConfigurationError = ConfigurationError; exports.SigningError = SigningError; exports.SimulationError = SimulationError; exports.ApiError = ApiError; exports.checkAllowance = checkAllowance; exports.buildErc20ApprovalCalldata = buildErc20ApprovalCalldata; exports.buildPermit2ApprovalCalldata = buildPermit2ApprovalCalldata; exports.V4_SWAP = V4_SWAP; exports.SWAP_EXACT_IN = SWAP_EXACT_IN; exports.SETTLE_ALL = SETTLE_ALL; exports.TAKE_ALL = TAKE_ALL; exports.buildV4SwapInput = buildV4SwapInput; exports.buildUniversalRouterExecuteArgs = buildUniversalRouterExecuteArgs; exports.buildSwapFromQuote = buildSwapFromQuote; exports.simulateSwap = simulateSwap; exports.BATCH_EXECUTOR_ABI = BATCH_EXECUTOR_ABI; exports.encodeBatchExecute = encodeBatchExecute; exports.buildPartialUserOperation = buildPartialUserOperation; exports.assembleUserOperation = assembleUserOperation; exports.erc20TransferOp = erc20TransferOp; exports.erc20ApproveOp = erc20ApproveOp; exports.erc20BurnOp = erc20BurnOp; exports.rawCallOp = rawCallOp; exports.buildSwapWithGasDeduction = buildSwapWithGasDeduction;
|
|
351
|
-
//# sourceMappingURL=chunk-
|
|
361
|
+
//# sourceMappingURL=chunk-YU7MFR6Y.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/chunk-YU7MFR6Y.cjs","../src/swap/approval.ts","../src/swap/universalRouter.ts","../src/errors.ts","../src/swap/simulate.ts","../src/swap/buildSwapWithGasDeduction.ts","../src/userop/batchExecute.ts","../src/userop/buildUserOperation.ts","../src/userop/operations.ts"],"names":["encodeFunctionData","erc20Abi"],"mappings":"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G,MAAA;AAClB,IAAA;AACH,EAAA;AACF;AAWa;AACJ,EAAA;AACG,IAAA;AACD,IAAA;AACkB,IAAA;AAClBA,MAAAA;AACS,MAAA;AACQ,MAAA;AACvB,IAAA;AACH,EAAA;AACF;AAWuE;AAC9D,EAAA;AACG,IAAA;AACD,IAAA;AACkB,IAAA;AAClB,MAAA;AACS,MAAA;AACD,MAAA;AACd,IAAA;AACH,EAAA;AACF;AAWa;AACkB,EAAA;AAC/B;ARmLwD;AACA;AKlKhC;AACK,EAAA;AACT,IAAA;AAClB,EAAA;AAC8B,EAAA;AAClB,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAC0B,EAAA;AACd,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AACkC,EAAA;AACtB,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAE6B,EAAA;AACpB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACT,EAAA;AAE6C,EAAA;AACtC,IAAA;AACS,IAAA;AAC0B,IAAA;AACzC,EAAA;AAE+B,EAAA;AACvB,IAAA;AACA,IAAA;AACA,IAAA;AACe,IAAA;AACxB,EAAA;AAEgC,EAAA;AAC9B,IAAA;AACS,MAAA;AACP,MAAA;AACO,MAAA;AACT,IAAA;AAC6C,IAAA;AACJ,IAAA;AAC3C,EAAA;AAE0B,EAAA;AACb,IAAA;AACT,MAAA;AACS,QAAA;AACA,QAAA;AACA,QAAA;AACT,MAAA;AACF,IAAA;AACF,EAAA;AAEiC,EAAA;AAChB,IAAA;AACD,IAAA;AACd,IAAA;AACW,IAAA;AACuC,MAAA;AAE5B,MAAA;AACkB,MAAA;AACxC,IAAA;AACD,EAAA;AACH;AL6JwD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/chunk-YU7MFR6Y.cjs","sourcesContent":[null,"import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex, PublicClient } from \"viem\";\nimport { erc20Abi } from \"../abi/erc20\";\nimport { permit2Abi } from \"../abi/permit2\";\n\nexport async function checkAllowance(\n client: PublicClient,\n token: Address,\n owner: Address,\n spender: Address,\n): Promise<bigint> {\n return client.readContract({\n address: token,\n abi: erc20Abi,\n functionName: \"allowance\",\n args: [owner, spender],\n });\n}\n\n/**\n * Encode an ERC-20 approve(spender, amount) call.\n */\nexport function buildErc20ApprovalCalldata(\n spender: Address,\n amount: bigint,\n): Hex {\n return encodeFunctionData({\n abi: erc20Abi,\n functionName: \"approve\",\n args: [spender, amount],\n });\n}\n\n/**\n * Encode a Permit2 approve(token, spender, amount, expiration) call.\n */\nexport function buildPermit2ApprovalCalldata(\n token: Address,\n spender: Address,\n amount: bigint,\n expiration: number,\n): Hex {\n return encodeFunctionData({\n abi: permit2Abi,\n functionName: \"approve\",\n args: [token, spender, amount, expiration],\n });\n}\n","import { encodeAbiParameters, encodePacked } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport type { PathKey, QuoteResult } from \"../types\";\n\n// -------------------------------------------------------------------------\n// V4 UniversalRouter command / action constants\n// Reference: https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/Actions.sol\n// -------------------------------------------------------------------------\n\n/** UniversalRouter command byte for V4 swap */\nexport const V4_SWAP = 0x10 as const;\n\n/** V4 actions */\nexport const SWAP_EXACT_IN_SINGLE = 0x06 as const;\nexport const SWAP_EXACT_IN = 0x07 as const;\nexport const SETTLE_ALL = 0x0c as const;\nexport const TAKE_ALL = 0x0f as const;\n\n// -------------------------------------------------------------------------\n// ABI type strings matching Uniswap's V4Planner encoding\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\n//\n// IMPORTANT: PathKey.fee is uint256 in the V4 Router ABI (not uint24).\n// -------------------------------------------------------------------------\n\n// PathKey components for V4 Router ABI encoding.\n// IMPORTANT: fee is uint256 in the V4 Router (not uint24 as in PoolKey).\n// Reference: https://github.com/Uniswap/sdks/blob/main/sdks/v4-sdk/src/utils/v4Planner.ts\nconst PATH_KEY_ABI_COMPONENTS = [\n { name: \"intermediateCurrency\", type: \"address\" },\n { name: \"fee\", type: \"uint256\" },\n { name: \"tickSpacing\", type: \"int24\" },\n { name: \"hooks\", type: \"address\" },\n { name: \"hookData\", type: \"bytes\" },\n] as const;\n\nconst EXACT_INPUT_PARAMS_ABI = [\n { name: \"currencyIn\", type: \"address\" },\n {\n name: \"path\",\n type: \"tuple[]\",\n components: PATH_KEY_ABI_COMPONENTS,\n },\n { name: \"amountIn\", type: \"uint128\" },\n { name: \"amountOutMinimum\", type: \"uint128\" },\n] as const;\n\n/**\n * Build the calldata inputs[0] (the V4_SWAP command payload) for\n * UniversalRouter.execute.\n *\n * Actions encoded: SWAP_EXACT_IN → SETTLE_ALL → TAKE_ALL\n *\n * Encoding matches the Uniswap V4 SDK's V4Planner — each action's params\n * are individually ABI-encoded, then wrapped together with the action bytes.\n */\nexport function buildV4SwapInput(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): Hex {\n const actions = encodePacked(\n [\"uint8\", \"uint8\", \"uint8\"],\n [SWAP_EXACT_IN, SETTLE_ALL, TAKE_ALL],\n );\n\n // Param 0: ExactInputParams — encoded as a single tuple so the CalldataDecoder\n // can locate it via a single offset pointer. fee is uint256 per V4 Router spec.\n const swapParam = encodeAbiParameters(\n [{ name: \"swap\", type: \"tuple\", components: EXACT_INPUT_PARAMS_ABI }],\n [\n {\n currencyIn,\n path: path.map((p) => ({\n intermediateCurrency: p.intermediateCurrency,\n fee: BigInt(p.fee),\n tickSpacing: p.tickSpacing,\n hooks: p.hooks,\n hookData: p.hookData,\n })),\n amountIn,\n amountOutMinimum: minAmountOut,\n },\n ],\n );\n\n // Param 1: SETTLE_ALL { currency, maxAmount }\n const settleParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"maxAmount\", type: \"uint256\" },\n ],\n [currencyIn, amountIn],\n );\n\n // Param 2: TAKE_ALL { currency, minAmount }\n const takeParam = encodeAbiParameters(\n [\n { name: \"currency\", type: \"address\" },\n { name: \"minAmount\", type: \"uint256\" },\n ],\n [outputCurrency, minAmountOut],\n );\n\n return encodeAbiParameters(\n [\n { name: \"actions\", type: \"bytes\" },\n { name: \"params\", type: \"bytes[]\" },\n ],\n [actions, [swapParam, settleParam, takeParam]],\n );\n}\n\n/**\n * Build the full commands + inputs args for UniversalRouter.execute.\n */\nexport function buildUniversalRouterExecuteArgs(\n currencyIn: Address,\n path: PathKey[],\n amountIn: bigint,\n minAmountOut: bigint,\n outputCurrency: Address,\n): { commands: Hex; inputs: Hex[] } {\n const commands = encodePacked([\"uint8\"], [V4_SWAP]);\n const inputs: Hex[] = [\n buildV4SwapInput(currencyIn, path, amountIn, minAmountOut, outputCurrency),\n ];\n return { commands, inputs };\n}\n\n/**\n * Build UniversalRouter execute args from a quote result.\n *\n * Takes the output of `findBestQuote` / `quoteBestRoute` and produces\n * ready-to-use `{ commands, inputs }` for `UniversalRouter.execute`.\n *\n * @param quote - Quote result containing the path\n * @param currencyIn - Input token address\n * @param currencyOut - Output token address\n * @param amountIn - Exact input amount (same value passed to the quoter)\n * @param minAmountOut - Minimum acceptable output (caller applies slippage)\n *\n * @deprecated Since v1.4 — the Issuer App no longer handles swaps.\n * For the new PT→USDT batch call on PAFI Web (Scenario 4 with\n * EIP-7702 gas deduction), use `buildSwapWithGasDeduction()` (v1.5).\n * This helper is kept for legacy v0.2.x consumers; will be removed in v2.0.\n */\nexport function buildSwapFromQuote(params: {\n quote: QuoteResult;\n currencyIn: Address;\n currencyOut: Address;\n amountIn: bigint;\n minAmountOut: bigint;\n}): { commands: Hex; inputs: Hex[] } {\n return buildUniversalRouterExecuteArgs(\n params.currencyIn,\n params.quote.path,\n params.amountIn,\n params.minAmountOut,\n params.currencyOut,\n );\n}\n","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 type { Address, Hex, PublicClient } from \"viem\";\nimport { universalRouterAbi } from \"../abi/universalRouter\";\nimport { SimulationError } from \"../errors\";\n\nexport interface SwapSimulationResult {\n success: boolean;\n gasEstimate: bigint;\n}\n\n/**\n * Simulate a UniversalRouter.execute swap call via eth_call (no gas spent).\n *\n * Runs the full V4 swap flow — token transfer via Permit2, swap via\n * PoolManager, output settlement — without submitting a transaction.\n * If the simulation reverts, throws a `SimulationError` with the reason.\n *\n * @param client - viem PublicClient\n * @param routerAddress - UniversalRouter contract address\n * @param commands - Packed command bytes (from buildSwapFromQuote)\n * @param inputs - Encoded inputs per command (from buildSwapFromQuote)\n * @param deadline - Unix timestamp after which the tx expires\n * @param from - Address that will execute the swap\n */\nexport async function simulateSwap(\n client: PublicClient,\n routerAddress: Address,\n commands: Hex,\n inputs: Hex[],\n deadline: bigint,\n from: Address,\n): Promise<SwapSimulationResult> {\n try {\n const gasEstimate = await client.estimateContractGas({\n address: routerAddress,\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, deadline],\n account: from,\n });\n\n return { success: true, gasEstimate };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Unknown simulation error\";\n throw new SimulationError(\"swap\", message);\n }\n}\n","import { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { universalRouterAbi } from \"../abi/universalRouter\";\nimport type { PathKey } from \"../types\";\nimport { buildPartialUserOperation } from \"../userop/buildUserOperation\";\nimport type { PartialUserOperation } from \"../userop/types\";\nimport {\n erc20ApproveOp,\n erc20TransferOp,\n rawCallOp,\n} from \"../userop/operations\";\nimport type { Operation } from \"../userop/types\";\nimport { buildUniversalRouterExecuteArgs } from \"./universalRouter\";\nimport { buildPermit2ApprovalCalldata } from \"./approval\";\nimport { PERMIT2_ADDRESS } from \"../constants\";\n\n/**\n * v1.5 — Scenario 4: Swap PT → USDT on PAFI Web with gas fee\n * deducted in PT from the user's balance.\n *\n * Builds an unsigned `PartialUserOperation` that packages up to four\n * inner calls into a single `BatchExecutor.execute(calls[])`:\n *\n * 1. `PT.approve(Permit2, amountIn)` — grant Permit2 ERC-20 allowance\n * 2. `Permit2.approve(PT, router, amountIn, deadline)` — authorize\n * the UniversalRouter to pull PT via Permit2\n * 3. `UniversalRouter.execute(commands, inputs, deadline)` — V4 swap\n * PT → USDT; user receives ≥ `minAmountOut` USDT\n * 4. `PT.transfer(feeRecipient, gasFeePt)` — pay the operator back\n * for sponsoring the gas, in PT (omitted when `gasFeePt` is 0)\n *\n * The user's wallet must hold `amountIn + gasFeePt` PT before the\n * UserOp runs. All inner calls execute atomically via EIP-7702\n * delegation (`msg.sender = user`), so a reverting swap unwinds\n * the approvals and fee transfer too.\n *\n * ## Fee model\n *\n * The gas fee is a separate `transfer` after the swap — it does NOT\n * come out of the USDT output, because that output goes straight to\n * the user's wallet with no intermediate hook.\n *\n * If the FE wants \"user receives exactly X USDT after gas\":\n * 1. Quote PT→USDT for candidate `amountIn` values\n * 2. Pick an `amountIn` where `minAmountOut ≈ X`\n * 3. Separately compute `gasFeePt` from the operator's rate\n * 4. Ensure user's PT balance ≥ `amountIn + gasFeePt`\n *\n * ## Order of operations\n *\n * Fee transfer is last so a reverting swap also refunds the fee\n * (atomic batch revert semantics).\n */\nexport interface BuildSwapWithGasDeductionParams {\n /** User's EOA (with EIP-7702 delegation to BatchExecutor). */\n userAddress: Address;\n /** ERC-4337 account nonce — fetched from EntryPoint by the caller. */\n aaNonce: bigint;\n\n /** PT token address being swapped. */\n pointTokenAddress: Address;\n /** Destination currency (typically USDT). */\n outputTokenAddress: Address;\n /** UniversalRouter contract address (chain-specific). */\n universalRouterAddress: Address;\n\n /** PT units to swap. User's balance must be ≥ `amountIn + gasFeePt`. */\n amountIn: bigint;\n /**\n * Minimum USDT to accept out of the swap. Caller applies slippage\n * (typically ~0.5-1%) against a fresh quote. Sub-minimum swap reverts.\n */\n minAmountOut: bigint;\n\n /** V4 pool path for the swap. Single-hop = 1 PathKey. */\n swapPath: PathKey[];\n /** Unix seconds. After this, the router rejects the swap. */\n deadline: bigint;\n\n /** PT amount transferred to `feeRecipient` as gas fee recovery. */\n gasFeePt: bigint;\n /** Where the gas fee lands — typically the operator or fee collector. */\n feeRecipient: Address;\n\n /** Override ERC-4337 gas estimates. Defaults are conservative; tune down for cheaper UserOps. */\n gasLimits?: {\n callGasLimit?: bigint;\n verificationGasLimit?: bigint;\n preVerificationGas?: bigint;\n };\n}\n\n/**\n * Build an unsigned UserOp for Scenario 4. Returns a\n * `PartialUserOperation` — caller attaches paymaster sponsorship (via\n * `POST /api/paymaster/sponsor`), adds the user's UserOp-hash\n * signature, and submits to the Bundler.\n *\n * @throws when `amountIn` or `gasFeePt` is not positive, or when\n * `swapPath` is empty (at least one PathKey required).\n */\nexport function buildSwapWithGasDeduction(\n params: BuildSwapWithGasDeductionParams,\n): PartialUserOperation {\n if (params.amountIn <= 0n) {\n throw new Error(\"buildSwapWithGasDeduction: amountIn must be positive\");\n }\n if (params.minAmountOut < 0n) {\n throw new Error(\n \"buildSwapWithGasDeduction: minAmountOut must be non-negative\",\n );\n }\n if (params.gasFeePt < 0n) {\n throw new Error(\n \"buildSwapWithGasDeduction: gasFeePt must be non-negative\",\n );\n }\n if (params.swapPath.length === 0) {\n throw new Error(\n \"buildSwapWithGasDeduction: swapPath must contain at least one PathKey\",\n );\n }\n\n const { commands, inputs } = buildUniversalRouterExecuteArgs(\n params.pointTokenAddress,\n params.swapPath,\n params.amountIn,\n params.minAmountOut,\n params.outputTokenAddress,\n );\n\n const swapCallData: Hex = encodeFunctionData({\n abi: universalRouterAbi,\n functionName: \"execute\",\n args: [commands, inputs, params.deadline],\n });\n\n const permit2ApproveData: Hex = buildPermit2ApprovalCalldata(\n params.pointTokenAddress,\n params.universalRouterAddress,\n params.amountIn,\n Number(params.deadline),\n );\n\n const operations: Operation[] = [\n erc20ApproveOp(\n params.pointTokenAddress,\n PERMIT2_ADDRESS,\n params.amountIn,\n ),\n rawCallOp(PERMIT2_ADDRESS, permit2ApproveData),\n rawCallOp(params.universalRouterAddress, swapCallData),\n ];\n\n if (params.gasFeePt > 0n) {\n operations.push(\n erc20TransferOp(\n params.pointTokenAddress,\n params.feeRecipient,\n params.gasFeePt,\n ),\n );\n }\n\n return buildPartialUserOperation({\n sender: params.userAddress,\n nonce: params.aaNonce,\n operations,\n gasLimits: {\n callGasLimit: params.gasLimits?.callGasLimit ?? 700_000n,\n verificationGasLimit:\n params.gasLimits?.verificationGasLimit ?? 150_000n,\n preVerificationGas: params.gasLimits?.preVerificationGas ?? 50_000n,\n },\n });\n}\n","import { encodeFunctionData, parseAbi } from \"viem\";\nimport type { 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 * Compatible with OpenZeppelin `Account.execute(Call[])`, Biconomy\n * `executeBatch`, Safe `MultiSend`, and most EIP-7702 delegation\n * targets. The exact deployed address is supplied by the infra team\n * (see [V1.4_V1.5_READINESS.md B2]).\n */\nexport const BATCH_EXECUTOR_ABI = parseAbi([\n \"function execute((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: \"execute\",\n args: [\n operations.map((op) => ({\n target: op.target,\n value: op.value,\n data: op.data,\n })),\n ],\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, 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"]}
|
package/dist/eip712/index.cjs
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
13
|
-
require('../chunk-
|
|
12
|
+
var _chunk2PY5RNVScjs = require('../chunk-2PY5RNVS.cjs');
|
|
13
|
+
require('../chunk-52SZJDFT.cjs');
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
@@ -22,5 +22,5 @@ require('../chunk-DMW67WBU.cjs');
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
exports.buildBurnRequestTypedData =
|
|
25
|
+
exports.buildBurnRequestTypedData = _chunk2PY5RNVScjs.buildBurnRequestTypedData; exports.buildDomain = _chunk2PY5RNVScjs.buildDomain; exports.buildMintRequestTypedData = _chunk2PY5RNVScjs.buildMintRequestTypedData; exports.buildReceiverConsentTypedData = _chunk2PY5RNVScjs.buildReceiverConsentTypedData; exports.signBurnRequest = _chunk2PY5RNVScjs.signBurnRequest; exports.signMintRequest = _chunk2PY5RNVScjs.signMintRequest; exports.signReceiverConsent = _chunk2PY5RNVScjs.signReceiverConsent; exports.verifyBurnRequest = _chunk2PY5RNVScjs.verifyBurnRequest; exports.verifyMintRequest = _chunk2PY5RNVScjs.verifyMintRequest; exports.verifyReceiverConsent = _chunk2PY5RNVScjs.verifyReceiverConsent;
|
|
26
26
|
//# sourceMappingURL=index.cjs.map
|
package/dist/eip712/index.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
verifyBurnRequest,
|
|
10
10
|
verifyMintRequest,
|
|
11
11
|
verifyReceiverConsent
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
} from "../chunk-WTWG6QXP.js";
|
|
13
|
+
import "../chunk-S5CCEO4O.js";
|
|
14
14
|
export {
|
|
15
15
|
buildBurnRequestTypedData,
|
|
16
16
|
buildDomain,
|
|
@@ -81,12 +81,6 @@ interface SwapSimulationResult {
|
|
|
81
81
|
*/
|
|
82
82
|
declare function simulateSwap(client: PublicClient, routerAddress: Address, commands: Hex, inputs: Hex[], deadline: bigint, from: Address): Promise<SwapSimulationResult>;
|
|
83
83
|
|
|
84
|
-
/**
|
|
85
|
-
* ERC-4337 v0.7 EntryPoint standard address (deployed deterministically
|
|
86
|
-
* at the same address across chains).
|
|
87
|
-
* https://eips.ethereum.org/EIPS/eip-4337
|
|
88
|
-
*/
|
|
89
|
-
declare const ENTRY_POINT_V07: Address;
|
|
90
84
|
/**
|
|
91
85
|
* A single call inside a batch. `BatchExecutor.execute(Call[])` iterates
|
|
92
86
|
* and invokes each one. When the batch runs via EIP-7702 delegation,
|
|
@@ -150,35 +144,32 @@ interface UserOpReceipt {
|
|
|
150
144
|
declare const ZERO_VALUE = 0n;
|
|
151
145
|
|
|
152
146
|
/**
|
|
153
|
-
* v1.5 — Scenario 4: Swap PT → USDT on PAFI Web with
|
|
154
|
-
* deducted in PT
|
|
147
|
+
* v1.5 — Scenario 4: Swap PT → USDT on PAFI Web with gas fee
|
|
148
|
+
* deducted in PT from the user's balance.
|
|
155
149
|
*
|
|
156
|
-
* Builds an unsigned `PartialUserOperation` that packages
|
|
157
|
-
* calls into a single `BatchExecutor.execute(calls[])`:
|
|
150
|
+
* Builds an unsigned `PartialUserOperation` that packages up to four
|
|
151
|
+
* inner calls into a single `BatchExecutor.execute(calls[])`:
|
|
158
152
|
*
|
|
159
|
-
* 1. `PT.approve(
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
153
|
+
* 1. `PT.approve(Permit2, amountIn)` — grant Permit2 ERC-20 allowance
|
|
154
|
+
* 2. `Permit2.approve(PT, router, amountIn, deadline)` — authorize
|
|
155
|
+
* the UniversalRouter to pull PT via Permit2
|
|
156
|
+
* 3. `UniversalRouter.execute(commands, inputs, deadline)` — V4 swap
|
|
157
|
+
* PT → USDT; user receives ≥ `minAmountOut` USDT
|
|
158
|
+
* 4. `PT.transfer(feeRecipient, gasFeePt)` — pay the operator back
|
|
159
|
+
* for sponsoring the gas, in PT (omitted when `gasFeePt` is 0)
|
|
166
160
|
*
|
|
167
|
-
* The user's wallet must hold `amountIn + gasFeePt` PT
|
|
168
|
-
* UserOp runs.
|
|
169
|
-
*
|
|
170
|
-
*
|
|
161
|
+
* The user's wallet must hold `amountIn + gasFeePt` PT before the
|
|
162
|
+
* UserOp runs. All inner calls execute atomically via EIP-7702
|
|
163
|
+
* delegation (`msg.sender = user`), so a reverting swap unwinds
|
|
164
|
+
* the approvals and fee transfer too.
|
|
171
165
|
*
|
|
172
166
|
* ## Fee model
|
|
173
167
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* separate `transfer` call — it does NOT come out of the swap's USDT
|
|
178
|
-
* output, because that output goes straight to the user's wallet with
|
|
179
|
-
* no intermediate hook to skim from.
|
|
168
|
+
* The gas fee is a separate `transfer` after the swap — it does NOT
|
|
169
|
+
* come out of the USDT output, because that output goes straight to
|
|
170
|
+
* the user's wallet with no intermediate hook.
|
|
180
171
|
*
|
|
181
|
-
* If the FE wants "user receives exactly X USDT after gas"
|
|
172
|
+
* If the FE wants "user receives exactly X USDT after gas":
|
|
182
173
|
* 1. Quote PT→USDT for candidate `amountIn` values
|
|
183
174
|
* 2. Pick an `amountIn` where `minAmountOut ≈ X`
|
|
184
175
|
* 3. Separately compute `gasFeePt` from the operator's rate
|
|
@@ -186,11 +177,8 @@ declare const ZERO_VALUE = 0n;
|
|
|
186
177
|
*
|
|
187
178
|
* ## Order of operations
|
|
188
179
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* batch revert). Doing fee transfer first would still unwind on
|
|
192
|
-
* revert, but ordering it last matches the intuitive "only charge
|
|
193
|
-
* gas on success" semantics.
|
|
180
|
+
* Fee transfer is last so a reverting swap also refunds the fee
|
|
181
|
+
* (atomic batch revert semantics).
|
|
194
182
|
*/
|
|
195
183
|
interface BuildSwapWithGasDeductionParams {
|
|
196
184
|
/** User's EOA (with EIP-7702 delegation to BatchExecutor). */
|
|
@@ -218,12 +206,7 @@ interface BuildSwapWithGasDeductionParams {
|
|
|
218
206
|
gasFeePt: bigint;
|
|
219
207
|
/** Where the gas fee lands — typically the operator or fee collector. */
|
|
220
208
|
feeRecipient: Address;
|
|
221
|
-
/**
|
|
222
|
-
* Optional — pre-signed Permit2 / EIP-2612 approval. If omitted, a
|
|
223
|
-
* standard `approve()` call is appended as the first batch op.
|
|
224
|
-
* Future work: support Permit2 so the approve is part of the swap
|
|
225
|
-
* input rather than a separate call.
|
|
226
|
-
*/
|
|
209
|
+
/** Override ERC-4337 gas estimates. Defaults are conservative; tune down for cheaper UserOps. */
|
|
227
210
|
gasLimits?: {
|
|
228
211
|
callGasLimit?: bigint;
|
|
229
212
|
verificationGasLimit?: bigint;
|
|
@@ -241,4 +224,4 @@ interface BuildSwapWithGasDeductionParams {
|
|
|
241
224
|
*/
|
|
242
225
|
declare function buildSwapWithGasDeduction(params: BuildSwapWithGasDeductionParams): PartialUserOperation;
|
|
243
226
|
|
|
244
|
-
export { type BuildSwapWithGasDeductionParams as B,
|
|
227
|
+
export { type BuildSwapWithGasDeductionParams as B, type Operation as O, type PartialUserOperation as P, type SwapSimulationResult as S, TAKE_ALL as T, type UserOperation as U, V4_SWAP as V, ZERO_VALUE as Z, type PaymasterFields as a, SETTLE_ALL as b, SWAP_EXACT_IN as c, type UserOpReceipt as d, buildErc20ApprovalCalldata as e, buildPermit2ApprovalCalldata as f, buildSwapFromQuote as g, buildSwapWithGasDeduction as h, buildUniversalRouterExecuteArgs as i, buildV4SwapInput as j, checkAllowance as k, simulateSwap as s };
|