@pafi-dev/core 0.6.1 → 0.7.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 +150 -257
- package/dist/index.cjs +10 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -9
- package/dist/index.d.ts +19 -9
- package/dist/index.js +11 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,344 +3,237 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@pafi-dev/core)
|
|
4
4
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Pure primitives for the PAFI point-token system. EIP-712 signing,
|
|
7
|
+
contract ABIs + addresses, ERC-4337 UserOp building, EIP-7702
|
|
8
|
+
delegation, sponsor-auth signing, perp deposit calldata, fee quoting.
|
|
7
9
|
|
|
8
|
-
**
|
|
10
|
+
**Browser + Node-safe.** Zero HTTP client. Peer-dep: `viem ^2`.
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
12
14
|
## Requirements
|
|
13
15
|
|
|
14
|
-
- Node.js >= 18
|
|
16
|
+
- Node.js >= 18 (or modern browser with native `fetch`)
|
|
15
17
|
- TypeScript >= 5.0
|
|
16
|
-
- `viem` ^2.0.0 (peer
|
|
17
|
-
|
|
18
|
-
> **Latest:** `0.5.16` — ERC-4337 v0.8 hash + EIP-712 signing fixes for the
|
|
19
|
-
> EIP-7702 mobile flow. See [Changelog](#changelog) for the full breakdown
|
|
20
|
-
> of the AA24/AA23 bugs this release closes.
|
|
18
|
+
- `viem` ^2.0.0 (peer)
|
|
21
19
|
|
|
22
20
|
---
|
|
23
21
|
|
|
24
22
|
## Installation
|
|
25
23
|
|
|
26
24
|
```bash
|
|
27
|
-
npm install @pafi-dev/core viem
|
|
28
|
-
# or
|
|
29
25
|
pnpm add @pafi-dev/core viem
|
|
30
26
|
```
|
|
31
27
|
|
|
32
28
|
---
|
|
33
29
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
| `@pafi-dev/core
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
| `@pafi-dev/
|
|
30
|
+
## What's in core (and what's not)
|
|
31
|
+
|
|
32
|
+
Core ships **data + primitives** only. Higher-level orchestration lives
|
|
33
|
+
in sibling packages:
|
|
34
|
+
|
|
35
|
+
| Concern | Package |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| Pure primitives (this package) | `@pafi-dev/core` |
|
|
38
|
+
| Issuer backend (claim / redeem / mobile flows) | `@pafi-dev/issuer` |
|
|
39
|
+
| Issuer DB ledger (TypeORM + Postgres) | `@pafi-dev/issuer-postgres` |
|
|
40
|
+
| Trading (swap + quote, FE-callable) | `@pafi-dev/trading` |
|
|
41
|
+
|
|
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).
|
|
45
52
|
|
|
46
53
|
---
|
|
47
54
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
All deployed PAFI contract addresses live in one place, keyed by `chainId`:
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
import { getContractAddresses, POINT_TOKEN_FACTORY_ADDRESSES } from "@pafi-dev/core";
|
|
55
|
+
## Modules
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
| Symbol / area | What it provides |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `getContractAddresses(chainId)` | All deployed PAFI contract addresses keyed by chain |
|
|
60
|
+
| `signMintRequest`, `verifyMintRequest` | EIP-712 sign / recover for `MintRequest` |
|
|
61
|
+
| `signBurnRequest`, `verifyBurnRequest` | EIP-712 sign / recover for `BurnRequest` |
|
|
62
|
+
| `signReceiverConsent`, `verifyReceiverConsent` | EIP-712 for sponsored-mint consent |
|
|
63
|
+
| `signSponsorAuth`, `verifySponsorAuth`, `buildAndSignSponsorAuth` | EIP-712 for sponsor-relayer auth |
|
|
64
|
+
| `buildPartialUserOperation`, `assembleUserOperation`, `computeUserOpHash` | ERC-4337 v0.7+ UserOp builder + hash |
|
|
65
|
+
| `encodeBatchExecute`, `decodeBatchExecuteCalls` | BatchExecutor (Coinbase SW v2) calldata |
|
|
66
|
+
| `buildDelegationUserOp`, `computeAuthorizationHash`, `parseEip7702DelegatedAddress` | EIP-7702 helpers |
|
|
67
|
+
| `splitAuthorizationSig`, `buildEip7702Authorization` | Split user's authSig + assemble bundler tuple |
|
|
68
|
+
| `buildPerpDepositViaRelay`, `buildPerpDepositWithGasDeduction`, `ORDERLY_RELAY_ABI`, `ORDERLY_VAULT_ABI`, `BROKER_HASHES`, `TOKEN_HASHES`, `computeAccountId` | Orderly perp deposit calldata + types |
|
|
69
|
+
| `quoteOperatorFeePt`, `quoteOperatorFeeUsdt` | Off-issuer fee quoter (Chainlink + V4 subgraph) |
|
|
70
|
+
| `fetchPafiPools`, `PAFI_SUBGRAPH_URL` | Pool discovery via PAFI subgraph |
|
|
71
|
+
| `pointTokenAbi` (alias `POINT_TOKEN_V2_ABI`), `issuerRegistryAbi`, `mintingOracleAbi`, `pointTokenFactoryAbi`, `erc20Abi`, `permit2Abi`, `universalRouterAbi`, `v4QuoterAbi` | Contract ABIs |
|
|
72
|
+
| `getMintRequestNonce`, `getBurnRequestNonce`, `getReceiverConsentNonce`, `getPointTokenBalance`, `isMinter`, `getTokenName` | On-chain read helpers |
|
|
73
|
+
| `createLoginMessage` | EIP-4361 SIWE login message builder |
|
|
74
|
+
| `parseEip7702DelegatedAddress`, `checkDelegation`, `isDelegatedTo`, `isDelegatedToTarget` | EIP-7702 delegation introspection |
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
```
|
|
76
|
+
---
|
|
65
77
|
|
|
66
|
-
|
|
78
|
+
## Contract addresses
|
|
67
79
|
|
|
68
80
|
```ts
|
|
69
|
-
import {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
import { getContractAddresses } from "@pafi-dev/core";
|
|
82
|
+
|
|
83
|
+
const {
|
|
84
|
+
pointToken,
|
|
85
|
+
batchExecutor, // EIP-7702 delegation target (Coinbase SW v2)
|
|
86
|
+
usdt,
|
|
87
|
+
issuerRegistry,
|
|
88
|
+
mintingOracle,
|
|
89
|
+
pafiHook, // Uniswap V4 hook (10% fee on PT→USDT only)
|
|
90
|
+
chainlinkEthUsd,
|
|
91
|
+
orderlyRelay,
|
|
92
|
+
pafiFeeRecipient,
|
|
93
|
+
universalRouter,
|
|
94
|
+
} = getContractAddresses(8453);
|
|
77
95
|
```
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Mixing v0.7 with a v0.8 account reverts with `AA23 reverted account: not
|
|
82
|
-
from EntryPoint`.
|
|
97
|
+
Throws if `chainId` isn't in the map. Base mainnet (8453) is the only
|
|
98
|
+
chain in active use.
|
|
83
99
|
|
|
84
100
|
---
|
|
85
101
|
|
|
86
102
|
## EIP-712 signing
|
|
87
103
|
|
|
88
|
-
Used by the **issuer backend** to sign mint/burn authorization. The frontend
|
|
89
|
-
sends the signature alongside the UserOp to the Relay contract.
|
|
90
|
-
|
|
91
104
|
```ts
|
|
92
|
-
import { signMintRequest,
|
|
105
|
+
import { signMintRequest, getContractAddresses } from "@pafi-dev/core";
|
|
106
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
107
|
+
import { createWalletClient, http } from "viem";
|
|
93
108
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
verifyingContract: addrs.pointToken,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const { signature } = await signMintRequest(issuerWalletClient, domain, {
|
|
101
|
-
to: userAddress,
|
|
102
|
-
amount: 500n * 10n ** 18n,
|
|
103
|
-
nonce: await getMintRequestNonce(publicClient, addrs.pointToken, userAddress),
|
|
104
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 900), // 15 min
|
|
109
|
+
const wallet = createWalletClient({
|
|
110
|
+
account: privateKeyToAccount(MINTER_PK),
|
|
111
|
+
transport: http(),
|
|
105
112
|
});
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
import {
|
|
120
|
-
signSponsorAuth,
|
|
121
|
-
verifySponsorAuth,
|
|
122
|
-
computeCallDataHash,
|
|
123
|
-
type SponsorAuthPayload,
|
|
124
|
-
} from "@pafi-dev/core";
|
|
114
|
+
const { pointToken } = getContractAddresses(8453);
|
|
115
|
+
const sig = await signMintRequest(
|
|
116
|
+
wallet,
|
|
117
|
+
{ name: "POINT", chainId: 8453, verifyingContract: pointToken },
|
|
118
|
+
{
|
|
119
|
+
to: userAddress,
|
|
120
|
+
amount: 1000n * 10n ** 18n,
|
|
121
|
+
nonce: currentMintRequestNonce,
|
|
122
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 900),
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
125
|
|
|
126
|
-
//
|
|
127
|
-
const payload: SponsorAuthPayload = {
|
|
128
|
-
chainId: 8453,
|
|
129
|
-
sender: userAddress,
|
|
130
|
-
callDataHash: computeCallDataHash(userOp.callData),
|
|
131
|
-
nonce: BigInt(Date.now()) * 1_000_000n + BigInt(Math.floor(Math.random() * 1_000_000)),
|
|
132
|
-
expiresAt: Math.floor(Date.now() / 1000) + 600, // 10 min
|
|
133
|
-
scenario: "mint", // "mint" | "burn" | "swap"
|
|
134
|
-
issuerId: "gg56",
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const sig = await signSponsorAuth(issuerWalletClient, payload);
|
|
138
|
-
|
|
139
|
-
// Paymaster proxy: verify before forwarding to Pimlico
|
|
140
|
-
const result = await verifySponsorAuth(payload, sig, expectedIssuerAddress);
|
|
141
|
-
// result.ok true/false
|
|
142
|
-
// result.reason "EXPIRED" | "INVALID_SIGNER" | "INVALID_SIGNATURE_FORMAT"
|
|
126
|
+
// sig.serialized — bytes hex passed to PointToken.mint(...)
|
|
143
127
|
```
|
|
144
128
|
|
|
145
|
-
|
|
129
|
+
Same pattern for `signBurnRequest`, `signReceiverConsent`,
|
|
130
|
+
`signSponsorAuth`. KMS-backed wallets work — pass any
|
|
131
|
+
`viem WalletClient`.
|
|
146
132
|
|
|
147
|
-
|
|
133
|
+
---
|
|
148
134
|
|
|
149
|
-
|
|
150
|
-
1. Approves Permit2
|
|
151
|
-
2. Sets a Permit2 allowance for UniversalRouter
|
|
152
|
-
3. Swaps PT → USDT via UniversalRouter
|
|
153
|
-
4. Optionally deducts a gas fee in PT
|
|
135
|
+
## ERC-4337 UserOp building
|
|
154
136
|
|
|
155
137
|
```ts
|
|
156
|
-
import {
|
|
157
|
-
buildSwapWithGasDeduction,
|
|
158
|
-
findBestQuote,
|
|
159
|
-
getContractAddresses,
|
|
160
|
-
UNIVERSAL_ROUTER_ADDRESSES,
|
|
161
|
-
} from "@pafi-dev/core";
|
|
162
|
-
|
|
163
|
-
const addrs = getContractAddresses(8453);
|
|
138
|
+
import { encodeBatchExecute, buildPartialUserOperation } from "@pafi-dev/core";
|
|
164
139
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
addrs.pointToken,
|
|
170
|
-
addrs.usdt,
|
|
171
|
-
500n * 10n ** 18n,
|
|
172
|
-
pools, // PoolKey[] from issuer backend GET /pools
|
|
173
|
-
);
|
|
140
|
+
const callData = encodeBatchExecute([
|
|
141
|
+
{ target: pointToken, value: 0n, data: mintCallData },
|
|
142
|
+
{ target: pointToken, value: 0n, data: feeTransferCallData }, // optional
|
|
143
|
+
]);
|
|
174
144
|
|
|
175
|
-
|
|
176
|
-
const userOp = buildSwapWithGasDeduction({
|
|
177
|
-
chainId: 8453,
|
|
145
|
+
const partial = buildPartialUserOperation({
|
|
178
146
|
sender: userAddress,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
pafiHookAddress: addrs.pafiHook,
|
|
183
|
-
quote,
|
|
184
|
-
slippageBps: 50,
|
|
185
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 300),
|
|
186
|
-
aaNonce: await getAaNonce(publicClient, userAddress),
|
|
187
|
-
batchExecutorAddress: addrs.batchExecutor,
|
|
188
|
-
gasFeePt: 0n, // set > 0 to deduct operator fee in PT
|
|
147
|
+
nonce: aaNonce,
|
|
148
|
+
operations: [...],
|
|
149
|
+
gasLimits: { callGasLimit: 300_000n, verificationGasLimit: 150_000n, preVerificationGas: 50_000n },
|
|
189
150
|
});
|
|
190
151
|
```
|
|
191
152
|
|
|
192
|
-
|
|
153
|
+
`computeUserOpHash(userOp, chainId)` — EntryPoint v0.8 EIP-712 digest.
|
|
154
|
+
The mobile prepare/submit flow signs this hash via Privy
|
|
155
|
+
`personal_sign`.
|
|
193
156
|
|
|
194
|
-
|
|
157
|
+
---
|
|
195
158
|
|
|
196
|
-
|
|
197
|
-
`BatchExecutor` capabilities without spending native ETH.
|
|
159
|
+
## EIP-7702 delegation helpers
|
|
198
160
|
|
|
199
161
|
```ts
|
|
200
162
|
import {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
163
|
+
computeAuthorizationHash,
|
|
164
|
+
parseEip7702DelegatedAddress,
|
|
165
|
+
splitAuthorizationSig,
|
|
166
|
+
buildEip7702Authorization,
|
|
205
167
|
} from "@pafi-dev/core";
|
|
206
168
|
|
|
207
|
-
|
|
169
|
+
// Check whether user EOA already has delegation installed
|
|
170
|
+
const code = await provider.getCode({ address: userAddress });
|
|
171
|
+
const designator = parseEip7702DelegatedAddress(code); // null = not delegated
|
|
208
172
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Then: sign the EIP-7702 authorization off-chain via Privy
|
|
215
|
-
// const authorization = await signAuthorization({ contractAddress: BATCH_EXECUTOR_ADDRESS_BASE_MAINNET, ... });
|
|
216
|
-
// await smartClient.sendTransaction({ to: userAddress, data: "0x", authorization });
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
## SIWE login message
|
|
222
|
-
|
|
223
|
-
```ts
|
|
224
|
-
import { createLoginMessage } from "@pafi-dev/core";
|
|
173
|
+
// Build the hash the user signs to authorize delegation
|
|
174
|
+
const accountNonce = BigInt(await provider.getTransactionCount({ address: userAddress }));
|
|
175
|
+
const authHash = computeAuthorizationHash(8453, batchExecutor, accountNonce);
|
|
225
176
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
177
|
+
// On the bundler side: split the user's 65-byte signature into the tuple
|
|
178
|
+
const { r, s, yParity } = splitAuthorizationSig(authSig);
|
|
179
|
+
const authorization = buildEip7702Authorization({
|
|
229
180
|
chainId: 8453,
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
181
|
+
address: batchExecutor,
|
|
182
|
+
nonce: accountNonce,
|
|
183
|
+
authSig,
|
|
233
184
|
});
|
|
234
|
-
|
|
235
|
-
// User signs with wallet, then POST /auth/login { message, signature }
|
|
236
185
|
```
|
|
237
186
|
|
|
238
187
|
---
|
|
239
188
|
|
|
240
|
-
##
|
|
189
|
+
## Operator fee quoter
|
|
190
|
+
|
|
191
|
+
Two helpers for FE direct-mode usage (no backend round-trip):
|
|
241
192
|
|
|
242
193
|
```ts
|
|
243
|
-
import {
|
|
244
|
-
buildPerpDepositWithGasDeduction,
|
|
245
|
-
computeAccountId,
|
|
246
|
-
BROKER_HASHES,
|
|
247
|
-
TOKEN_HASHES,
|
|
248
|
-
ORDERLY_VAULT_ADDRESSES,
|
|
249
|
-
} from "@pafi-dev/core";
|
|
194
|
+
import { quoteOperatorFeeUsdt, quoteOperatorFeePt } from "@pafi-dev/core";
|
|
250
195
|
|
|
251
|
-
|
|
196
|
+
// USDT-denominated (replaces issuer's GET /gas-fee).
|
|
197
|
+
// Pure RPC + Chainlink read.
|
|
198
|
+
const gasFeeUsdt = await quoteOperatorFeeUsdt({ provider, chainId: 8453 });
|
|
252
199
|
|
|
253
|
-
|
|
200
|
+
// PT-denominated (used by the swap flow as operator gas reimbursement
|
|
201
|
+
// in PT). Needs a subgraph call to read PT spot price.
|
|
202
|
+
const gasFeePt = await quoteOperatorFeePt({
|
|
203
|
+
provider,
|
|
254
204
|
chainId: 8453,
|
|
255
|
-
|
|
256
|
-
usdcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
257
|
-
vaultAddress: ORDERLY_VAULT_ADDRESSES[8453],
|
|
258
|
-
amount: 100n * 10n ** 6n,
|
|
259
|
-
accountId,
|
|
260
|
-
brokerHash: BROKER_HASHES["woofi_pro"],
|
|
261
|
-
tokenHash: TOKEN_HASHES["USDC"],
|
|
262
|
-
layerZeroFee: await vault.getDepositFee(),
|
|
263
|
-
aaNonce: await getAaNonce(publicClient, userAddress),
|
|
264
|
-
batchExecutorAddress: addrs.batchExecutor,
|
|
205
|
+
pointTokenAddress: POINT_TOKEN,
|
|
265
206
|
});
|
|
266
207
|
```
|
|
267
208
|
|
|
209
|
+
Both return `bigint` raw units. Sponsor-relayer's `FeeValidator` runs
|
|
210
|
+
the same math server-side with a 5% tolerance window — minor drift
|
|
211
|
+
between client and server is accepted.
|
|
212
|
+
|
|
268
213
|
---
|
|
269
214
|
|
|
270
|
-
##
|
|
271
|
-
|
|
272
|
-
### 0.5.16
|
|
273
|
-
|
|
274
|
-
ERC-4337 v0.8 + EIP-7702 mobile flow correctness fixes.
|
|
275
|
-
|
|
276
|
-
**Why this release.** The mobile prepare/submit flow (issuer backend computes
|
|
277
|
-
the userOpHash, mobile client signs it, backend submits to the bundler)
|
|
278
|
-
was reverting on Pimlico with `AA24 signature error` even though the same
|
|
279
|
-
UserOp validated cleanly on the web flow via `permissionless`. Three
|
|
280
|
-
distinct bugs stacked on top of each other; this release fixes them.
|
|
281
|
-
|
|
282
|
-
**1. `computeUserOpHash` now produces the EIP-712 typed digest used by
|
|
283
|
-
EntryPoint v0.8.** Previous versions hashed via the v0.7 scheme
|
|
284
|
-
(`keccak256(packed userOp || entryPoint || chainId)`), which produces a
|
|
285
|
-
totally different hash than what Pimlico's `Simple7702Account` (impl
|
|
286
|
-
`0xe6Cae8…`, `entryPoint() = 0x4337084d…`) actually validates against.
|
|
287
|
-
Symptom: `AA24` on every mobile UserOp.
|
|
288
|
-
|
|
289
|
-
**2. `buildUserOpTypedData()` exposed for client-side signing.** The
|
|
290
|
-
deployed Pimlico `Simple7702Account` validates the user signature with
|
|
291
|
-
`SignatureCheckerLib.isValidSignatureNow(address(this), userOpHash, sig)`
|
|
292
|
-
— **no EIP-191 prefix wrapping.** That means
|
|
293
|
-
`personal_sign` / `signMessage({ raw: userOpHash })` produces a signature
|
|
294
|
-
that `ecrecover`s to the wrong address; AA24 again. The new helper returns
|
|
295
|
-
`{ domain, types, primaryType, message }` ready to pass straight into
|
|
296
|
-
`walletClient.signTypedData(...)`. Because `userOpHash` IS the EIP-712
|
|
297
|
-
digest of `PackedUserOperation`, signing the typed data yields a
|
|
298
|
-
signature that recovers the EOA from the raw userOpHash — which is what
|
|
299
|
-
the contract checks.
|
|
215
|
+
## Sponsor-auth signing
|
|
300
216
|
|
|
301
217
|
```ts
|
|
302
|
-
import {
|
|
303
|
-
|
|
304
|
-
// Backend (gg56-backend, claim/prepare):
|
|
305
|
-
const typedData = buildUserOpTypedData(userOpWithPaymaster, chainId);
|
|
306
|
-
const userOpHash = computeUserOpHash(userOpWithPaymaster, chainId);
|
|
307
|
-
return { lockId, userOpHash, typedData /* serialise bigints */ };
|
|
308
|
-
|
|
309
|
-
// Client (Privy embedded wallet):
|
|
310
|
-
const signature = await walletClient.signTypedData({
|
|
311
|
-
domain: typedData.domain,
|
|
312
|
-
types: typedData.types,
|
|
313
|
-
primaryType: typedData.primaryType,
|
|
314
|
-
message: typedData.message,
|
|
315
|
-
});
|
|
316
|
-
// Submit { lockId, signature } to /claim/submit. AA24 stays away.
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
**Do NOT use `signMessage({ raw })` or `personal_sign` to sign a v0.8
|
|
320
|
-
userOpHash for `Simple7702Account`** — that path is a foot-gun the SDK
|
|
321
|
-
intentionally no longer offers a helper for.
|
|
218
|
+
import { buildAndSignSponsorAuth } from "@pafi-dev/core";
|
|
322
219
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
220
|
+
const sponsorAuth = await buildAndSignSponsorAuth({
|
|
221
|
+
userAddress,
|
|
222
|
+
callData: userOp.callData,
|
|
223
|
+
chainId: 8453,
|
|
224
|
+
scenario: "mint", // "mint" | "burn" | "swap" | "perp-deposit" | "delegate"
|
|
225
|
+
issuerId: ISSUER_ID,
|
|
226
|
+
issuerSignerWallet, // KMS-backed in prod
|
|
227
|
+
});
|
|
328
228
|
|
|
329
|
-
|
|
330
|
-
import { ENTRY_POINT_V08 } from "@pafi-dev/core";
|
|
331
|
-
// 0x4337084d9e255ff0702461cf8895ce9e3b5ff108
|
|
229
|
+
// Pass to sponsor-relayer's POST /paymaster/sponsor as the `sponsorAuth` field.
|
|
332
230
|
```
|
|
333
231
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
- `PERMIT2_ADDRESS` and `ENTRY_POINT_V07` centralised in `constants.ts`
|
|
337
|
-
- `BATCH_EXECUTOR_ADDRESS_BASE_*` derived from `addresses.ts` — no duplicate hardcoding
|
|
232
|
+
The issuer signer must be registered in PAFI's `IssuerRegistry`
|
|
233
|
+
(`signerAddress` field).
|
|
338
234
|
|
|
339
|
-
|
|
340
|
-
- All Base mainnet contract addresses live and verified against deployed contracts
|
|
235
|
+
---
|
|
341
236
|
|
|
342
|
-
|
|
343
|
-
- Full 4-scenario UserOp builders (mint, burn, swap, perp_deposit)
|
|
237
|
+
## License
|
|
344
238
|
|
|
345
|
-
|
|
346
|
-
- Initial EIP-7702 BatchExecutor support, UserOp primitives
|
|
239
|
+
Apache-2.0
|
package/dist/index.cjs
CHANGED
|
@@ -396,26 +396,19 @@ function buildPerpDepositViaRelay(params) {
|
|
|
396
396
|
throw new Error("buildPerpDepositViaRelay: relayAddress required");
|
|
397
397
|
}
|
|
398
398
|
const operations = [];
|
|
399
|
-
if (params.
|
|
400
|
-
if (!params.
|
|
399
|
+
if (params.gasFeeUsdc && params.gasFeeUsdc > 0n) {
|
|
400
|
+
if (!params.gasFeeUsdcRecipient) {
|
|
401
401
|
throw new Error(
|
|
402
|
-
"buildPerpDepositViaRelay:
|
|
402
|
+
"buildPerpDepositViaRelay: gasFeeUsdcRecipient required when gasFeeUsdc > 0"
|
|
403
403
|
);
|
|
404
404
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
value: 0n,
|
|
413
|
-
data: _viem.encodeFunctionData.call(void 0, {
|
|
414
|
-
abi: _viem.erc20Abi,
|
|
415
|
-
functionName: "transfer",
|
|
416
|
-
args: [params.gasFeePtRecipient, params.gasFeePt]
|
|
417
|
-
})
|
|
418
|
-
});
|
|
405
|
+
operations.push(
|
|
406
|
+
erc20TransferOp(
|
|
407
|
+
params.request.token,
|
|
408
|
+
params.gasFeeUsdcRecipient,
|
|
409
|
+
params.gasFeeUsdc
|
|
410
|
+
)
|
|
411
|
+
);
|
|
419
412
|
}
|
|
420
413
|
operations.push(
|
|
421
414
|
erc20ApproveOp(
|