@aastar/sdk 0.20.8 → 0.20.9
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/dist/BaseClient-CkBhQ1ou.d.cts +88 -0
- package/dist/UserClient-2J6XMTNV.cjs +15 -0
- package/dist/UserClient-2J6XMTNV.cjs.map +1 -0
- package/dist/account.cjs +31 -0
- package/dist/account.cjs.map +1 -0
- package/dist/account.d.cts +48 -0
- package/dist/admin.cjs +15 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.d.cts +62 -0
- package/dist/airaccount.cjs +452 -0
- package/dist/airaccount.cjs.map +1 -0
- package/dist/airaccount.d.cts +4 -0
- package/dist/channel-CkRRbzT8.d.cts +77 -0
- package/dist/channel.cjs +27 -0
- package/dist/channel.cjs.map +1 -0
- package/dist/channel.d.cts +64 -0
- package/dist/chunk-2RCJBWPO.cjs +1168 -0
- package/dist/chunk-2RCJBWPO.cjs.map +1 -0
- package/dist/chunk-FTJD2DWE.cjs +42472 -0
- package/dist/chunk-FTJD2DWE.cjs.map +1 -0
- package/dist/chunk-GRDC6ZRA.cjs +118 -0
- package/dist/chunk-GRDC6ZRA.cjs.map +1 -0
- package/dist/chunk-GX7NROST.cjs +421 -0
- package/dist/chunk-GX7NROST.cjs.map +1 -0
- package/dist/chunk-HSVQIFIK.cjs +128 -0
- package/dist/chunk-HSVQIFIK.cjs.map +1 -0
- package/dist/chunk-JTWY2XEG.cjs +115 -0
- package/dist/chunk-JTWY2XEG.cjs.map +1 -0
- package/dist/chunk-MRREGCWN.cjs +585 -0
- package/dist/chunk-MRREGCWN.cjs.map +1 -0
- package/dist/chunk-NT26BDGN.cjs +228 -0
- package/dist/chunk-NT26BDGN.cjs.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +11 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/chunk-QLF7N6H7.cjs +448 -0
- package/dist/chunk-QLF7N6H7.cjs.map +1 -0
- package/dist/chunk-RNHSA3LO.cjs +108 -0
- package/dist/chunk-RNHSA3LO.cjs.map +1 -0
- package/dist/chunk-S5IKOOUR.cjs +393 -0
- package/dist/chunk-S5IKOOUR.cjs.map +1 -0
- package/dist/chunk-TFLZETWB.cjs +4693 -0
- package/dist/chunk-TFLZETWB.cjs.map +1 -0
- package/dist/chunk-WQREDGUF.cjs +435 -0
- package/dist/chunk-WQREDGUF.cjs.map +1 -0
- package/dist/chunk-XQROKLZI.cjs +4521 -0
- package/dist/chunk-XQROKLZI.cjs.map +1 -0
- package/dist/contract-addresses-TANQ5DLX.cjs +49 -0
- package/dist/contract-addresses-TANQ5DLX.cjs.map +1 -0
- package/dist/core.cjs +894 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +6930 -0
- package/dist/dapp.cjs +289 -0
- package/dist/dapp.cjs.map +1 -0
- package/dist/dapp.d.cts +127 -0
- package/dist/doc-types-471vSmPO.d.cts +16 -0
- package/dist/enduser.cjs +24 -0
- package/dist/enduser.cjs.map +1 -0
- package/dist/enduser.d.cts +261 -0
- package/dist/identity.cjs +23 -0
- package/dist/identity.cjs.map +1 -0
- package/dist/identity.d.cts +81 -0
- package/dist/index-B6SfEQxo.d.cts +47 -0
- package/dist/index.cjs +2814 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +656 -0
- package/dist/kms.cjs +452 -0
- package/dist/kms.cjs.map +1 -0
- package/dist/kms.d.cts +3054 -0
- package/dist/lib-FE4GR7TO.cjs +1865 -0
- package/dist/lib-FE4GR7TO.cjs.map +1 -0
- package/dist/operator.cjs +27 -0
- package/dist/operator.cjs.map +1 -0
- package/dist/operator.d.cts +164 -0
- package/dist/paymaster.cjs +63 -0
- package/dist/paymaster.cjs.map +1 -0
- package/dist/paymaster.d.cts +312 -0
- package/dist/src-ENPA7D2S.cjs +63 -0
- package/dist/src-ENPA7D2S.cjs.map +1 -0
- package/dist/src-TQKEO2I4.cjs +894 -0
- package/dist/src-TQKEO2I4.cjs.map +1 -0
- package/dist/tier-router-DeeVg69O.d.cts +370 -0
- package/dist/tokens.cjs +15 -0
- package/dist/tokens.cjs.map +1 -0
- package/dist/tokens.d.cts +64 -0
- package/dist/x402.cjs +103 -0
- package/dist/x402.cjs.map +1 -0
- package/dist/x402.d.cts +373 -0
- package/package.json +32 -32
|
@@ -0,0 +1,1168 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkFTJD2DWE_cjs = require('./chunk-FTJD2DWE.cjs');
|
|
4
|
+
var viem = require('viem');
|
|
5
|
+
|
|
6
|
+
var DEFAULT_VERIFICATION_GAS = 160000n;
|
|
7
|
+
var DEFAULT_POSTOP_GAS = 10000n;
|
|
8
|
+
function getSuperPaymasterMiddleware(config) {
|
|
9
|
+
return {
|
|
10
|
+
sponsorUserOperation: async (args) => {
|
|
11
|
+
const verGas = config.verificationGasLimit ?? DEFAULT_VERIFICATION_GAS;
|
|
12
|
+
const postGas = config.postOpGasLimit ?? DEFAULT_POSTOP_GAS;
|
|
13
|
+
const maxRate = config.maxRate ?? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn;
|
|
14
|
+
const paymasterAndData = viem.concat([
|
|
15
|
+
config.paymasterAddress,
|
|
16
|
+
viem.pad(viem.toHex(verGas), { size: 16 }),
|
|
17
|
+
viem.pad(viem.toHex(postGas), { size: 16 }),
|
|
18
|
+
config.operator,
|
|
19
|
+
viem.pad(viem.toHex(maxRate), { size: 32 })
|
|
20
|
+
]);
|
|
21
|
+
return {
|
|
22
|
+
paymasterAndData,
|
|
23
|
+
verificationGasLimit: verGas,
|
|
24
|
+
preVerificationGas: args.userOperation.preVerificationGas
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function checkEligibility(client, paymaster, user, operator) {
|
|
30
|
+
try {
|
|
31
|
+
const operatorData = await client.readContract({
|
|
32
|
+
address: paymaster,
|
|
33
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
34
|
+
functionName: "operators",
|
|
35
|
+
args: [operator]
|
|
36
|
+
});
|
|
37
|
+
const token = operatorData[0];
|
|
38
|
+
const isConfigured = operatorData[2];
|
|
39
|
+
const isPaused = operatorData[3];
|
|
40
|
+
if (!isConfigured || isPaused) {
|
|
41
|
+
return { eligible: false };
|
|
42
|
+
}
|
|
43
|
+
const credit = await client.readContract({
|
|
44
|
+
address: paymaster,
|
|
45
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
46
|
+
functionName: "getAvailableCredit",
|
|
47
|
+
args: [user, token]
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
eligible: credit > 0n,
|
|
51
|
+
credit,
|
|
52
|
+
token
|
|
53
|
+
};
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.warn("Eligibility check failed:", e);
|
|
56
|
+
return { eligible: false };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
var SuperPaymasterAdminClient = class {
|
|
60
|
+
client;
|
|
61
|
+
paymasterAddress;
|
|
62
|
+
constructor(client, paymasterAddress) {
|
|
63
|
+
this.client = client;
|
|
64
|
+
this.paymasterAddress = paymasterAddress;
|
|
65
|
+
}
|
|
66
|
+
async getOperator(operator) {
|
|
67
|
+
return this.client.readContract({
|
|
68
|
+
address: this.paymasterAddress,
|
|
69
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
70
|
+
functionName: "operators",
|
|
71
|
+
args: [operator]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
static async configureOperator(wallet, paymaster, token, treasury) {
|
|
75
|
+
return wallet.writeContract({
|
|
76
|
+
address: paymaster,
|
|
77
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
78
|
+
functionName: "configureOperator",
|
|
79
|
+
args: [token, treasury],
|
|
80
|
+
chain: wallet.chain
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
static async setOperatorPaused(wallet, paymaster, operator, paused) {
|
|
84
|
+
return wallet.writeContract({
|
|
85
|
+
address: paymaster,
|
|
86
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
87
|
+
functionName: "setOperatorPaused",
|
|
88
|
+
args: [operator, paused],
|
|
89
|
+
chain: wallet.chain
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
static async updateReputation(wallet, paymaster, operator, score) {
|
|
93
|
+
return wallet.writeContract({
|
|
94
|
+
address: paymaster,
|
|
95
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
96
|
+
functionName: "updateReputation",
|
|
97
|
+
args: [operator, score],
|
|
98
|
+
chain: wallet.chain
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
static async setAPNTsToken(wallet, paymaster, token) {
|
|
102
|
+
return wallet.writeContract({
|
|
103
|
+
address: paymaster,
|
|
104
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
105
|
+
functionName: "setAPNTsToken",
|
|
106
|
+
args: [token],
|
|
107
|
+
chain: wallet.chain
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
static async setXPNTsFactory(wallet, paymaster, factory) {
|
|
111
|
+
return wallet.writeContract({
|
|
112
|
+
address: paymaster,
|
|
113
|
+
abi: chunkFTJD2DWE_cjs.SuperPaymasterABI,
|
|
114
|
+
functionName: "setXPNTsFactory",
|
|
115
|
+
args: [factory],
|
|
116
|
+
chain: wallet.chain
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var DEFAULT_VERIFICATION_GAS_V4 = 1500000n;
|
|
121
|
+
var DEFAULT_POSTOP_GAS_V4 = 300000n;
|
|
122
|
+
function getPaymasterV4Middleware(config) {
|
|
123
|
+
return {
|
|
124
|
+
sponsorUserOperation: async (args) => {
|
|
125
|
+
const verGas = config.verificationGasLimit ?? DEFAULT_VERIFICATION_GAS_V4;
|
|
126
|
+
const postGas = config.postOpGasLimit ?? DEFAULT_POSTOP_GAS_V4;
|
|
127
|
+
const paymasterAndData = viem.concat([
|
|
128
|
+
config.paymasterAddress,
|
|
129
|
+
viem.pad(viem.toHex(verGas), { size: 16 }),
|
|
130
|
+
viem.pad(viem.toHex(postGas), { size: 16 }),
|
|
131
|
+
config.gasToken
|
|
132
|
+
]);
|
|
133
|
+
return {
|
|
134
|
+
paymasterAndData,
|
|
135
|
+
verificationGasLimit: verGas,
|
|
136
|
+
preVerificationGas: args.userOperation.preVerificationGas
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function buildPaymasterData(paymasterAddress, token, options) {
|
|
142
|
+
const validityWindow = options?.validityWindow ?? 3600;
|
|
143
|
+
const verGas = options?.verificationGasLimit ?? 200000n;
|
|
144
|
+
const postGas = options?.postOpGasLimit ?? 100000n;
|
|
145
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
146
|
+
const validUntil = now + validityWindow;
|
|
147
|
+
const validAfter = now - 100;
|
|
148
|
+
return viem.concat([
|
|
149
|
+
paymasterAddress,
|
|
150
|
+
viem.pad(viem.toHex(verGas), { size: 16 }),
|
|
151
|
+
viem.pad(viem.toHex(postGas), { size: 16 }),
|
|
152
|
+
token,
|
|
153
|
+
viem.pad(viem.toHex(validUntil), { size: 6 }),
|
|
154
|
+
viem.pad(viem.toHex(validAfter), { size: 6 })
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
function buildSuperPaymasterData(paymasterAddress, operator, options) {
|
|
158
|
+
const verGas = options?.verificationGasLimit ?? 80000n;
|
|
159
|
+
const postGas = options?.postOpGasLimit ?? 100000n;
|
|
160
|
+
const maxRate = options?.maxRate ?? (1n << 256n) - 1n;
|
|
161
|
+
return viem.concat([
|
|
162
|
+
paymasterAddress,
|
|
163
|
+
viem.pad(viem.toHex(verGas), { size: 16 }),
|
|
164
|
+
viem.pad(viem.toHex(postGas), { size: 16 }),
|
|
165
|
+
operator,
|
|
166
|
+
viem.pad(viem.toHex(maxRate), { size: 32 })
|
|
167
|
+
// Optional rate commitment (rug pull protection)
|
|
168
|
+
]);
|
|
169
|
+
}
|
|
170
|
+
function formatUserOpV07(userOp) {
|
|
171
|
+
const result = {
|
|
172
|
+
sender: userOp.sender,
|
|
173
|
+
nonce: viem.toHex(userOp.nonce),
|
|
174
|
+
callData: userOp.callData,
|
|
175
|
+
preVerificationGas: viem.toHex(userOp.preVerificationGas),
|
|
176
|
+
signature: userOp.signature
|
|
177
|
+
};
|
|
178
|
+
if (userOp.initCode && userOp.initCode !== "0x" && userOp.initCode.length > 2) {
|
|
179
|
+
result.initCode = userOp.initCode;
|
|
180
|
+
if (userOp.initCode.length > 42) {
|
|
181
|
+
result.factory = userOp.initCode.slice(0, 42);
|
|
182
|
+
result.factoryData = "0x" + userOp.initCode.slice(42);
|
|
183
|
+
} else {
|
|
184
|
+
result.factory = "0x0000000000000000000000000000000000000000";
|
|
185
|
+
result.factoryData = "0x";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (userOp.accountGasLimits && userOp.accountGasLimits !== "0x") {
|
|
189
|
+
const packed = userOp.accountGasLimits.replace("0x", "").padStart(64, "0");
|
|
190
|
+
result.verificationGasLimit = "0x" + BigInt("0x" + packed.slice(0, 32)).toString(16);
|
|
191
|
+
result.callGasLimit = "0x" + BigInt("0x" + packed.slice(32, 64)).toString(16);
|
|
192
|
+
}
|
|
193
|
+
if (userOp.gasFees && userOp.gasFees !== "0x") {
|
|
194
|
+
const packed = userOp.gasFees.replace("0x", "").padStart(64, "0");
|
|
195
|
+
result.maxPriorityFeePerGas = "0x" + BigInt("0x" + packed.slice(0, 32)).toString(16);
|
|
196
|
+
result.maxFeePerGas = "0x" + BigInt("0x" + packed.slice(32, 64)).toString(16);
|
|
197
|
+
}
|
|
198
|
+
if (userOp.paymasterAndData && userOp.paymasterAndData !== "0x") {
|
|
199
|
+
const packed = userOp.paymasterAndData.replace("0x", "");
|
|
200
|
+
if (packed.length >= 104) {
|
|
201
|
+
result.paymaster = "0x" + packed.slice(0, 40);
|
|
202
|
+
result.paymasterVerificationGasLimit = "0x" + BigInt("0x" + packed.slice(40, 72)).toString(16);
|
|
203
|
+
result.paymasterPostOpGasLimit = "0x" + BigInt("0x" + packed.slice(72, 104)).toString(16);
|
|
204
|
+
result.paymasterData = "0x" + packed.slice(104);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
function getUserOpHashV07(userOp, entryPoint, chainId) {
|
|
210
|
+
const hashedUserOp = viem.keccak256(viem.encodeAbiParameters(
|
|
211
|
+
["address", "uint256", "bytes32", "bytes32", "bytes32", "uint256", "bytes32", "bytes32"].map((t) => ({ type: t })),
|
|
212
|
+
[
|
|
213
|
+
userOp.sender,
|
|
214
|
+
userOp.nonce,
|
|
215
|
+
viem.keccak256(viem.toBytes(userOp.initCode)),
|
|
216
|
+
viem.keccak256(viem.toBytes(userOp.callData)),
|
|
217
|
+
userOp.accountGasLimits,
|
|
218
|
+
viem.toHex(userOp.preVerificationGas),
|
|
219
|
+
userOp.gasFees,
|
|
220
|
+
viem.keccak256(viem.toBytes(userOp.paymasterAndData))
|
|
221
|
+
]
|
|
222
|
+
));
|
|
223
|
+
return viem.keccak256(viem.encodeAbiParameters(
|
|
224
|
+
["bytes32", "address", "uint256"].map((t) => ({ type: t })),
|
|
225
|
+
[hashedUserOp, entryPoint, chainId]
|
|
226
|
+
));
|
|
227
|
+
}
|
|
228
|
+
function tuneGasLimit(estimate, nominalActual, targetEfficiency = 0.45) {
|
|
229
|
+
if (estimate === 0n) return 0n;
|
|
230
|
+
const ceiling = nominalActual * 100n / BigInt(Math.floor(targetEfficiency * 100));
|
|
231
|
+
return estimate < ceiling ? estimate : ceiling;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ../paymaster/src/V4/BundlerCompat.ts
|
|
235
|
+
function detectBundlerType(bundlerUrl) {
|
|
236
|
+
const url = bundlerUrl.toLowerCase();
|
|
237
|
+
if (url.includes("alchemy.com")) return "alchemy" /* ALCHEMY */;
|
|
238
|
+
if (url.includes("pimlico.io")) return "pimlico" /* PIMLICO */;
|
|
239
|
+
if (url.includes("stackup")) return "stackup" /* STACKUP */;
|
|
240
|
+
if (url.includes("candide.dev")) return "candide" /* CANDIDE */;
|
|
241
|
+
return "unknown" /* UNKNOWN */;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ../paymaster/src/V4/PaymasterClient.ts
|
|
245
|
+
var PaymasterClient = class _PaymasterClient {
|
|
246
|
+
/**
|
|
247
|
+
* @private
|
|
248
|
+
* Static utility class, should not be instantiated.
|
|
249
|
+
*/
|
|
250
|
+
constructor() {
|
|
251
|
+
}
|
|
252
|
+
static makePlaceholderSignature(byteLength) {
|
|
253
|
+
const clamped = Math.max(0, Math.min(byteLength, 1e4));
|
|
254
|
+
return `0x${"11".repeat(clamped)}`;
|
|
255
|
+
}
|
|
256
|
+
static estimatePreVerificationGasV07(userOp) {
|
|
257
|
+
const encoded = viem.encodeAbiParameters(
|
|
258
|
+
viem.parseAbiParameters("(address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)"),
|
|
259
|
+
[
|
|
260
|
+
[
|
|
261
|
+
userOp.sender,
|
|
262
|
+
userOp.nonce,
|
|
263
|
+
userOp.initCode,
|
|
264
|
+
userOp.callData,
|
|
265
|
+
userOp.accountGasLimits,
|
|
266
|
+
userOp.preVerificationGas,
|
|
267
|
+
userOp.gasFees,
|
|
268
|
+
userOp.paymasterAndData,
|
|
269
|
+
userOp.signature
|
|
270
|
+
]
|
|
271
|
+
]
|
|
272
|
+
);
|
|
273
|
+
const bytes = viem.toBytes(encoded);
|
|
274
|
+
let calldataCost = 0n;
|
|
275
|
+
for (const b of bytes) calldataCost += b === 0 ? 4n : 16n;
|
|
276
|
+
return calldataCost + 26000n;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get user's deposited balance on the Paymaster.
|
|
280
|
+
*/
|
|
281
|
+
static async getDepositedBalance(publicClient, address, user, token) {
|
|
282
|
+
return publicClient.readContract({
|
|
283
|
+
address,
|
|
284
|
+
abi: [{
|
|
285
|
+
name: "balances",
|
|
286
|
+
type: "function",
|
|
287
|
+
inputs: [
|
|
288
|
+
{ name: "user", type: "address" },
|
|
289
|
+
{ name: "token", type: "address" }
|
|
290
|
+
],
|
|
291
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
292
|
+
stateMutability: "view"
|
|
293
|
+
}],
|
|
294
|
+
functionName: "balances",
|
|
295
|
+
args: [user, token]
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Deposit tokens to Paymaster for a user (enables gasless transactions).
|
|
300
|
+
*/
|
|
301
|
+
static async depositFor(wallet, address, user, token, amount) {
|
|
302
|
+
return wallet.writeContract({
|
|
303
|
+
address,
|
|
304
|
+
abi: viem.parseAbi(["function depositFor(address user, address token, uint256 amount) external"]),
|
|
305
|
+
functionName: "depositFor",
|
|
306
|
+
args: [user, token, amount],
|
|
307
|
+
chain: wallet.chain
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Approve the Paymaster (or any spender) to spend gas tokens.
|
|
312
|
+
*/
|
|
313
|
+
static async approveGasToken(wallet, token, spender, amount) {
|
|
314
|
+
return wallet.writeContract({
|
|
315
|
+
address: token,
|
|
316
|
+
abi: viem.parseAbi(["function approve(address spender, uint256 amount) external returns (bool)"]),
|
|
317
|
+
functionName: "approve",
|
|
318
|
+
args: [spender, amount],
|
|
319
|
+
chain: wallet.chain
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Estimate Gas for a UserOperation.
|
|
324
|
+
*/
|
|
325
|
+
static async estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
|
|
326
|
+
if (!options?.operator) {
|
|
327
|
+
try {
|
|
328
|
+
const cache = await client.readContract({
|
|
329
|
+
address: paymasterAddress,
|
|
330
|
+
abi: viem.parseAbi(["function cachedPrice() view returns (uint208 price, uint48 updatedAt)"]),
|
|
331
|
+
functionName: "cachedPrice"
|
|
332
|
+
});
|
|
333
|
+
const cachedPrice = BigInt(cache?.price ?? cache?.[0] ?? 0);
|
|
334
|
+
const cachedUpdatedAt = BigInt(cache?.updatedAt ?? cache?.[1] ?? 0);
|
|
335
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
336
|
+
let stalenessThreshold = 0n;
|
|
337
|
+
try {
|
|
338
|
+
stalenessThreshold = await client.readContract({
|
|
339
|
+
address: paymasterAddress,
|
|
340
|
+
abi: viem.parseAbi(["function priceStalenessThreshold() view returns (uint256)"]),
|
|
341
|
+
functionName: "priceStalenessThreshold"
|
|
342
|
+
});
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
const isStale = cachedPrice === 0n || cachedUpdatedAt === 0n || stalenessThreshold > 0n && cachedUpdatedAt + stalenessThreshold < now;
|
|
346
|
+
if (isStale) {
|
|
347
|
+
const chainId2 = client.chain?.id || await client.getChainId();
|
|
348
|
+
const isTestnet2 = [11155111, 11155420, 31337].includes(chainId2);
|
|
349
|
+
if (isTestnet2) {
|
|
350
|
+
const updateHash = await wallet.writeContract({
|
|
351
|
+
address: paymasterAddress,
|
|
352
|
+
abi: viem.parseAbi(["function updatePrice() external"]),
|
|
353
|
+
functionName: "updatePrice"
|
|
354
|
+
});
|
|
355
|
+
await client.waitForTransactionReceipt({ hash: updateHash });
|
|
356
|
+
console.log("[PaymasterClient] \u2705 cachedPrice refreshed via updatePrice()");
|
|
357
|
+
} else {
|
|
358
|
+
throw new Error(
|
|
359
|
+
`Paymaster cachedPrice is stale on Mainnet (chainId: ${chainId2}). This requires Keeper to call updatePrice(). Please ensure Keeper is running.`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
} catch (e) {
|
|
364
|
+
if (e.message?.includes("requires Keeper")) throw e;
|
|
365
|
+
console.log("[PaymasterClient] \u26A0\uFE0F Failed to check cachedPrice:", e.message?.slice(0, 50));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
let paymasterAndData;
|
|
369
|
+
if (options?.operator) {
|
|
370
|
+
paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
|
|
371
|
+
verificationGasLimit: 300000n,
|
|
372
|
+
postOpGasLimit: 300000n
|
|
373
|
+
});
|
|
374
|
+
} else {
|
|
375
|
+
paymasterAndData = buildPaymasterData(paymasterAddress, token, {
|
|
376
|
+
validityWindow: options?.validityWindow,
|
|
377
|
+
verificationGasLimit: 250000n,
|
|
378
|
+
postOpGasLimit: 150000n
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
const chainId = client.chain?.id || await client.getChainId();
|
|
382
|
+
const isTestnet = [11155111, 11155420, 31337].includes(chainId);
|
|
383
|
+
const TESTNET_PRIORITY_FLOOR = 500000000n;
|
|
384
|
+
let maxFeePerGas = 0n;
|
|
385
|
+
let maxPriorityFeePerGas = 0n;
|
|
386
|
+
try {
|
|
387
|
+
const feeData = await client.estimateFeesPerGas();
|
|
388
|
+
maxFeePerGas = (feeData.maxFeePerGas ?? 0n) * 115n / 100n;
|
|
389
|
+
maxPriorityFeePerGas = (feeData.maxPriorityFeePerGas ?? 0n) * 115n / 100n;
|
|
390
|
+
} catch {
|
|
391
|
+
}
|
|
392
|
+
if (!maxFeePerGas) {
|
|
393
|
+
try {
|
|
394
|
+
const gasPrice = await client.getGasPrice();
|
|
395
|
+
maxFeePerGas = gasPrice * 120n / 100n;
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (isTestnet) {
|
|
400
|
+
if (maxPriorityFeePerGas < TESTNET_PRIORITY_FLOOR) maxPriorityFeePerGas = TESTNET_PRIORITY_FLOOR;
|
|
401
|
+
if (maxFeePerGas < TESTNET_PRIORITY_FLOOR * 2n) maxFeePerGas = TESTNET_PRIORITY_FLOOR * 2n;
|
|
402
|
+
}
|
|
403
|
+
if (!maxFeePerGas) maxFeePerGas = 1n;
|
|
404
|
+
if (maxFeePerGas < maxPriorityFeePerGas) maxFeePerGas = maxPriorityFeePerGas + 1n;
|
|
405
|
+
const partialUserOp = {
|
|
406
|
+
sender: aaAddress,
|
|
407
|
+
nonce: 0n,
|
|
408
|
+
initCode: options?.factory && options?.factoryData ? viem.concat([options.factory, options.factoryData]) : "0x",
|
|
409
|
+
callData,
|
|
410
|
+
accountGasLimits: viem.concat([viem.pad(viem.toHex(250000n), { size: 16 }), viem.pad(viem.toHex(500000n), { size: 16 })]),
|
|
411
|
+
preVerificationGas: 0n,
|
|
412
|
+
gasFees: viem.concat([viem.pad(viem.toHex(maxPriorityFeePerGas), { size: 16 }), viem.pad(viem.toHex(maxFeePerGas), { size: 16 })]),
|
|
413
|
+
paymasterAndData,
|
|
414
|
+
signature: _PaymasterClient.makePlaceholderSignature(65)
|
|
415
|
+
};
|
|
416
|
+
try {
|
|
417
|
+
const nonce = await client.readContract({
|
|
418
|
+
address: aaAddress,
|
|
419
|
+
abi: viem.parseAbi(["function getNonce() view returns (uint256)"]),
|
|
420
|
+
functionName: "getNonce"
|
|
421
|
+
});
|
|
422
|
+
partialUserOp.nonce = BigInt(nonce);
|
|
423
|
+
} catch (e) {
|
|
424
|
+
}
|
|
425
|
+
partialUserOp.preVerificationGas = _PaymasterClient.estimatePreVerificationGasV07(partialUserOp) * 120n / 100n + 5000n;
|
|
426
|
+
const userOpHash = getUserOpHashV07(partialUserOp, entryPoint, BigInt(client.chain.id));
|
|
427
|
+
partialUserOp.signature = await wallet.account.signMessage({ message: { raw: userOpHash } });
|
|
428
|
+
const payload = {
|
|
429
|
+
jsonrpc: "2.0",
|
|
430
|
+
id: 1,
|
|
431
|
+
method: "eth_estimateUserOperationGas",
|
|
432
|
+
params: [formatUserOpV07(partialUserOp), entryPoint]
|
|
433
|
+
};
|
|
434
|
+
const response = await fetch(bundlerUrl, {
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: { "Content-Type": "application/json" },
|
|
437
|
+
body: JSON.stringify(payload, (_, v) => typeof v === "bigint" ? "0x" + v.toString(16) : v)
|
|
438
|
+
});
|
|
439
|
+
const result = await response.json();
|
|
440
|
+
if (bundlerUrl.includes("candide")) {
|
|
441
|
+
console.log("[PaymasterClient] Candide Request:", JSON.stringify(payload.params[0], null, 2));
|
|
442
|
+
console.log("[PaymasterClient] Candide Response:", JSON.stringify(result, null, 2));
|
|
443
|
+
}
|
|
444
|
+
const data = result.result;
|
|
445
|
+
console.log("[PaymasterClient] Gas Estimation Result:", JSON.stringify(data, null, 2));
|
|
446
|
+
if (result.error && (result.error.code === -32601 || result.error.message?.includes("Method not found"))) {
|
|
447
|
+
console.log("[PaymasterClient] EstimateUserOp failed (Method not found). Using Anvil defaults.");
|
|
448
|
+
return {
|
|
449
|
+
preVerificationGas: partialUserOp.preVerificationGas,
|
|
450
|
+
verificationGasLimit: 1000000n,
|
|
451
|
+
callGasLimit: 2000000n,
|
|
452
|
+
paymasterVerificationGasLimit: 100000n,
|
|
453
|
+
paymasterPostOpGasLimit: 100000n
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
if (result.error) throw new Error(`Estimation Error: ${JSON.stringify(result.error)}`);
|
|
457
|
+
const estVGL = BigInt(data.verificationGasLimit);
|
|
458
|
+
const estPMVGL = data.paymasterVerificationGasLimit ? BigInt(data.paymasterVerificationGasLimit) : 100000n;
|
|
459
|
+
return {
|
|
460
|
+
preVerificationGas: BigInt(data.preVerificationGas) * 120n / 100n + 5000n,
|
|
461
|
+
verificationGasLimit: tuneGasLimit(estVGL, 35000n, 0.45),
|
|
462
|
+
callGasLimit: BigInt(data.callGasLimit) * 110n / 100n,
|
|
463
|
+
// Small 1.1x buffer
|
|
464
|
+
paymasterVerificationGasLimit: tuneGasLimit(estPMVGL, 35000n, 0.45),
|
|
465
|
+
paymasterPostOpGasLimit: data.paymasterPostOpGasLimit ? BigInt(data.paymasterPostOpGasLimit) : 100000n
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* High-level API to submit a gasless UserOperation.
|
|
470
|
+
* Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
|
|
471
|
+
*/
|
|
472
|
+
static async submitGaslessUserOperation(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
|
|
473
|
+
let gasLimits = {
|
|
474
|
+
preVerificationGas: options?.preVerificationGas,
|
|
475
|
+
verificationGasLimit: options?.verificationGasLimit,
|
|
476
|
+
callGasLimit: options?.callGasLimit,
|
|
477
|
+
paymasterVerificationGasLimit: options?.paymasterVerificationGasLimit,
|
|
478
|
+
paymasterPostOpGasLimit: options?.paymasterPostOpGasLimit ?? 200000n
|
|
479
|
+
};
|
|
480
|
+
if (options?.autoEstimate !== false && (!gasLimits.verificationGasLimit || !gasLimits.callGasLimit)) {
|
|
481
|
+
const est = await this.estimateUserOperationGas(
|
|
482
|
+
client,
|
|
483
|
+
wallet,
|
|
484
|
+
aaAddress,
|
|
485
|
+
entryPoint,
|
|
486
|
+
paymasterAddress,
|
|
487
|
+
token,
|
|
488
|
+
bundlerUrl,
|
|
489
|
+
callData,
|
|
490
|
+
{
|
|
491
|
+
validityWindow: options?.validityWindow,
|
|
492
|
+
operator: options?.operator,
|
|
493
|
+
factory: options?.factory,
|
|
494
|
+
factoryData: options?.factoryData
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
gasLimits.preVerificationGas = options?.preVerificationGas ?? est.preVerificationGas;
|
|
498
|
+
gasLimits.verificationGasLimit = options?.verificationGasLimit ?? est.verificationGasLimit;
|
|
499
|
+
gasLimits.callGasLimit = options?.callGasLimit ?? est.callGasLimit;
|
|
500
|
+
gasLimits.paymasterVerificationGasLimit = options?.paymasterVerificationGasLimit ?? est.paymasterVerificationGasLimit;
|
|
501
|
+
if (!options?.paymasterPostOpGasLimit) {
|
|
502
|
+
const _base = est.paymasterPostOpGasLimit + 100000n;
|
|
503
|
+
gasLimits.paymasterPostOpGasLimit = _base > 200000n ? _base : 200000n;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const nonce = await client.readContract({
|
|
507
|
+
address: aaAddress,
|
|
508
|
+
abi: viem.parseAbi(["function getNonce() view returns (uint256)"]),
|
|
509
|
+
functionName: "getNonce"
|
|
510
|
+
});
|
|
511
|
+
const chainId = client.chain?.id || await client.getChainId();
|
|
512
|
+
const isTestnet = [11155111, 11155420, 31337].includes(chainId);
|
|
513
|
+
const TESTNET_PRIORITY_FLOOR = 500000000n;
|
|
514
|
+
let maxFeePerGas = options?.maxFeePerGas;
|
|
515
|
+
let maxPriorityFeePerGas = options?.maxPriorityFeePerGas;
|
|
516
|
+
if (!maxFeePerGas || !maxPriorityFeePerGas) {
|
|
517
|
+
try {
|
|
518
|
+
const feeData = await client.estimateFeesPerGas();
|
|
519
|
+
maxFeePerGas = maxFeePerGas ?? (feeData.maxFeePerGas ?? 0n) * 115n / 100n;
|
|
520
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? (feeData.maxPriorityFeePerGas ?? 0n) * 115n / 100n;
|
|
521
|
+
} catch (e) {
|
|
522
|
+
maxFeePerGas = maxFeePerGas ?? void 0;
|
|
523
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? void 0;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (!maxFeePerGas) {
|
|
527
|
+
try {
|
|
528
|
+
maxFeePerGas = await client.getGasPrice() * 150n / 100n;
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (isTestnet) {
|
|
533
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? TESTNET_PRIORITY_FLOOR;
|
|
534
|
+
if (maxPriorityFeePerGas < TESTNET_PRIORITY_FLOOR) maxPriorityFeePerGas = TESTNET_PRIORITY_FLOOR;
|
|
535
|
+
if (!maxFeePerGas || maxFeePerGas < TESTNET_PRIORITY_FLOOR * 2n) maxFeePerGas = TESTNET_PRIORITY_FLOOR * 2n;
|
|
536
|
+
}
|
|
537
|
+
maxFeePerGas = maxFeePerGas ?? 1n;
|
|
538
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? 0n;
|
|
539
|
+
if (maxFeePerGas < maxPriorityFeePerGas) maxFeePerGas = maxPriorityFeePerGas + 1n;
|
|
540
|
+
console.log(`[PaymasterClient] Gas Pricing: ${isTestnet ? "TESTNET (0.5 Gwei floor)" : "MAINNET (dynamic)"} | priority=${maxPriorityFeePerGas} maxFee=${maxFeePerGas}`);
|
|
541
|
+
let paymasterAndData;
|
|
542
|
+
if (options?.operator) {
|
|
543
|
+
paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
|
|
544
|
+
verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n,
|
|
545
|
+
postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
|
|
546
|
+
});
|
|
547
|
+
} else {
|
|
548
|
+
const pmVerGas = gasLimits.paymasterVerificationGasLimit ?? 75000n;
|
|
549
|
+
paymasterAndData = buildPaymasterData(paymasterAddress, token, {
|
|
550
|
+
validityWindow: options?.validityWindow,
|
|
551
|
+
verificationGasLimit: pmVerGas,
|
|
552
|
+
postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
const initCode = options?.factory && options?.factoryData ? viem.concat([options.factory, options.factoryData]) : "0x";
|
|
556
|
+
const accountGasLimits = viem.concat([
|
|
557
|
+
viem.pad(viem.toHex(gasLimits.verificationGasLimit ?? 75000n), { size: 16 }),
|
|
558
|
+
viem.pad(viem.toHex(gasLimits.callGasLimit ?? 500000n), { size: 16 })
|
|
559
|
+
]);
|
|
560
|
+
const gasFees = viem.concat([
|
|
561
|
+
viem.pad(viem.toHex(maxPriorityFeePerGas), { size: 16 }),
|
|
562
|
+
viem.pad(viem.toHex(maxFeePerGas), { size: 16 })
|
|
563
|
+
]);
|
|
564
|
+
const preVerificationGas = gasLimits.preVerificationGas ?? _PaymasterClient.estimatePreVerificationGasV07({
|
|
565
|
+
sender: aaAddress,
|
|
566
|
+
nonce: BigInt(nonce),
|
|
567
|
+
initCode,
|
|
568
|
+
callData,
|
|
569
|
+
accountGasLimits,
|
|
570
|
+
preVerificationGas: 0n,
|
|
571
|
+
gasFees,
|
|
572
|
+
paymasterAndData,
|
|
573
|
+
signature: _PaymasterClient.makePlaceholderSignature(65)
|
|
574
|
+
}) * 120n / 100n + 5000n;
|
|
575
|
+
const userOp = {
|
|
576
|
+
sender: aaAddress,
|
|
577
|
+
nonce: BigInt(nonce),
|
|
578
|
+
initCode,
|
|
579
|
+
callData,
|
|
580
|
+
accountGasLimits,
|
|
581
|
+
preVerificationGas,
|
|
582
|
+
gasFees,
|
|
583
|
+
paymasterAndData,
|
|
584
|
+
signature: "0x"
|
|
585
|
+
};
|
|
586
|
+
const userOpHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
|
|
587
|
+
const signature = await wallet.account.signMessage({ message: { raw: userOpHash } });
|
|
588
|
+
userOp.signature = signature;
|
|
589
|
+
const bundlerType = detectBundlerType(bundlerUrl);
|
|
590
|
+
console.log(`[PaymasterClient] Using ${bundlerType} Bundler`);
|
|
591
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
592
|
+
const response = await fetch(bundlerUrl, {
|
|
593
|
+
method: "POST",
|
|
594
|
+
headers: { "Content-Type": "application/json" },
|
|
595
|
+
body: JSON.stringify({
|
|
596
|
+
jsonrpc: "2.0",
|
|
597
|
+
id: 1,
|
|
598
|
+
method: "eth_sendUserOperation",
|
|
599
|
+
params: [formatUserOpV07(userOp), entryPoint]
|
|
600
|
+
}, (_, v) => typeof v === "bigint" ? "0x" + v.toString(16) : v)
|
|
601
|
+
});
|
|
602
|
+
const result = await response.json();
|
|
603
|
+
if (result.error && attempt < 4) {
|
|
604
|
+
const msg = result.error.message || "";
|
|
605
|
+
const errData = result.error.data || {};
|
|
606
|
+
if (result.error.code === -32602 || msg.includes("replacement underpriced")) {
|
|
607
|
+
console.log(`[PaymasterClient] \u26A0\uFE0F Replacement Underpriced. Bumping fees to replace pending UserOp...`);
|
|
608
|
+
let newMaxPriority = userOp.gasFees ? BigInt("0x" + userOp.gasFees.slice(2, 34)) : 0n;
|
|
609
|
+
let newMaxFee = userOp.gasFees ? BigInt("0x" + userOp.gasFees.slice(34)) : 0n;
|
|
610
|
+
if (errData.currentMaxPriorityFee && errData.currentMaxFee) {
|
|
611
|
+
const currentPriority = BigInt(errData.currentMaxPriorityFee);
|
|
612
|
+
const currentMax = BigInt(errData.currentMaxFee);
|
|
613
|
+
newMaxPriority = currentPriority * 110n / 100n;
|
|
614
|
+
newMaxFee = currentMax * 110n / 100n;
|
|
615
|
+
} else {
|
|
616
|
+
newMaxPriority = newMaxPriority * 115n / 100n;
|
|
617
|
+
newMaxFee = newMaxFee * 115n / 100n;
|
|
618
|
+
}
|
|
619
|
+
console.log(` -> New Priority: ${newMaxPriority}, New MaxFee: ${newMaxFee}`);
|
|
620
|
+
userOp.gasFees = viem.concat([
|
|
621
|
+
viem.pad(viem.toHex(newMaxPriority), { size: 16 }),
|
|
622
|
+
viem.pad(viem.toHex(newMaxFee), { size: 16 })
|
|
623
|
+
]);
|
|
624
|
+
const newHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
|
|
625
|
+
userOp.signature = await wallet.account.signMessage({ message: { raw: newHash } });
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const matchPriority = msg.match(/maxPriorityFeePerGas.*(?:at least|expected) (\d+)/i) || msg.match(/priority fee.*(?:at least|expected) (\d+)/i);
|
|
629
|
+
const matchMaxFee = msg.match(/maxFeePerGas.*(?:at least|expected) (\d+)/i);
|
|
630
|
+
if (matchPriority || matchMaxFee) {
|
|
631
|
+
console.log(`[PaymasterClient] \u26A0\uFE0F Fee Error: ${msg}. Retrying with higher fees...`);
|
|
632
|
+
let newMaxPriority = userOp.gasFees ? BigInt("0x" + userOp.gasFees.slice(2, 34)) : 0n;
|
|
633
|
+
let newMaxFee = userOp.gasFees ? BigInt("0x" + userOp.gasFees.slice(34)) : 0n;
|
|
634
|
+
if (matchPriority && matchPriority[1]) {
|
|
635
|
+
const required = BigInt(matchPriority[1]);
|
|
636
|
+
if (required > newMaxPriority) {
|
|
637
|
+
console.log(` -> Bumping Priority Fee to ${required}`);
|
|
638
|
+
const delta = required - newMaxPriority;
|
|
639
|
+
newMaxPriority = required;
|
|
640
|
+
newMaxFee += delta;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (matchMaxFee && matchMaxFee[1]) {
|
|
644
|
+
const required = BigInt(matchMaxFee[1]);
|
|
645
|
+
if (required > newMaxFee) {
|
|
646
|
+
console.log(` -> Bumping Max Fee to ${required}`);
|
|
647
|
+
newMaxFee = required;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (newMaxFee < newMaxPriority) newMaxFee = newMaxPriority + 1n;
|
|
651
|
+
userOp.gasFees = viem.concat([
|
|
652
|
+
viem.pad(viem.toHex(newMaxPriority), { size: 16 }),
|
|
653
|
+
viem.pad(viem.toHex(newMaxFee), { size: 16 })
|
|
654
|
+
]);
|
|
655
|
+
const newHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
|
|
656
|
+
userOp.signature = await wallet.account.signMessage({ message: { raw: newHash } });
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
const matchPVG = msg.match(/preVerificationGas.*(?:at least|expected) (\d+)/i);
|
|
660
|
+
if (matchPVG && matchPVG[1]) {
|
|
661
|
+
const requiredPVG = BigInt(matchPVG[1]);
|
|
662
|
+
const currentPVG = BigInt(userOp.preVerificationGas);
|
|
663
|
+
if (requiredPVG > currentPVG) {
|
|
664
|
+
console.log(`[PaymasterClient] \u26A0\uFE0F PVG Error: ${msg}. Updating preVerificationGas...`);
|
|
665
|
+
const bufferedPVG = requiredPVG * 105n / 100n;
|
|
666
|
+
console.log(` -> Updating PVG from ${currentPVG} to ${bufferedPVG} (inc. buffer)`);
|
|
667
|
+
userOp.preVerificationGas = bufferedPVG;
|
|
668
|
+
const newHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
|
|
669
|
+
userOp.signature = await wallet.account.signMessage({ message: { raw: newHash } });
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (result.error && (result.error.code === -32601 || result.error.message?.includes("Method not found"))) {
|
|
675
|
+
console.log("[PaymasterClient] SendUserOp failed (Method not found). Falling back to direct handleOps...");
|
|
676
|
+
const caller = wallet.account?.address ? wallet.account.address : wallet.account;
|
|
677
|
+
return await wallet.writeContract({
|
|
678
|
+
address: entryPoint,
|
|
679
|
+
abi: viem.parseAbi(["function handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[], address) external"]),
|
|
680
|
+
functionName: "handleOps",
|
|
681
|
+
args: [[userOp], caller],
|
|
682
|
+
chain: wallet.chain,
|
|
683
|
+
account: wallet.account
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
if (result.error) throw new Error(`Bundler Error: ${JSON.stringify(result.error)}`);
|
|
687
|
+
console.log("[PaymasterClient] \u2705 Submitted via", bundlerType, "hash:", result.result);
|
|
688
|
+
return result.result;
|
|
689
|
+
}
|
|
690
|
+
throw new Error("Failed to submit UserOp after retries");
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Helper to extract the actual Gas Token fee from a UserOperation receipt.
|
|
694
|
+
* Looks for the 'PostOpProcessed' event emitted by the Paymaster.
|
|
695
|
+
*/
|
|
696
|
+
static getFeeFromReceipt(receipt, paymasterAddress) {
|
|
697
|
+
const TOPIC_POST_OP = "0x62544d7f48b11c32334310ebd306b47224fca220163218d4a7264322c52ae073";
|
|
698
|
+
for (const log of receipt.logs) {
|
|
699
|
+
if (log.address.toLowerCase() === paymasterAddress.toLowerCase() && log.topics[0] === TOPIC_POST_OP) {
|
|
700
|
+
const data = log.data.replace("0x", "");
|
|
701
|
+
if (data.length >= 192) {
|
|
702
|
+
const actualGasCostWei = BigInt("0x" + data.slice(0, 64));
|
|
703
|
+
const tokenCost = BigInt("0x" + data.slice(64, 128));
|
|
704
|
+
return { tokenCost, actualGasCostWei };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Get the fee for a specific transaction hash.
|
|
712
|
+
* Fetches the receipt (no scanning required) and decodes the log.
|
|
713
|
+
*/
|
|
714
|
+
static async getTransactionFee(publicClient, txHash, paymasterAddress) {
|
|
715
|
+
const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
|
|
716
|
+
return this.getFeeFromReceipt(receipt, paymasterAddress);
|
|
717
|
+
}
|
|
718
|
+
// ===========================================
|
|
719
|
+
// 🛠️ Semantic CallData Builders (For DX)
|
|
720
|
+
// ===========================================
|
|
721
|
+
/**
|
|
722
|
+
* Helper: Encode a standardized ERC-20 Transfer.
|
|
723
|
+
* Returns the raw function data: `transfer(to, amount)`
|
|
724
|
+
*/
|
|
725
|
+
static encodeTokenTransfer(recipient, amount) {
|
|
726
|
+
return viem.encodeFunctionData({
|
|
727
|
+
abi: viem.parseAbi(["function transfer(address to, uint256 amount) external returns (bool)"]),
|
|
728
|
+
functionName: "transfer",
|
|
729
|
+
args: [recipient, amount]
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Helper: Encode a SimpleAccount execution.
|
|
734
|
+
* Wraps the inner call into: `execute(target, value, data)`
|
|
735
|
+
* This is the payload signed by the user.
|
|
736
|
+
*/
|
|
737
|
+
static encodeExecution(target, value, data) {
|
|
738
|
+
return viem.encodeFunctionData({
|
|
739
|
+
abi: viem.parseAbi(["function execute(address dest, uint256 value, bytes func) external"]),
|
|
740
|
+
functionName: "execute",
|
|
741
|
+
args: [target, value, data]
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* More robust version of waitForUserOperationReceipt.
|
|
746
|
+
* Catches timeouts and returns a cleaner result.
|
|
747
|
+
*/
|
|
748
|
+
static async waitForUserOperation(bundlerClient, hash, timeout = 18e4) {
|
|
749
|
+
try {
|
|
750
|
+
return await bundlerClient.waitForUserOperationReceipt({ hash, timeout });
|
|
751
|
+
} catch (error) {
|
|
752
|
+
const errName = error.name || "";
|
|
753
|
+
const errMsg = error.message || "";
|
|
754
|
+
if (errName === "TimeoutError" || errName === "WaitForUserOperationReceiptTimeoutError" || /timed? out/i.test(errMsg)) {
|
|
755
|
+
return { timeout: true, hash };
|
|
756
|
+
}
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
var PaymasterOperator = class {
|
|
762
|
+
/**
|
|
763
|
+
* Update the cached ETH/USD price from Chainlink Oracle.
|
|
764
|
+
* Must be called if cachedPrice is 0 (uninitialized).
|
|
765
|
+
*/
|
|
766
|
+
static async updatePrice(wallet, address) {
|
|
767
|
+
return wallet.writeContract({
|
|
768
|
+
address,
|
|
769
|
+
abi: viem.parseAbi(["function updatePrice() external"]),
|
|
770
|
+
functionName: "updatePrice",
|
|
771
|
+
chain: wallet.chain
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Set the token price (in 8 decimals, e.g., 1e8 = $1 USD).
|
|
776
|
+
*/
|
|
777
|
+
static async setTokenPrice(wallet, address, token, priceUSD) {
|
|
778
|
+
return wallet.writeContract({
|
|
779
|
+
address,
|
|
780
|
+
abi: viem.parseAbi(["function setTokenPrice(address token, uint256 price) external"]),
|
|
781
|
+
functionName: "setTokenPrice",
|
|
782
|
+
args: [token, priceUSD],
|
|
783
|
+
chain: wallet.chain
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
static async getCachedPrice(publicClient, address) {
|
|
787
|
+
const result = await publicClient.readContract({
|
|
788
|
+
address,
|
|
789
|
+
abi: [{
|
|
790
|
+
name: "cachedPrice",
|
|
791
|
+
type: "function",
|
|
792
|
+
inputs: [],
|
|
793
|
+
outputs: [
|
|
794
|
+
{ name: "price", type: "uint208" },
|
|
795
|
+
{ name: "updatedAt", type: "uint48" }
|
|
796
|
+
],
|
|
797
|
+
stateMutability: "view"
|
|
798
|
+
}],
|
|
799
|
+
functionName: "cachedPrice"
|
|
800
|
+
});
|
|
801
|
+
return { price: result[0], updatedAt: result[1] };
|
|
802
|
+
}
|
|
803
|
+
static async getTokenPrice(publicClient, address, token) {
|
|
804
|
+
return publicClient.readContract({
|
|
805
|
+
address,
|
|
806
|
+
abi: [{
|
|
807
|
+
name: "tokenPrices",
|
|
808
|
+
type: "function",
|
|
809
|
+
inputs: [{ name: "token", type: "address" }],
|
|
810
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
811
|
+
stateMutability: "view"
|
|
812
|
+
}],
|
|
813
|
+
functionName: "tokenPrices",
|
|
814
|
+
args: [token]
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
static async getDepositedBalance(publicClient, address, user, token) {
|
|
818
|
+
return publicClient.readContract({
|
|
819
|
+
address,
|
|
820
|
+
abi: [{
|
|
821
|
+
name: "balances",
|
|
822
|
+
type: "function",
|
|
823
|
+
inputs: [
|
|
824
|
+
{ name: "user", type: "address" },
|
|
825
|
+
{ name: "token", type: "address" }
|
|
826
|
+
],
|
|
827
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
828
|
+
stateMutability: "view"
|
|
829
|
+
}],
|
|
830
|
+
functionName: "balances",
|
|
831
|
+
args: [user, token]
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
static async ensurePriceInitialized(wallet, publicClient, address) {
|
|
835
|
+
const { price } = await this.getCachedPrice(publicClient, address);
|
|
836
|
+
if (price === 0n) {
|
|
837
|
+
await this.updatePrice(wallet, address);
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
return false;
|
|
841
|
+
}
|
|
842
|
+
static async addStake(wallet, address, amount, unstakeDelaySec) {
|
|
843
|
+
return wallet.writeContract({
|
|
844
|
+
address,
|
|
845
|
+
abi: viem.parseAbi(["function addStake(uint32 unstakeDelaySec) external payable"]),
|
|
846
|
+
functionName: "addStake",
|
|
847
|
+
args: [unstakeDelaySec],
|
|
848
|
+
value: amount,
|
|
849
|
+
chain: wallet.chain
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
static async addDeposit(wallet, address, amount) {
|
|
853
|
+
return wallet.writeContract({
|
|
854
|
+
address,
|
|
855
|
+
abi: viem.parseAbi(["function addDeposit() external payable"]),
|
|
856
|
+
functionName: "addDeposit",
|
|
857
|
+
value: amount,
|
|
858
|
+
chain: wallet.chain
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
static async addGasToken(wallet, address, token) {
|
|
862
|
+
return wallet.writeContract({
|
|
863
|
+
address,
|
|
864
|
+
abi: ["function addGasToken(address token)"],
|
|
865
|
+
functionName: "addGasToken",
|
|
866
|
+
args: [token],
|
|
867
|
+
chain: wallet.chain
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
static async removeGasToken(wallet, address, token) {
|
|
871
|
+
return wallet.writeContract({
|
|
872
|
+
address,
|
|
873
|
+
abi: ["function removeGasToken(address token)"],
|
|
874
|
+
functionName: "removeGasToken",
|
|
875
|
+
args: [token],
|
|
876
|
+
chain: wallet.chain
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
static async setServiceFeeRate(wallet, address, rate) {
|
|
880
|
+
return wallet.writeContract({
|
|
881
|
+
address,
|
|
882
|
+
abi: ["function setServiceFeeRate(uint256 rate)"],
|
|
883
|
+
functionName: "setServiceFeeRate",
|
|
884
|
+
args: [rate],
|
|
885
|
+
chain: wallet.chain
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
static async setMaxGasCostCap(wallet, address, cap) {
|
|
889
|
+
return wallet.writeContract({
|
|
890
|
+
address,
|
|
891
|
+
abi: ["function setMaxGasCostCap(uint256 cap)"],
|
|
892
|
+
functionName: "setMaxGasCostCap",
|
|
893
|
+
args: [cap],
|
|
894
|
+
chain: wallet.chain
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
static async withdrawPNT(wallet, address, to, token, amount) {
|
|
898
|
+
return wallet.writeContract({
|
|
899
|
+
address,
|
|
900
|
+
abi: ["function withdrawPNT(address to, address token, uint256 amount)"],
|
|
901
|
+
functionName: "withdrawPNT",
|
|
902
|
+
args: [to, token, amount],
|
|
903
|
+
chain: wallet.chain
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
// --- Diagnostics & Automation ---
|
|
907
|
+
static async checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, user, token) {
|
|
908
|
+
const issues = [];
|
|
909
|
+
const depositInfo = await publicClient.readContract({
|
|
910
|
+
address: entryPoint,
|
|
911
|
+
abi: viem.parseAbi(["function getDepositInfo(address account) external view returns (uint256 deposit, bool staked, uint256 stake, uint32 unstakeDelaySec, uint48 withdrawTime)"]),
|
|
912
|
+
functionName: "getDepositInfo",
|
|
913
|
+
args: [paymasterAddress]
|
|
914
|
+
});
|
|
915
|
+
if (depositInfo[2] < 50000000000000000n) issues.push("Paymaster stake in EntryPoint is less than 0.05 ETH");
|
|
916
|
+
if (depositInfo[3] < 86400) issues.push("Paymaster unstake delay is less than 1 day");
|
|
917
|
+
if (depositInfo[0] < 100000000000000000n) issues.push("Paymaster deposit in EntryPoint is less than 0.1 ETH");
|
|
918
|
+
const ethPrice = await publicClient.readContract({
|
|
919
|
+
address: paymasterAddress,
|
|
920
|
+
abi: viem.parseAbi(["function cachedPrice() external view returns (uint208 price, uint48 updatedAt)"]),
|
|
921
|
+
functionName: "cachedPrice"
|
|
922
|
+
}).catch(() => [0n, 0n]);
|
|
923
|
+
if (ethPrice[0] === 0n) issues.push("Paymaster ETH/USD price not initialized");
|
|
924
|
+
const [tokenPrice, userTokenBal, userPMDeposit] = await Promise.all([
|
|
925
|
+
this.getTokenPrice(publicClient, paymasterAddress, token),
|
|
926
|
+
publicClient.readContract({
|
|
927
|
+
address: token,
|
|
928
|
+
abi: viem.parseAbi(["function balanceOf(address account) external view returns (uint256)"]),
|
|
929
|
+
functionName: "balanceOf",
|
|
930
|
+
args: [user]
|
|
931
|
+
}),
|
|
932
|
+
this.getDepositedBalance(publicClient, paymasterAddress, user, token)
|
|
933
|
+
]);
|
|
934
|
+
if (tokenPrice === 0n) issues.push("Token price not set in Paymaster");
|
|
935
|
+
if (userPMDeposit === 0n) issues.push("User has no deposit in Paymaster");
|
|
936
|
+
return {
|
|
937
|
+
isReady: issues.length === 0,
|
|
938
|
+
issues,
|
|
939
|
+
details: {
|
|
940
|
+
paymasterStake: depositInfo[2],
|
|
941
|
+
paymasterDeposit: depositInfo[0],
|
|
942
|
+
ethUsdPrice: ethPrice.price,
|
|
943
|
+
tokenSupported: true,
|
|
944
|
+
tokenPrice,
|
|
945
|
+
userTokenBalance: userTokenBal,
|
|
946
|
+
userPaymasterDeposit: userPMDeposit
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
static async prepareGaslessEnvironment(operatorWallet, publicClient, entryPoint, paymasterAddress, token, options = {}) {
|
|
951
|
+
const report = await this.checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, operatorWallet.account.address, token);
|
|
952
|
+
const results = [];
|
|
953
|
+
if (report.details.paymasterStake < (options.minStake || 50000000000000000n)) {
|
|
954
|
+
const hash = await this.addStake(operatorWallet, paymasterAddress, options.minStake || 50000000000000000n, 86400);
|
|
955
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
956
|
+
results.push({ step: "Stake", hash, status: "Confirmed" });
|
|
957
|
+
}
|
|
958
|
+
if (report.details.paymasterDeposit < (options.minDeposit || 100000000000000000n)) {
|
|
959
|
+
const hash = await this.addDeposit(operatorWallet, paymasterAddress, options.minDeposit || 300000000000000000n);
|
|
960
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
961
|
+
results.push({ step: "Deposit", hash, status: "Confirmed" });
|
|
962
|
+
}
|
|
963
|
+
if (report.details.ethUsdPrice === 0n) {
|
|
964
|
+
const hash = await this.updatePrice(operatorWallet, paymasterAddress);
|
|
965
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
966
|
+
results.push({ step: "OraclePrice", hash, status: "Confirmed" });
|
|
967
|
+
}
|
|
968
|
+
if (report.details.tokenPrice === 0n) {
|
|
969
|
+
try {
|
|
970
|
+
const hash = await this.addGasToken(operatorWallet, paymasterAddress, token);
|
|
971
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
972
|
+
results.push({ step: "AddGasToken", hash, status: "Confirmed" });
|
|
973
|
+
} catch (e) {
|
|
974
|
+
}
|
|
975
|
+
if (options.tokenPriceUSD) {
|
|
976
|
+
const hash = await this.setTokenPrice(operatorWallet, paymasterAddress, token, options.tokenPriceUSD);
|
|
977
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
978
|
+
results.push({ step: "TokenPrice", hash, status: "Confirmed" });
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return results;
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
var SuperPaymasterClient = class {
|
|
985
|
+
/**
|
|
986
|
+
* @private
|
|
987
|
+
* Static utility class, should not be instantiated.
|
|
988
|
+
*/
|
|
989
|
+
constructor() {
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Submit a gasless transaction using SuperPaymaster.
|
|
993
|
+
* Automatically handles gas estimation with a smart efficiency buffer.
|
|
994
|
+
*/
|
|
995
|
+
static async submitGaslessTransaction(client, wallet, aaAddress, entryPoint, bundlerUrl, config) {
|
|
996
|
+
const callData = viem.encodeFunctionData({
|
|
997
|
+
abi: viem.parseAbi(["function execute(address dest, uint256 value, bytes func) external"]),
|
|
998
|
+
functionName: "execute",
|
|
999
|
+
args: [
|
|
1000
|
+
config.token,
|
|
1001
|
+
0n,
|
|
1002
|
+
viem.encodeFunctionData({
|
|
1003
|
+
abi: viem.parseAbi(["function transfer(address to, uint256 amount) external returns (bool)"]),
|
|
1004
|
+
functionName: "transfer",
|
|
1005
|
+
args: [config.recipient, config.amount]
|
|
1006
|
+
})
|
|
1007
|
+
]
|
|
1008
|
+
});
|
|
1009
|
+
console.log(`[SuperPaymasterClient] \u{1F3AF} Target Info:`);
|
|
1010
|
+
console.log(` - Paymaster: ${config.paymasterAddress}`);
|
|
1011
|
+
console.log(` - Token: ${config.token}`);
|
|
1012
|
+
console.log(` - Operator: ${config.operator}`);
|
|
1013
|
+
console.log("[SuperPaymasterClient] \u2601\uFE0F Estimating Gas usage...");
|
|
1014
|
+
const est = await PaymasterClient.estimateUserOperationGas(
|
|
1015
|
+
client,
|
|
1016
|
+
wallet,
|
|
1017
|
+
aaAddress,
|
|
1018
|
+
entryPoint,
|
|
1019
|
+
config.paymasterAddress,
|
|
1020
|
+
config.token,
|
|
1021
|
+
bundlerUrl,
|
|
1022
|
+
callData,
|
|
1023
|
+
{
|
|
1024
|
+
operator: config.operator,
|
|
1025
|
+
factory: config.factory,
|
|
1026
|
+
factoryData: config.factoryData
|
|
1027
|
+
}
|
|
1028
|
+
);
|
|
1029
|
+
console.log("[SuperPaymasterClient] \u2601\uFE0F Bundler Estimates:", est);
|
|
1030
|
+
const tunedVGL = tuneGasLimit(est.verificationGasLimit, 35000n, 0.45);
|
|
1031
|
+
const bundlerEstimateVGL = est.paymasterVerificationGasLimit || 100000n;
|
|
1032
|
+
const tunedPMVerificationGas = tuneGasLimit(bundlerEstimateVGL, 60000n, 0.45);
|
|
1033
|
+
const _postOpBase = est.paymasterPostOpGasLimit + 100000n;
|
|
1034
|
+
const tunedPostOp = _postOpBase > 200000n ? _postOpBase : 200000n;
|
|
1035
|
+
console.log(`[SuperPaymasterClient] \u{1F527} Tuned Limits: VGL=${tunedVGL}, PMVGL=${tunedPMVerificationGas}, PostOp=${tunedPostOp}`);
|
|
1036
|
+
return PaymasterClient.submitGaslessUserOperation(
|
|
1037
|
+
client,
|
|
1038
|
+
wallet,
|
|
1039
|
+
aaAddress,
|
|
1040
|
+
entryPoint,
|
|
1041
|
+
config.paymasterAddress,
|
|
1042
|
+
config.token,
|
|
1043
|
+
bundlerUrl,
|
|
1044
|
+
callData,
|
|
1045
|
+
{
|
|
1046
|
+
operator: config.operator,
|
|
1047
|
+
verificationGasLimit: tunedVGL,
|
|
1048
|
+
callGasLimit: est.callGasLimit,
|
|
1049
|
+
preVerificationGas: est.preVerificationGas,
|
|
1050
|
+
paymasterVerificationGasLimit: tunedPMVerificationGas,
|
|
1051
|
+
// EXPLICIT PM LIMIT
|
|
1052
|
+
paymasterPostOpGasLimit: tunedPostOp,
|
|
1053
|
+
autoEstimate: false,
|
|
1054
|
+
// We did it ourselves
|
|
1055
|
+
factory: config.factory,
|
|
1056
|
+
factoryData: config.factoryData
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
// ../paymaster/src/PaymasterManager.ts
|
|
1063
|
+
var PaymasterManager = class _PaymasterManager {
|
|
1064
|
+
knownPaymasters;
|
|
1065
|
+
constructor(opts) {
|
|
1066
|
+
this.knownPaymasters = /* @__PURE__ */ new Map();
|
|
1067
|
+
if (opts?.knownPaymasters) {
|
|
1068
|
+
for (const [address, type] of Object.entries(opts.knownPaymasters)) {
|
|
1069
|
+
this.setKnownPaymaster(address, type);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Register a known paymaster address → type mapping so that callers can
|
|
1075
|
+
* omit the explicit `type` and have it resolved from the address.
|
|
1076
|
+
*/
|
|
1077
|
+
registerPaymaster(address, type) {
|
|
1078
|
+
this.setKnownPaymaster(address, type);
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Record an address → type mapping, throwing on a CONFLICTING re-registration.
|
|
1082
|
+
* Silently overwriting a v4 address with `super` (or vice-versa) would later
|
|
1083
|
+
* pack the wrong-length paymasterData for a `type`-less call, so a conflicting
|
|
1084
|
+
* re-registration is treated as a programmer error. Re-registering the SAME
|
|
1085
|
+
* type (including a case-variant of the address) is an idempotent no-op.
|
|
1086
|
+
*/
|
|
1087
|
+
setKnownPaymaster(address, type) {
|
|
1088
|
+
const normalized = address.toLowerCase();
|
|
1089
|
+
const existing = this.knownPaymasters.get(normalized);
|
|
1090
|
+
if (existing && existing !== type) {
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
`Paymaster ${address} is already registered as '${existing}'; refusing to re-register as '${type}'`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
this.knownPaymasters.set(normalized, type);
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Resolve a paymaster's type from a registered address. Returns undefined
|
|
1099
|
+
* if the address is not registered.
|
|
1100
|
+
*/
|
|
1101
|
+
resolveType(address) {
|
|
1102
|
+
return this.knownPaymasters.get(address.toLowerCase());
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Build `paymasterAndData`, auto-selecting the correct byte layout for the
|
|
1106
|
+
* paymaster type. Dispatches to the existing per-type packers.
|
|
1107
|
+
*/
|
|
1108
|
+
buildPaymasterData(params) {
|
|
1109
|
+
const type = params.type ?? this.resolveType(params.paymasterAddress);
|
|
1110
|
+
if (!type) {
|
|
1111
|
+
throw new Error(
|
|
1112
|
+
`PaymasterManager: cannot resolve paymaster type for ${params.paymasterAddress}. Pass an explicit \`type\` ('v4' | 'super') or register the address via registerPaymaster().`
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
return _PaymasterManager.dispatch(type, params);
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Static helper: build `paymasterAndData` for an explicit type without an
|
|
1119
|
+
* instance. Useful when the caller already knows the type.
|
|
1120
|
+
*/
|
|
1121
|
+
static buildPaymasterData(type, params) {
|
|
1122
|
+
return _PaymasterManager.dispatch(type, params);
|
|
1123
|
+
}
|
|
1124
|
+
static dispatch(type, params) {
|
|
1125
|
+
switch (type) {
|
|
1126
|
+
case "v4": {
|
|
1127
|
+
if (!params.token) {
|
|
1128
|
+
throw new Error("PaymasterManager: type 'v4' requires `token`.");
|
|
1129
|
+
}
|
|
1130
|
+
return buildPaymasterData(params.paymasterAddress, params.token, {
|
|
1131
|
+
validityWindow: params.validityWindow,
|
|
1132
|
+
verificationGasLimit: params.verificationGasLimit,
|
|
1133
|
+
postOpGasLimit: params.postOpGasLimit
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
case "super": {
|
|
1137
|
+
if (!params.operator) {
|
|
1138
|
+
throw new Error("PaymasterManager: type 'super' requires `operator`.");
|
|
1139
|
+
}
|
|
1140
|
+
return buildSuperPaymasterData(params.paymasterAddress, params.operator, {
|
|
1141
|
+
verificationGasLimit: params.verificationGasLimit,
|
|
1142
|
+
postOpGasLimit: params.postOpGasLimit,
|
|
1143
|
+
maxRate: params.maxRate
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
default: {
|
|
1147
|
+
const _never = type;
|
|
1148
|
+
throw new Error(`PaymasterManager: unsupported paymaster type '${_never}'.`);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
exports.PaymasterClient = PaymasterClient;
|
|
1155
|
+
exports.PaymasterManager = PaymasterManager;
|
|
1156
|
+
exports.PaymasterOperator = PaymasterOperator;
|
|
1157
|
+
exports.SuperPaymasterAdminClient = SuperPaymasterAdminClient;
|
|
1158
|
+
exports.SuperPaymasterClient = SuperPaymasterClient;
|
|
1159
|
+
exports.buildPaymasterData = buildPaymasterData;
|
|
1160
|
+
exports.buildSuperPaymasterData = buildSuperPaymasterData;
|
|
1161
|
+
exports.checkEligibility = checkEligibility;
|
|
1162
|
+
exports.formatUserOpV07 = formatUserOpV07;
|
|
1163
|
+
exports.getPaymasterV4Middleware = getPaymasterV4Middleware;
|
|
1164
|
+
exports.getSuperPaymasterMiddleware = getSuperPaymasterMiddleware;
|
|
1165
|
+
exports.getUserOpHashV07 = getUserOpHashV07;
|
|
1166
|
+
exports.tuneGasLimit = tuneGasLimit;
|
|
1167
|
+
//# sourceMappingURL=chunk-2RCJBWPO.cjs.map
|
|
1168
|
+
//# sourceMappingURL=chunk-2RCJBWPO.cjs.map
|