@pafi-dev/core 0.9.6 → 0.13.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.
Files changed (43) hide show
  1. package/README.md +146 -188
  2. package/dist/abi/index.cjs +2 -2
  3. package/dist/abi/index.cjs.map +1 -1
  4. package/dist/abi/index.d.cts +58 -106
  5. package/dist/abi/index.d.ts +58 -106
  6. package/dist/abi/index.js +3 -3
  7. package/dist/{chunk-Y5EYH2SQ.js → chunk-H3X3FYUU.js} +1 -10
  8. package/dist/chunk-H3X3FYUU.js.map +1 -0
  9. package/dist/{chunk-5NEAI2BH.cjs → chunk-NT2ZPF72.cjs} +50 -72
  10. package/dist/chunk-NT2ZPF72.cjs.map +1 -0
  11. package/dist/{chunk-BNO5SM25.cjs → chunk-TRYGIC2I.cjs} +2 -11
  12. package/dist/chunk-TRYGIC2I.cjs.map +1 -0
  13. package/dist/{chunk-HJYHGCMT.js → chunk-UEO4YN6T.js} +53 -75
  14. package/dist/chunk-UEO4YN6T.js.map +1 -0
  15. package/dist/{chunk-MIQA46E3.cjs → chunk-XXLIIWIF.cjs} +45 -53
  16. package/dist/chunk-XXLIIWIF.cjs.map +1 -0
  17. package/dist/{chunk-CWH4KOUW.js → chunk-ZJXXCG5P.js} +45 -53
  18. package/dist/chunk-ZJXXCG5P.js.map +1 -0
  19. package/dist/contract/index.cjs +2 -4
  20. package/dist/contract/index.cjs.map +1 -1
  21. package/dist/contract/index.d.cts +5 -15
  22. package/dist/contract/index.d.ts +5 -15
  23. package/dist/contract/index.js +1 -3
  24. package/dist/eip712/index.cjs +2 -8
  25. package/dist/eip712/index.cjs.map +1 -1
  26. package/dist/eip712/index.d.cts +29 -43
  27. package/dist/eip712/index.d.ts +29 -43
  28. package/dist/eip712/index.js +3 -9
  29. package/dist/index.cjs +141 -158
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +201 -182
  32. package/dist/index.d.ts +201 -182
  33. package/dist/index.js +135 -152
  34. package/dist/index.js.map +1 -1
  35. package/dist/{types-DWLZNgcw.d.cts → types-C17pznGz.d.cts} +72 -30
  36. package/dist/{types-DWLZNgcw.d.ts → types-C17pznGz.d.ts} +72 -30
  37. package/package.json +15 -5
  38. package/dist/chunk-5NEAI2BH.cjs.map +0 -1
  39. package/dist/chunk-BNO5SM25.cjs.map +0 -1
  40. package/dist/chunk-CWH4KOUW.js.map +0 -1
  41. package/dist/chunk-HJYHGCMT.js.map +0 -1
  42. package/dist/chunk-MIQA46E3.cjs.map +0 -1
  43. package/dist/chunk-Y5EYH2SQ.js.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
 
6
6
  Pure primitives for the PAFI point-token system. EIP-712 signing,
7
7
  contract ABIs + addresses, ERC-4337 UserOp building, EIP-7702
8
- delegation, sponsor-auth signing, perp deposit calldata, fee quoting.
8
+ delegation, sponsor-auth signing, perp deposit calldata, fee quoting,
9
+ MintFeeWrapper helpers.
9
10
 
10
11
  **Browser + Node-safe.** Zero HTTP client. Peer-dep: `viem ^2`.
11
12
 
@@ -13,12 +14,10 @@ delegation, sponsor-auth signing, perp deposit calldata, fee quoting.
13
14
 
14
15
  ## Requirements
15
16
 
16
- - Node.js >= 18 (or modern browser with native `fetch`)
17
- - TypeScript >= 5.0
17
+ - Node.js 18 (or modern browser with native `fetch`)
18
+ - TypeScript 5.0
18
19
  - `viem` ^2.0.0 (peer)
19
20
 
20
- ---
21
-
22
21
  ## Installation
23
22
 
24
23
  ```bash
@@ -27,10 +26,9 @@ pnpm add @pafi-dev/core viem
27
26
 
28
27
  ---
29
28
 
30
- ## What's in core (and what's not)
29
+ ## Package layout
31
30
 
32
- Core ships **data + primitives** only. Higher-level orchestration lives
33
- in sibling packages:
31
+ Core ships **data + primitives** only. Higher-level orchestration in siblings:
34
32
 
35
33
  | Concern | Package |
36
34
  | --- | --- |
@@ -39,44 +37,33 @@ in sibling packages:
39
37
  | Issuer DB ledger (TypeORM + Postgres) | `@pafi-dev/issuer-postgres` |
40
38
  | Trading (swap + quote, FE-callable) | `@pafi-dev/trading` |
41
39
 
42
- > **0.6.0 (2026-04-27):** swap UserOp builders + V4 quoting moved
43
- > from core to `@pafi-dev/trading`. Core retains the underlying
44
- > `universalRouterAbi`, `permit2Abi`, `v4QuoterAbi`, `PoolKey`,
45
- > `PathKey`, `QuoteResult` types — trading wraps them with the actual
46
- > swap logic. The `PafiSDK` class also drops `quote` / `swap`
47
- > namespaces; use trading or import primitives directly.
48
- >
49
- > **0.6.1 (2026-04-27):** added `quoteOperatorFeeUsdt` so FE can
50
- > compute USDT-denominated gas fee without round-tripping the issuer
51
- > backend (`/gas-fee` is now optional).
52
- >
53
- > **0.7.5 (2026-04-28):** added `delegateDirect()` — FE one-shot EIP-7702
54
- > delegation that user pays gas for. Bypasses the AA + sponsor-relayer
55
- > stack entirely. See [section below](#delegatedirect--fe-one-shot-delegation-no-aa--no-sponsor).
56
-
57
40
  ---
58
41
 
59
- ## Modules
42
+ ## Exports cheatsheet
60
43
 
61
- | Symbol / area | What it provides |
44
+ | Symbol / area | Provides |
62
45
  | --- | --- |
63
- | `getContractAddresses(chainId)` | All deployed PAFI contract addresses keyed by chain |
64
- | `signMintRequest`, `verifyMintRequest` | EIP-712 sign / recover for `MintRequest` |
65
- | `signBurnRequest`, `verifyBurnRequest` | EIP-712 sign / recover for `BurnRequest` |
66
- | `signReceiverConsent`, `verifyReceiverConsent` | EIP-712 for sponsored-mint consent |
46
+ | `getContractAddresses(chainId)` | All deployed PAFI addresses keyed by chain |
47
+ | `signMintRequest`, `verifyMintRequest`, `buildMintRequestTypedData` | EIP-712 sign/recover for `MintForRequest` (5 fields: user, receiver, amount, nonce, deadline) |
48
+ | `signBurnRequest`, `verifyBurnRequest`, `buildBurnRequestTypedData` | EIP-712 for `BurnRequest` |
67
49
  | `signSponsorAuth`, `verifySponsorAuth`, `buildAndSignSponsorAuth` | EIP-712 for sponsor-relayer auth |
68
50
  | `buildPartialUserOperation`, `assembleUserOperation`, `computeUserOpHash` | ERC-4337 v0.7+ UserOp builder + hash |
69
- | `encodeBatchExecute`, `decodeBatchExecuteCalls` | BatchExecutor (Coinbase SW v2) calldata |
70
- | `buildDelegationUserOp`, `computeAuthorizationHash`, `parseEip7702DelegatedAddress` | EIP-7702 helpers |
71
- | `splitAuthorizationSig`, `buildEip7702Authorization` | Split user's authSig + assemble bundler tuple |
72
- | `delegateDirect` | One-shot FE-direct EIP-7702 delegation (user pays gas, no AA) |
51
+ | `encodeBatchExecute`, `decodeBatchExecuteCalls` | BatchExecutor (Pimlico Simple7702Account) calldata |
52
+ | `buildDelegationUserOp`, `computeAuthorizationHash`, `parseEip7702DelegatedAddress`, `splitAuthorizationSig`, `buildEip7702Authorization`, `delegateDirect` | EIP-7702 helpers (build + introspect) |
73
53
  | `buildPerpDepositViaRelay`, `buildPerpDepositWithGasDeduction`, `ORDERLY_RELAY_ABI`, `ORDERLY_VAULT_ABI`, `BROKER_HASHES`, `TOKEN_HASHES`, `computeAccountId` | Orderly perp deposit calldata + types |
74
- | `quoteOperatorFeePt`, `quoteOperatorFeeUsdt` | Off-issuer fee quoter (Chainlink + V4 subgraph) |
75
- | `fetchPafiPools`, `PAFI_SUBGRAPH_URL` | Pool discovery via PAFI subgraph |
76
- | `pointTokenAbi` (alias `POINT_TOKEN_V2_ABI`), `issuerRegistryAbi`, `mintingOracleAbi`, `pointTokenFactoryAbi`, `erc20Abi`, `permit2Abi`, `universalRouterAbi`, `v4QuoterAbi` | Contract ABIs |
77
- | `getMintRequestNonce`, `getBurnRequestNonce`, `getReceiverConsentNonce`, `getPointTokenBalance`, `isMinter`, `getTokenName` | On-chain read helpers |
78
- | `createLoginMessage` | EIP-4361 SIWE login message builder |
79
- | `parseEip7702DelegatedAddress`, `checkDelegation`, `isDelegatedTo`, `isDelegatedToTarget` | EIP-7702 delegation introspection |
54
+ | `quoteOperatorFeePt`, `quoteOperatorFeeUsdt` | Gas-reimbursement fee quoter (Chainlink + V3 subgraph) |
55
+ | `getMintFeeBps`, `getMintFeeRecipients` | Read wrapper fee config per pointToken |
56
+ | `getTokenCap` | Read `MintingOracle.tokenCaps(pointToken)` |
57
+ | `verifyMintCap`, `getPointTokenIssuer` | MintingOracle read helpers |
58
+ | `getIssuer`, `isActiveIssuer`, `issuerRegistryGetIssuerFlatAbi` | IssuerRegistry helpers (7-field record) |
59
+ | `getMintRequestNonce`, `getBurnRequestNonce`, `getPointTokenBalance`, `isMinter`, `getTokenName`, `getPointTokenIssuerAddress` | PointToken read helpers |
60
+ | `fetchPafiPools`, `PAFI_SUBGRAPH_URL` | Pool discovery — endpoint is `…/pafi-subgraph-v4` (PAFI V3-fork DEX + extensions); parser tolerates both V3 and legacy V4 subgraph responses |
61
+ | `getPafiServiceUrls(chainId)` | Hardcoded PAFI service endpoints (sponsorRelayer, issuerApi) |
62
+ | `PoolKey` (`{ token0, token1, fee }`), `V3Path` (`{ tokens, fees }`), `QuoteResult` | Uniswap V3 routing types used by `@pafi-dev/trading` |
63
+ | `encodeV3Path`, `encodeV3PathReversed`, `computeV3PoolAddress` | V3 packed-bytes path encoding + CREATE2 pool-address derivation |
64
+ | `V3_FACTORY_ADDRESSES`, `V3_SWAP_ROUTER_ADDRESSES`, `QUOTER_V2_ADDRESSES`, `V3_POOL_INIT_CODE_HASH` | PAFI's V3-fork deployment (Base mainnet) |
65
+ | `pointTokenAbi` (alias `POINT_TOKEN_V2_ABI`), `issuerRegistryAbi`, `mintingOracleAbi`, `mintFeeWrapperAbi`, `pointTokenFactoryAbi`, `erc20Abi`, `permit2Abi`, `universalRouterAbi`, `v3QuoterV2Abi` | Contract ABIs (regenerated from Foundry artifacts) |
66
+ | `createLoginMessage` | EIP-4361 SIWE login builder |
80
67
 
81
68
  ---
82
69
 
@@ -85,29 +72,22 @@ in sibling packages:
85
72
  ```ts
86
73
  import { getContractAddresses } from "@pafi-dev/core";
87
74
 
88
- const {
89
- pointToken,
90
- batchExecutor, // EIP-7702 delegation target (Coinbase SW v2)
91
- usdt,
92
- issuerRegistry,
93
- mintingOracle,
94
- pafiHook, // Uniswap V4 hook (10% fee on PT→USDT only)
95
- chainlinkEthUsd,
96
- orderlyRelay,
97
- pafiFeeRecipient,
98
- universalRouter,
99
- } = getContractAddresses(8453);
75
+ const addr = getContractAddresses(8453); // Base mainnet
76
+ // addr.issuerRegistry, addr.mintingOracle, addr.mintFeeWrapper,
77
+ // addr.usdt, addr.batchExecutor, addr.pafiFeeRecipient,
78
+ // addr.chainlinkEthUsd, addr.orderlyRelay, addr.universalRouter
100
79
  ```
101
80
 
102
- Throws if `chainId` isn't in the map. Base mainnet (8453) is the only
103
- chain in active use.
81
+ > Per-issuer `pointToken` clones are NOT in the chain-level address bag.
82
+ > Read from your issuer env (e.g. `POINT_TOKEN_ADDRESS`) or
83
+ > `PointTokenFactory.createToken()` at runtime.
104
84
 
105
85
  ---
106
86
 
107
- ## EIP-712 signing
87
+ ## EIP-712 — `MintForRequest`
108
88
 
109
89
  ```ts
110
- import { signMintRequest, getContractAddresses } from "@pafi-dev/core";
90
+ import { signMintRequest, verifyMintRequest } from "@pafi-dev/core";
111
91
  import { privateKeyToAccount } from "viem/accounts";
112
92
  import { createWalletClient, http } from "viem";
113
93
 
@@ -116,183 +96,131 @@ const wallet = createWalletClient({
116
96
  transport: http(),
117
97
  });
118
98
 
119
- const { pointToken } = getContractAddresses(8453);
120
99
  const sig = await signMintRequest(
121
100
  wallet,
122
- { name: "POINT", chainId: 8453, verifyingContract: pointToken },
101
+ { name: "POINT", chainId: 8453, verifyingContract: pointTokenAddress },
123
102
  {
124
- to: userAddress,
103
+ user, // off-chain spender (drives nonces)
104
+ receiver: wrapperAddress, // on-chain caller of PointToken.mint
105
+ // (= wrapper for wrapper-mediated; = user for direct)
125
106
  amount: 1000n * 10n ** 18n,
126
- nonce: currentMintRequestNonce,
107
+ nonce: currentMintRequestNonce, // from PointToken.mintRequestNonces(user)
127
108
  deadline: BigInt(Math.floor(Date.now() / 1000) + 900),
128
109
  },
129
110
  );
130
111
 
131
- // sig.serialized — bytes hex passed to PointToken.mint(...)
112
+ // sig.serialized — bytes hex passed to PointToken.mint(...) or wrapper.mintWithFee(...)
132
113
  ```
133
114
 
134
- Same pattern for `signBurnRequest`, `signReceiverConsent`,
135
- `signSponsorAuth`. KMS-backed wallets work pass any
136
- `viem WalletClient`.
115
+ Wrapper-mediated mint puts `receiver = wrapperAddress`; direct mint puts
116
+ `receiver = user`. The contract requires `msg.sender == receiver`.
137
117
 
138
118
  ---
139
119
 
140
- ## ERC-4337 UserOp building
120
+ ## MintFeeWrapper helpers
141
121
 
142
122
  ```ts
143
- import { encodeBatchExecute, buildPartialUserOperation } from "@pafi-dev/core";
123
+ import { getMintFeeBps, getMintFeeRecipients, getContractAddresses } from "@pafi-dev/core";
144
124
 
145
- const callData = encodeBatchExecute([
146
- { target: pointToken, value: 0n, data: mintCallData },
147
- { target: pointToken, value: 0n, data: feeTransferCallData }, // optional
148
- ]);
125
+ const { mintFeeWrapper } = getContractAddresses(8453);
126
+ const POINT_TOKEN = "0x855c2046...";
149
127
 
150
- const partial = buildPartialUserOperation({
151
- sender: userAddress,
152
- nonce: aaNonce,
153
- operations: [...],
154
- gasLimits: { callGasLimit: 300_000n, verificationGasLimit: 150_000n, preVerificationGas: 50_000n },
155
- });
128
+ const bps = await getMintFeeBps(provider, mintFeeWrapper, POINT_TOKEN);
129
+ // bps = 50 (= 0.50%)
130
+
131
+ const recipients = await getMintFeeRecipients(provider, mintFeeWrapper, POINT_TOKEN);
132
+ // [{ account: 0x..., basisPoints: 20 }, { account: 0x..., basisPoints: 30 }]
156
133
  ```
157
134
 
158
- `computeUserOpHash(userOp, chainId)` EntryPoint v0.8 EIP-712 digest.
159
- The mobile prepare/submit flow signs this hash via Privy
160
- `personal_sign`.
135
+ Wrapper deducts `gross × bps / 10000` PT on every mint and distributes
136
+ to recipients. User receives `gross × (1 - bps/10000)` net.
161
137
 
162
138
  ---
163
139
 
164
- ## EIP-7702 delegation helpers
140
+ ## Operator fee quoter
165
141
 
166
- ```ts
167
- import {
168
- computeAuthorizationHash,
169
- parseEip7702DelegatedAddress,
170
- splitAuthorizationSig,
171
- buildEip7702Authorization,
172
- } from "@pafi-dev/core";
142
+ Two helpers for FE direct usage (no backend round-trip):
173
143
 
174
- // Check whether user EOA already has delegation installed
175
- const code = await provider.getCode({ address: userAddress });
176
- const designator = parseEip7702DelegatedAddress(code); // null = not delegated
144
+ ```ts
145
+ import { quoteOperatorFeeUsdt, quoteOperatorFeePt } from "@pafi-dev/core";
177
146
 
178
- // Build the hash the user signs to authorize delegation
179
- const accountNonce = BigInt(await provider.getTransactionCount({ address: userAddress }));
180
- const authHash = computeAuthorizationHash(8453, batchExecutor, accountNonce);
147
+ // USDT-denominated (replaces issuer's GET /gas-fee). Chainlink-only.
148
+ const gasFeeUsdt = await quoteOperatorFeeUsdt({
149
+ provider, chainId: 8453, scenario: "mint",
150
+ });
181
151
 
182
- // On the bundler side: split the user's 65-byte signature into the tuple
183
- const { r, s, yParity } = splitAuthorizationSig(authSig);
184
- const authorization = buildEip7702Authorization({
185
- chainId: 8453,
186
- address: batchExecutor,
187
- nonce: accountNonce,
188
- authSig,
152
+ // PT-denominated (used by mint/burn flows). Adds V3 subgraph call.
153
+ const gasFeePt = await quoteOperatorFeePt({
154
+ provider, chainId: 8453, scenario: "mint",
155
+ pointTokenAddress: POINT_TOKEN,
156
+ allowStaleFallback: true, // recommended: don't block on subgraph outage
189
157
  });
190
158
  ```
191
159
 
192
- ---
193
-
194
- ## `delegateDirect` — FE one-shot delegation, no AA / no sponsor
160
+ Both return `bigint` raw units. Fallback prices (`0.1 USDT/PT` default,
161
+ 3000 USD/ETH default) used when oracles unreachable + `allowStaleFallback`
162
+ is true. Sponsor-relayer's `FeeValidator` runs the same math server-side
163
+ with a 5% tolerance window.
195
164
 
196
- For the **FE-direct** path where the user pays gas in ETH and you don't
197
- want a dependency on `permissionless` / Pimlico bundlers / PAFI
198
- sponsor-relayer:
165
+ See [`docs/FEE_FLOW.md`](../../../docs/FEE_FLOW.md) in the main repo for
166
+ full math derivation.
199
167
 
200
- ```ts
201
- import { useSign7702Authorization, useWallets } from "@privy-io/react-auth";
202
- import { delegateDirect } from "@pafi-dev/core";
203
- import { createWalletClient, custom, createPublicClient, http } from "viem";
204
- import { base } from "viem/chains";
205
-
206
- const publicClient = createPublicClient({ chain: base, transport: http() });
207
-
208
- function DelegateButton() {
209
- const { wallets } = useWallets();
210
- const { signAuthorization } = useSign7702Authorization();
211
-
212
- // Privy ALWAYS signs EIP-7702 with the embedded wallet — pick that
213
- // one as the smart-account owner regardless of how user logged in.
214
- const wallet = wallets.find((w) => w.walletClientType === "privy");
215
-
216
- async function handleClick() {
217
- if (!wallet) return;
218
- const provider = await wallet.getEthereumProvider();
219
- const walletClient = createWalletClient({
220
- account: wallet.address as `0x${string}`,
221
- chain: base,
222
- transport: custom(provider),
223
- });
224
-
225
- const result = await delegateDirect({
226
- userAddress: wallet.address as `0x${string}`,
227
- chainId: 8453,
228
- publicClient,
229
- walletClient,
230
- signAuthorization,
231
- // optional: skipIfAlreadyDelegated (default true), waitForReceipt (default true)
232
- });
233
-
234
- if (result.status === "already-delegated") {
235
- console.log("Already delegated to", result.delegatedTo);
236
- } else {
237
- console.log("Delegated! tx:", result.txHash);
238
- // result.receipt — full TransactionReceipt when waitForReceipt=true
239
- }
240
- }
241
-
242
- return <button onClick={handleClick}>Delegate</button>;
243
- }
244
- ```
245
-
246
- **What happens internally:**
168
+ ---
247
169
 
248
- 1. `getCode(userAddress)` if already delegated to expected impl, return early.
249
- 2. `getTransactionCount(userAddress, 'pending')` → tx nonce.
250
- 3. `signAuthorization({ contractAddress, chainId, nonce })` — Privy hook signs with embedded wallet (raw `secp256k1_sign`, no EIP-191 prefix).
251
- 4. `walletClient.sendTransaction({ to: userAddress, data: '0x', authorizationList: [auth] })` — viem encodes a type-4 EIP-7702 transaction.
252
- 5. `waitForTransactionReceipt(txHash)` (optional).
170
+ ## ERC-4337 UserOp building
253
171
 
254
- **Requirements:**
172
+ ```ts
173
+ import { encodeBatchExecute, buildPartialUserOperation } from "@pafi-dev/core";
255
174
 
256
- - Privy embedded wallet (external wallets like MetaMask **cannot**
257
- sign EIP-7702 only Privy's embedded wallet exposes raw
258
- `secp256k1_sign`).
259
- - A few cents of ETH on Base for gas (~$0.01–0.10).
175
+ const callData = encodeBatchExecute([
176
+ { target: mintFeeWrapper, value: 0n, data: mintWithFeeCallData },
177
+ { target: pointToken, value: 0n, data: feeTransferCallData },
178
+ ]);
260
179
 
261
- **vs. AA path:** `delegateDirect` produces 1 native L1 tx instead of an
262
- ERC-4337 UserOp. Cheaper, simpler, no bundler / paymaster involvement —
263
- but the user pays gas. Use the AA path (via `permissionless` +
264
- sponsor-relayer) when you want gas-free UX.
180
+ const partial = buildPartialUserOperation({
181
+ sender: userAddress,
182
+ nonce: aaNonce,
183
+ callData,
184
+ gasLimits: {
185
+ callGasLimit: 300_000n,
186
+ verificationGasLimit: 150_000n,
187
+ preVerificationGas: 50_000n,
188
+ },
189
+ });
190
+ ```
265
191
 
266
- **vs. mobile gg56 flow:** mobile delegate flow goes through gg56's
267
- `/delegate/{prepare,submit}` + sponsor-relayer for the gas sponsorship.
268
- `delegateDirect` is the FE-only counterpart that bypasses that
269
- infrastructure entirely.
192
+ `computeUserOpHash(userOp, chainId)` EntryPoint v0.8 EIP-712 digest.
193
+ Mobile signs this hash via `eth_signTypedData_v4` (NOT `personal_sign` —
194
+ Pimlico Simple7702Account does raw `ecrecover` without EIP-191 prefix).
270
195
 
271
196
  ---
272
197
 
273
- ## Operator fee quoter
198
+ ## EIP-7702 `delegateDirect`
274
199
 
275
- Two helpers for FE direct-mode usage (no backend round-trip):
200
+ FE one-shot delegation, no AA / no sponsor:
276
201
 
277
202
  ```ts
278
- import { quoteOperatorFeeUsdt, quoteOperatorFeePt } from "@pafi-dev/core";
203
+ import { delegateDirect } from "@pafi-dev/core";
204
+ import { useSign7702Authorization, useWallets } from "@privy-io/react-auth";
279
205
 
280
- // USDT-denominated (replaces issuer's GET /gas-fee).
281
- // Pure RPC + Chainlink read.
282
- const gasFeeUsdt = await quoteOperatorFeeUsdt({ provider, chainId: 8453 });
206
+ const { signAuthorization } = useSign7702Authorization();
207
+ const wallet = useWallets().find((w) => w.walletClientType === "privy");
283
208
 
284
- // PT-denominated (used by the swap flow as operator gas reimbursement
285
- // in PT). Needs a subgraph call to read PT spot price.
286
- const gasFeePt = await quoteOperatorFeePt({
287
- provider,
209
+ const result = await delegateDirect({
210
+ userAddress: wallet.address,
288
211
  chainId: 8453,
289
- pointTokenAddress: POINT_TOKEN,
212
+ publicClient,
213
+ walletClient,
214
+ signAuthorization,
215
+ // optional: skipIfAlreadyDelegated (default true), waitForReceipt (default true)
290
216
  });
217
+
218
+ // result.status: "already-delegated" | "broadcasted"
219
+ // result.txHash, result.delegatedTo, result.receipt?
291
220
  ```
292
221
 
293
- Both return `bigint` raw units. Sponsor-relayer's `FeeValidator` runs
294
- the same math server-side with a 5% tolerance window — minor drift
295
- between client and server is accepted.
222
+ **Privy embedded wallet only** external wallets (MetaMask) can't sign
223
+ EIP-7702 (no raw `secp256k1_sign` exposed). User pays ~$0.01–0.10 ETH gas.
296
224
 
297
225
  ---
298
226
 
@@ -309,15 +237,45 @@ const sponsorAuth = await buildAndSignSponsorAuth({
309
237
  issuerId: ISSUER_ID,
310
238
  issuerSignerWallet, // KMS-backed in prod
311
239
  });
312
-
313
- // Pass to sponsor-relayer's POST /paymaster/sponsor as the `sponsorAuth` field.
240
+ // Pass to sponsor-relayer's POST /paymaster/sponsor as `sponsorAuth` field
314
241
  ```
315
242
 
316
- The issuer signer must be registered in PAFI's `IssuerRegistry`
317
- (`signerAddress` field).
243
+ Issuer signer must be registered in `IssuerRegistry` (`signerAddress`
244
+ field) and whitelisted via `PointToken.addMinter(signer)`.
245
+
246
+ ---
247
+
248
+ ## Verify on-chain state (debug)
249
+
250
+ ```ts
251
+ import {
252
+ getIssuer, getTokenCap, getMintFeeBps,
253
+ getMintRequestNonce, isMinter,
254
+ } from "@pafi-dev/core";
255
+
256
+ // Issuer registry record (7-field flat record)
257
+ const issuer = await getIssuer(provider, registry, issuerAddress);
258
+ // { issuerAddress, signerAddress, name, symbol, active, pointToken, mintingOracle }
259
+
260
+ // Per-token cap (read from oracle, not issuer struct)
261
+ const cap = await getTokenCap(provider, mintingOracle, pointToken);
262
+ // { declaredTotalSupply, capBasisPoints }
263
+
264
+ // Fee config
265
+ const bps = await getMintFeeBps(provider, wrapper, pointToken);
266
+
267
+ // Mint state
268
+ const nonce = await getMintRequestNonce(provider, pointToken, user);
269
+ const authorized = await isMinter(provider, pointToken, signerAddress);
270
+ ```
318
271
 
319
272
  ---
320
273
 
274
+ ## References
275
+
276
+ - Architecture: [`ARCHITECTURE.md`](../../ARCHITECTURE.md) at SDK root
277
+ - Fee math: [`docs/FEE_FLOW.md`](../../../docs/FEE_FLOW.md)
278
+
321
279
  ## License
322
280
 
323
281
  Apache-2.0
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkMIQA46E3cjs = require('../chunk-MIQA46E3.cjs');
7
+ var _chunkXXLIIWIFcjs = require('../chunk-XXLIIWIF.cjs');
8
8
 
9
9
 
10
10
 
@@ -24,5 +24,5 @@ require('../chunk-JEQ2X3Z6.cjs');
24
24
 
25
25
 
26
26
 
27
- exports.erc20Abi = _chunkMIQA46E3cjs.erc20Abi; exports.issuerRegistryAbi = _chunkC7VB6WTLcjs.issuerRegistryAbi; exports.mintFeeWrapperAbi = _chunkC7VB6WTLcjs.mintFeeWrapperAbi; exports.mintingOracleAbi = _chunkC7VB6WTLcjs.mintingOracleAbi; exports.permit2Abi = _chunkMIQA46E3cjs.permit2Abi; exports.pointTokenAbi = _chunkKRHGFUDIcjs.pointTokenAbi; exports.pointTokenFactoryAbi = _chunkMIQA46E3cjs.pointTokenFactoryAbi; exports.universalRouterAbi = _chunkMIQA46E3cjs.universalRouterAbi; exports.v4QuoterAbi = _chunkMIQA46E3cjs.v4QuoterAbi;
27
+ exports.erc20Abi = _chunkXXLIIWIFcjs.erc20Abi; exports.issuerRegistryAbi = _chunkC7VB6WTLcjs.issuerRegistryAbi; exports.mintFeeWrapperAbi = _chunkC7VB6WTLcjs.mintFeeWrapperAbi; exports.mintingOracleAbi = _chunkC7VB6WTLcjs.mintingOracleAbi; exports.permit2Abi = _chunkXXLIIWIFcjs.permit2Abi; exports.pointTokenAbi = _chunkKRHGFUDIcjs.pointTokenAbi; exports.pointTokenFactoryAbi = _chunkXXLIIWIFcjs.pointTokenFactoryAbi; exports.universalRouterAbi = _chunkXXLIIWIFcjs.universalRouterAbi; exports.v3QuoterV2Abi = _chunkXXLIIWIFcjs.v3QuoterV2Abi;
28
28
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/abi/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,0hBAAC","file":"/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/abi/index.cjs"}
1
+ {"version":3,"sources":["/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/abi/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACF,yDAA8B;AAC9B,iCAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,8hBAAC","file":"/Users/phitran/Pacific-Finance/pafi-backend/pafi-sdk/packages/core/dist/abi/index.cjs"}