abstractionkit 0.3.7 → 0.3.8
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/CHANGELOG.md +454 -0
- package/dist/index.cjs +1815 -1008
- package/dist/index.d.cts +234 -130
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +234 -130
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +1815 -1008
- package/dist/index.mjs +1811 -1006
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/dist/index.iife.js
CHANGED
|
@@ -30,6 +30,16 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
30
30
|
"-32521": "EXECUTION_REVERTED"
|
|
31
31
|
};
|
|
32
32
|
/**
|
|
33
|
+
* Maps JSON-RPC numeric error codes to human-readable {@link JsonRpcErrorCode} values.
|
|
34
|
+
*/
|
|
35
|
+
const JsonRpcErrorDict = {
|
|
36
|
+
"-32700": "PARSE_ERROR",
|
|
37
|
+
"-32600": "INVALID_REQUEST",
|
|
38
|
+
"-32601": "METHOD_NOT_FOUND",
|
|
39
|
+
"-32602": "INVALID_PARAMS",
|
|
40
|
+
"-32603": "INTERNAL_ERROR"
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
33
43
|
* Custom error class for the AbstractionKit SDK. Wraps bundler, JSON-RPC,
|
|
34
44
|
* and general errors with a structured code, optional numeric errno, and
|
|
35
45
|
* arbitrary JSON-serializable context.
|
|
@@ -84,164 +94,164 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
84
94
|
return /* @__PURE__ */ new Error(`This value was thrown as is, not through an Error: ${stringified}`);
|
|
85
95
|
}
|
|
86
96
|
//#endregion
|
|
87
|
-
//#region src/
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
//#region src/transport/Transport.ts
|
|
98
|
+
/**
|
|
99
|
+
* Default {@link ProviderRpcError} implementation. {@link BaseRpcTransport}
|
|
100
|
+
* throws this automatically when a JSON-RPC envelope returns
|
|
101
|
+
* `{ error: { code, message, data } }`.
|
|
102
|
+
*/
|
|
103
|
+
var TransportRpcError = class extends Error {
|
|
104
|
+
code;
|
|
105
|
+
data;
|
|
106
|
+
/**
|
|
107
|
+
* @param code - Numeric JSON-RPC error code (e.g. -32601 for METHOD_NOT_FOUND)
|
|
108
|
+
* @param message - Human-readable error description
|
|
109
|
+
* @param data - Optional additional data returned by the RPC server
|
|
110
|
+
*/
|
|
111
|
+
constructor(code, message, data) {
|
|
112
|
+
super(message);
|
|
113
|
+
this.name = "TransportRpcError";
|
|
114
|
+
this.code = code;
|
|
115
|
+
this.data = data;
|
|
116
|
+
}
|
|
107
117
|
};
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Narrowing helper for {@link EventfulTransport}.
|
|
120
|
+
*
|
|
121
|
+
* @param transport - Any transport to test
|
|
122
|
+
* @returns `true` when both `on` and `removeListener` methods are present
|
|
123
|
+
*/
|
|
124
|
+
function isEventfulTransport(transport) {
|
|
125
|
+
const t = transport;
|
|
126
|
+
return typeof t.on === "function" && typeof t.removeListener === "function";
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/transport/BaseRpcTransport.ts
|
|
130
|
+
/**
|
|
131
|
+
* Optional convenience base class for users writing new wire-level
|
|
132
|
+
* {@link Transport} backends (WebSocket, IPC, custom HTTP, in-process mock,
|
|
133
|
+
* etc.). Handles JSON-RPC framing, id assignment, bigint serialization, and
|
|
134
|
+
* standard error parsing so subclasses implement only the byte-level
|
|
135
|
+
* `send(envelope, options)` hook.
|
|
136
|
+
*
|
|
137
|
+
* Users who already have a {@link Transport} in hand (window.ethereum, viem
|
|
138
|
+
* `WalletClient`, ethers `Eip1193Provider`-shaped object, etc.) do NOT need
|
|
139
|
+
* this class — they pass their object directly.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* class WebSocketTransport extends BaseRpcTransport {
|
|
144
|
+
* protected async send(envelope) {
|
|
145
|
+
* // serialize envelope to JSON, send over the socket, await response
|
|
146
|
+
* return JSON.parse(await this.socket.sendAndAwait(JSON.stringify(envelope)));
|
|
147
|
+
* }
|
|
148
|
+
* }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
var BaseRpcTransport = class BaseRpcTransport {
|
|
152
|
+
nextId = 1;
|
|
153
|
+
/**
|
|
154
|
+
* Build a JSON-RPC envelope, delegate the wire I/O to the subclass's
|
|
155
|
+
* {@link BaseRpcTransport.send} method, and parse the response.
|
|
156
|
+
*
|
|
157
|
+
* @throws {@link TransportRpcError} when the response contains an `error` field
|
|
158
|
+
* @throws {@link TransportRpcError} (code -32603) when the response is malformed
|
|
159
|
+
*/
|
|
160
|
+
async request(args, options) {
|
|
161
|
+
const envelope = {
|
|
162
|
+
jsonrpc: "2.0",
|
|
163
|
+
id: this.nextId++,
|
|
164
|
+
method: args.method,
|
|
165
|
+
params: args.params
|
|
166
|
+
};
|
|
167
|
+
const raw = await this.send(envelope, options);
|
|
168
|
+
return BaseRpcTransport.parseResponse(raw);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Serialize a JSON-RPC envelope to a string, converting bigint values to
|
|
172
|
+
* `0x`-prefixed hex strings (preserving the historical SDK behavior).
|
|
173
|
+
*/
|
|
174
|
+
static serializeEnvelope(envelope) {
|
|
175
|
+
return JSON.stringify(envelope, (_key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Parse a decoded JSON-RPC response. Returns the `result` field on success
|
|
179
|
+
* or throws a {@link TransportRpcError} on error / malformed response.
|
|
180
|
+
*/
|
|
181
|
+
static parseResponse(raw) {
|
|
182
|
+
if (raw == null || typeof raw !== "object") throw new TransportRpcError(-32603, "malformed JSON-RPC response", raw);
|
|
183
|
+
const response = raw;
|
|
184
|
+
if ("error" in response) {
|
|
185
|
+
const { code, message, data } = response.error;
|
|
186
|
+
throw new TransportRpcError(code, message, data);
|
|
187
|
+
}
|
|
188
|
+
if ("result" in response) return response.result;
|
|
189
|
+
throw new TransportRpcError(-32603, "malformed JSON-RPC response", raw);
|
|
190
|
+
}
|
|
119
191
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
type: "uint256",
|
|
154
|
-
name: "maxFeePerGas"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
type: "uint256",
|
|
158
|
-
name: "maxPriorityFeePerGas"
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
type: "bytes",
|
|
162
|
-
name: "paymasterAndData"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: "uint48",
|
|
166
|
-
name: "validAfter"
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
type: "uint48",
|
|
170
|
-
name: "validUntil"
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
type: "address",
|
|
174
|
-
name: "entryPoint"
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/transport/HttpTransport.ts
|
|
194
|
+
/**
|
|
195
|
+
* Default concrete {@link Transport}: POSTs JSON-RPC envelopes to an HTTP
|
|
196
|
+
* endpoint. Used by every URL-string call site once a string is normalized
|
|
197
|
+
* into a transport.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const t = new HttpTransport("https://api.candide.dev/public/v3/11155111");
|
|
202
|
+
* const chainId = await t.request<string>({ method: "eth_chainId" });
|
|
203
|
+
*
|
|
204
|
+
* // With auth headers and a custom fetch:
|
|
205
|
+
* const t2 = new HttpTransport("https://...", {
|
|
206
|
+
* headers: { Authorization: `Bearer ${token}` },
|
|
207
|
+
* fetch: myFetchWithRetry,
|
|
208
|
+
* });
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
var HttpTransport = class HttpTransport extends BaseRpcTransport {
|
|
212
|
+
/** Endpoint URL this transport POSTs to. */
|
|
213
|
+
url;
|
|
214
|
+
/** Options passed at construction time. */
|
|
215
|
+
options;
|
|
216
|
+
/**
|
|
217
|
+
* @param url - JSON-RPC endpoint URL (bundler, paymaster, or node)
|
|
218
|
+
* @param options - Optional fetch override and static headers
|
|
219
|
+
*/
|
|
220
|
+
constructor(url, options = {}) {
|
|
221
|
+
super();
|
|
222
|
+
this.url = url;
|
|
223
|
+
this.options = options;
|
|
175
224
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
name: "initCode"
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
type: "bytes",
|
|
193
|
-
name: "callData"
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
type: "uint128",
|
|
197
|
-
name: "verificationGasLimit"
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
type: "uint128",
|
|
201
|
-
name: "callGasLimit"
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
type: "uint256",
|
|
205
|
-
name: "preVerificationGas"
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
type: "uint128",
|
|
209
|
-
name: "maxPriorityFeePerGas"
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
type: "uint128",
|
|
213
|
-
name: "maxFeePerGas"
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
type: "bytes",
|
|
217
|
-
name: "paymasterAndData"
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
type: "uint48",
|
|
221
|
-
name: "validAfter"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
type: "uint48",
|
|
225
|
-
name: "validUntil"
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
type: "address",
|
|
229
|
-
name: "entryPoint"
|
|
225
|
+
async send(envelope, options) {
|
|
226
|
+
const headers = {
|
|
227
|
+
...this.options.headers ?? {},
|
|
228
|
+
"Content-Type": "application/json"
|
|
229
|
+
};
|
|
230
|
+
const body = HttpTransport.serializeEnvelope(envelope);
|
|
231
|
+
return await (await (this.options.fetch ?? globalThis.fetch)(this.url, {
|
|
232
|
+
method: "POST",
|
|
233
|
+
headers,
|
|
234
|
+
body,
|
|
235
|
+
redirect: "follow",
|
|
236
|
+
signal: options?.signal
|
|
237
|
+
})).json();
|
|
230
238
|
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Narrowing helper for {@link HttpTransport}. Useful for code that wants to
|
|
242
|
+
* read the underlying URL — e.g. when serializing a configured Bundler for
|
|
243
|
+
* logging or diagnostics.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```ts
|
|
247
|
+
* if (isHttpTransport(bundler.transport)) {
|
|
248
|
+
* console.log("Bundler URL:", bundler.transport.url);
|
|
249
|
+
* }
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
function isHttpTransport(transport) {
|
|
253
|
+
return transport instanceof HttpTransport;
|
|
254
|
+
}
|
|
245
255
|
//#endregion
|
|
246
256
|
//#region src/types.ts
|
|
247
257
|
/**
|
|
@@ -275,560 +285,456 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
275
285
|
return PolygonChain;
|
|
276
286
|
}({});
|
|
277
287
|
//#endregion
|
|
278
|
-
//#region src/
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
//#region src/transport/normalize.ts
|
|
289
|
+
/**
|
|
290
|
+
* Recursively convert any `bigint` values inside an RPC param to `0x`-prefixed
|
|
291
|
+
* hex strings, descending into arrays and plain objects. Other values pass
|
|
292
|
+
* through unchanged.
|
|
293
|
+
*
|
|
294
|
+
* Required for user-supplied {@link Transport} implementations that don't go
|
|
295
|
+
* through {@link BaseRpcTransport.serializeEnvelope} (EIP-1193 providers, viem
|
|
296
|
+
* clients, etc.) and would otherwise see raw `bigint`s in `params`. Mirrors the
|
|
297
|
+
* normalization done in {@link sendJsonRpcRequest}.
|
|
298
|
+
*
|
|
299
|
+
* @internal
|
|
300
|
+
*/
|
|
301
|
+
function normalizeRpcValue(value) {
|
|
302
|
+
if (typeof value === "bigint") return `0x${value.toString(16)}`;
|
|
303
|
+
if (Array.isArray(value)) return value.map(normalizeRpcValue);
|
|
304
|
+
if (value !== null && typeof value === "object") {
|
|
305
|
+
const out = {};
|
|
306
|
+
for (const [k, v] of Object.entries(value)) out[k] = normalizeRpcValue(v);
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
return value;
|
|
287
310
|
}
|
|
288
311
|
/**
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
312
|
+
* Wrap a {@link Transport} so every outbound `request` has its `params`
|
|
313
|
+
* normalized (bigints → 0x-hex) before delegation. Idempotent: wrapping an
|
|
314
|
+
* already-normalizing transport is harmless because the second pass sees only
|
|
315
|
+
* strings.
|
|
292
316
|
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
317
|
+
* Applied once at each service boundary (Bundler, CandidePaymaster,
|
|
318
|
+
* Erc7677Paymaster, JsonRpcNode, …) so normalization is impossible to forget
|
|
319
|
+
* per-method. Required for user-supplied transports (EIP-1193 providers, viem
|
|
320
|
+
* clients, etc.) that don't route through {@link BaseRpcTransport.serializeEnvelope}.
|
|
321
|
+
*
|
|
322
|
+
* @internal
|
|
297
323
|
*/
|
|
298
|
-
function
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"address",
|
|
307
|
-
"uint256"
|
|
308
|
-
], [
|
|
309
|
-
packedUserOperationHash,
|
|
310
|
-
entrypointAddress,
|
|
311
|
-
chainId
|
|
312
|
-
]));
|
|
313
|
-
} else if (entrypointAddress.toLowerCase() === "0x0000000071727De22E5E9d8BAf0edAc6f37da032".toLowerCase()) {
|
|
314
|
-
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV7(useroperation));
|
|
315
|
-
userOperationHash = (0, ethers.keccak256)(abiCoder.encode([
|
|
316
|
-
"bytes32",
|
|
317
|
-
"address",
|
|
318
|
-
"uint256"
|
|
319
|
-
], [
|
|
320
|
-
packedUserOperationHash,
|
|
321
|
-
entrypointAddress,
|
|
322
|
-
chainId
|
|
323
|
-
]));
|
|
324
|
-
} else if (entrypointAddress.toLowerCase() === "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108".toLowerCase()) {
|
|
325
|
-
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV8(useroperation));
|
|
326
|
-
userOperationHash = (0, ethers.keccak256)(`0x1901${buildDomainSeparator(chainId, entrypointAddress).slice(2)}${packedUserOperationHash.slice(2)}`);
|
|
327
|
-
} else if (entrypointAddress.toLowerCase() === "0x433709009B8330FDa32311DF1C2AFA402eD8D009".toLowerCase()) {
|
|
328
|
-
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV9(useroperation));
|
|
329
|
-
userOperationHash = (0, ethers.keccak256)(`0x1901${buildDomainSeparator(chainId, entrypointAddress).slice(2)}${packedUserOperationHash.slice(2)}`);
|
|
330
|
-
} else throw new RangeError(`unsupported entrypoint address: ${entrypointAddress}`);
|
|
331
|
-
return userOperationHash;
|
|
324
|
+
function normalizingTransport(inner) {
|
|
325
|
+
return { request(args, options) {
|
|
326
|
+
const params = args.params == null ? args.params : normalizeRpcValue(args.params);
|
|
327
|
+
return inner.request({
|
|
328
|
+
method: args.method,
|
|
329
|
+
params
|
|
330
|
+
}, options);
|
|
331
|
+
} };
|
|
332
332
|
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/transport/JsonRpcNode.ts
|
|
335
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
333
336
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
337
|
+
* High-level service class for the JSON-RPC node methods abstractionkit reads
|
|
338
|
+
* from. Intentionally NOT a general Ethereum client — only exposes the
|
|
339
|
+
* methods the SDK actually uses. For broader functionality, drop down to
|
|
340
|
+
* `.transport` and call `request({ method, params })` directly, or use a
|
|
341
|
+
* dedicated library like viem / ethers.
|
|
339
342
|
*
|
|
340
|
-
*
|
|
341
|
-
* {@link
|
|
342
|
-
*
|
|
343
|
-
* use within the package and not re-exported from `src/abstractionkit.ts`.
|
|
343
|
+
* Like {@link Bundler} and the paymaster classes, `JsonRpcNode` itself
|
|
344
|
+
* implements {@link Transport} so it can be passed back into any Transport
|
|
345
|
+
* position.
|
|
344
346
|
*
|
|
345
|
-
* @
|
|
346
|
-
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* const node = new JsonRpcNode("https://ethereum-sepolia.publicnode.com");
|
|
350
|
+
* const id = await node.chainId();
|
|
351
|
+
* const code = await node.getCode("0x...");
|
|
352
|
+
*
|
|
353
|
+
* // Also a Transport — can be slotted in:
|
|
354
|
+
* const bundler = new Bundler(node); // bundler will speak through this node
|
|
355
|
+
* ```
|
|
347
356
|
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
357
|
+
var JsonRpcNode = class JsonRpcNode {
|
|
358
|
+
/**
|
|
359
|
+
* The raw transport the user passed in (or {@link HttpTransport} when a URL
|
|
360
|
+
* string was passed). Exposed for introspection — reading `.url`,
|
|
361
|
+
* `isHttpTransport(...)` checks, passing it back into another service.
|
|
362
|
+
*
|
|
363
|
+
* Calls made directly on this field (`node.transport.request(...)`) go
|
|
364
|
+
* to the raw transport and skip SDK-level behavior like bigint param
|
|
365
|
+
* normalization. For SDK-pipeline behavior, use {@link JsonRpcNode.request}
|
|
366
|
+
* or the typed methods.
|
|
367
|
+
*/
|
|
368
|
+
transport;
|
|
369
|
+
/** Normalizing wrapper around {@link transport}, used for every SDK-outbound call. */
|
|
370
|
+
outbound;
|
|
371
|
+
/**
|
|
372
|
+
* @param rpc - Node JSON-RPC endpoint URL, or any {@link Transport}
|
|
373
|
+
*/
|
|
374
|
+
constructor(rpc) {
|
|
375
|
+
this.transport = typeof rpc === "string" ? new HttpTransport(rpc) : rpc;
|
|
376
|
+
this.outbound = normalizingTransport(this.transport);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Normalize any acceptable input into a {@link JsonRpcNode}. Used at every
|
|
380
|
+
* public-API widening site (in account / paymaster classes). When the
|
|
381
|
+
* input is already a `JsonRpcNode`, the same instance is returned by
|
|
382
|
+
* reference, so a user's preconstructed `JsonRpcNode` is never re-wrapped.
|
|
383
|
+
*
|
|
384
|
+
* @param input - URL string, Transport, or existing JsonRpcNode
|
|
385
|
+
*/
|
|
386
|
+
static from(input) {
|
|
387
|
+
return input instanceof JsonRpcNode ? input : new JsonRpcNode(input);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Transport delegate. Routes through the normalizing wrapper so `bigint`
|
|
391
|
+
* values in `params` are converted to `0x`-hex before reaching
|
|
392
|
+
* user-supplied transports that don't go through
|
|
393
|
+
* {@link BaseRpcTransport.serializeEnvelope}. Lets a `JsonRpcNode` itself
|
|
394
|
+
* slot into any other transport position.
|
|
395
|
+
*/
|
|
396
|
+
request(args, options) {
|
|
397
|
+
return this.outbound.request(args, options);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* `eth_chainId`. Returns the hex-encoded chain id (e.g. `"0xaa36a7"` for
|
|
401
|
+
* Sepolia).
|
|
402
|
+
*/
|
|
403
|
+
async chainId(options) {
|
|
404
|
+
try {
|
|
405
|
+
const result = await this.outbound.request({ method: "eth_chainId" }, options);
|
|
406
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_chainId returned ill formed data", { context: JSON.stringify(result) });
|
|
407
|
+
return result;
|
|
408
|
+
} catch (err) {
|
|
409
|
+
throw translateNodeError(err, "eth_chainId");
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* `eth_blockNumber`. Returns the latest block number as a bigint.
|
|
414
|
+
*/
|
|
415
|
+
async blockNumber(options) {
|
|
416
|
+
try {
|
|
417
|
+
const result = await this.outbound.request({ method: "eth_blockNumber" }, options);
|
|
418
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_blockNumber returned ill formed data", { context: JSON.stringify(result) });
|
|
419
|
+
return BigInt(result);
|
|
420
|
+
} catch (err) {
|
|
421
|
+
throw translateNodeError(err, "eth_blockNumber");
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* `eth_getCode`. Returns the deployed bytecode at `address` at the given
|
|
426
|
+
* block tag (default `"latest"`).
|
|
427
|
+
*/
|
|
428
|
+
async getCode(address, blockTag = "latest", options) {
|
|
429
|
+
try {
|
|
430
|
+
const result = await this.outbound.request({
|
|
431
|
+
method: "eth_getCode",
|
|
432
|
+
params: [address, blockTag]
|
|
433
|
+
}, options);
|
|
434
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_getCode returned ill formed data", { context: JSON.stringify(result) });
|
|
435
|
+
return result;
|
|
436
|
+
} catch (err) {
|
|
437
|
+
throw translateNodeError(err, "eth_getCode");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* `eth_call`. Executes a read-only call against `to` and returns the raw
|
|
442
|
+
* return data as a hex string. Supports state overrides via the optional
|
|
443
|
+
* third parameter.
|
|
444
|
+
*/
|
|
445
|
+
async call(tx, blockTag = "latest", stateOverrides, options) {
|
|
446
|
+
const params = stateOverrides == null ? [tx, blockTag] : [
|
|
447
|
+
tx,
|
|
448
|
+
blockTag,
|
|
449
|
+
stateOverrides
|
|
450
|
+
];
|
|
451
|
+
try {
|
|
452
|
+
const result = await this.outbound.request({
|
|
453
|
+
method: "eth_call",
|
|
454
|
+
params
|
|
455
|
+
}, options);
|
|
456
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_call returned ill formed data", { context: JSON.stringify(result) });
|
|
457
|
+
return result;
|
|
458
|
+
} catch (err) {
|
|
459
|
+
throw translateNodeError(err, "eth_call");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* `eth_getTransactionCount`. Returns the transaction count (account nonce
|
|
464
|
+
* at the EOA level — not the EntryPoint nonce; see
|
|
465
|
+
* {@link JsonRpcNode.getEntryPointNonce}) as a bigint.
|
|
466
|
+
*/
|
|
467
|
+
async getTransactionCount(address, blockTag = "latest", options) {
|
|
468
|
+
try {
|
|
469
|
+
const result = await this.outbound.request({
|
|
470
|
+
method: "eth_getTransactionCount",
|
|
471
|
+
params: [address, blockTag]
|
|
472
|
+
}, options);
|
|
473
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_getTransactionCount returned ill formed data", { context: JSON.stringify(result) });
|
|
474
|
+
return BigInt(result);
|
|
475
|
+
} catch (err) {
|
|
476
|
+
throw translateNodeError(err, "eth_getTransactionCount");
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Fetch current gas prices and apply a level multiplier.
|
|
481
|
+
*
|
|
482
|
+
* Tries `eth_maxPriorityFeePerGas` + `eth_gasPrice` first (EIP-1559),
|
|
483
|
+
* falling back to `eth_gasPrice` alone if the priority-fee method is
|
|
484
|
+
* unsupported, and finally to a 1 gwei floor multiplied by `gasLevel`.
|
|
485
|
+
*
|
|
486
|
+
* @param gasLevel - {@link GasOption} multiplier (default: Medium = 1.2x)
|
|
487
|
+
* @returns `[maxFeePerGas, maxPriorityFeePerGas]` as bigints
|
|
488
|
+
*/
|
|
489
|
+
async getFeeData(gasLevel = GasOption.Medium, options) {
|
|
490
|
+
try {
|
|
491
|
+
let gasPrice = null;
|
|
492
|
+
let maxPriorityFeePerGas = null;
|
|
493
|
+
try {
|
|
494
|
+
const result = await this.outbound.request({ method: "eth_gasPrice" }, options);
|
|
495
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_gasPrice returned ill formed data", { context: JSON.stringify(result) });
|
|
496
|
+
gasPrice = BigInt(result);
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (!isMethodNotSupportedError(err)) throw err;
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
const result = await this.outbound.request({ method: "eth_maxPriorityFeePerGas" }, options);
|
|
502
|
+
if (typeof result !== "string") throw new AbstractionKitError("BAD_DATA", "eth_maxPriorityFeePerGas returned ill formed data", { context: JSON.stringify(result) });
|
|
503
|
+
maxPriorityFeePerGas = BigInt(result);
|
|
504
|
+
} catch (err) {
|
|
505
|
+
if (!isMethodNotSupportedError(err)) throw err;
|
|
506
|
+
}
|
|
507
|
+
let maxFeePerGas;
|
|
508
|
+
let priorityFee;
|
|
509
|
+
if (gasPrice != null && maxPriorityFeePerGas != null) {
|
|
510
|
+
maxFeePerGas = scaleBigIntByGasLevel(gasPrice, gasLevel);
|
|
511
|
+
priorityFee = scaleBigIntByGasLevel(maxPriorityFeePerGas, gasLevel);
|
|
512
|
+
} else if (gasPrice != null) {
|
|
513
|
+
maxFeePerGas = scaleBigIntByGasLevel(gasPrice, gasLevel);
|
|
514
|
+
priorityFee = maxFeePerGas;
|
|
515
|
+
} else {
|
|
516
|
+
maxFeePerGas = scaleBigIntByGasLevel(1000000000n, gasLevel);
|
|
517
|
+
priorityFee = maxFeePerGas;
|
|
518
|
+
}
|
|
519
|
+
if (maxFeePerGas === 0n) maxFeePerGas = 1n;
|
|
520
|
+
if (priorityFee === 0n) priorityFee = 1n;
|
|
521
|
+
if (priorityFee > maxFeePerGas) maxFeePerGas = priorityFee;
|
|
522
|
+
return [maxFeePerGas, priorityFee];
|
|
523
|
+
} catch (err) {
|
|
524
|
+
throw translateNodeError(err, "getFeeData");
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Check whether an address is EIP-7702-delegated and return the delegatee
|
|
529
|
+
* address. EIP-7702-delegated accounts have bytecode of the form
|
|
530
|
+
* `0xef0100<20-byte-delegatee>` per the spec.
|
|
531
|
+
*
|
|
532
|
+
* @returns The checksummed delegatee address, or `null` if not delegated
|
|
533
|
+
*/
|
|
534
|
+
async getDelegatedAddress(accountAddress, options) {
|
|
535
|
+
const code = (await this.getCode(accountAddress, "latest", options)).toLowerCase();
|
|
536
|
+
if (code.length === 48 && code.startsWith("0xef0100")) return (0, ethers.getAddress)(`0x${code.slice(8)}`);
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Fetch the smart account's nonce from the EntryPoint contract via
|
|
541
|
+
* `eth_call`. This is the 4337 nonce (an EntryPoint-managed counter with
|
|
542
|
+
* 192-bit parallel keys), not the EOA `eth_getTransactionCount`.
|
|
543
|
+
*
|
|
544
|
+
* @param entryPoint - EntryPoint contract address
|
|
545
|
+
* @param account - Smart account address
|
|
546
|
+
* @param key - Nonce key as a `bigint` (default `0n`). Different keys allow
|
|
547
|
+
* parallel nonce channels. `bigint` so the full `uint192` range is
|
|
548
|
+
* representable (a JS `number` would cap at 2^53−1).
|
|
549
|
+
*/
|
|
550
|
+
async getEntryPointNonce(entryPoint, account, key = 0n, options) {
|
|
551
|
+
const data = "0x35567e1a" + ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint192"], [account, key]).slice(2);
|
|
552
|
+
const callResult = await this.call({
|
|
553
|
+
from: ZERO_ADDRESS,
|
|
554
|
+
to: entryPoint,
|
|
555
|
+
data
|
|
556
|
+
}, "latest", void 0, options);
|
|
557
|
+
try {
|
|
558
|
+
return BigInt(callResult);
|
|
559
|
+
} catch (err) {
|
|
560
|
+
throw new AbstractionKitError("BAD_DATA", "getNonce returned ill formed data", {
|
|
561
|
+
cause: ensureError(err),
|
|
562
|
+
context: callResult
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Get the EntryPoint deposit balance for an address.
|
|
568
|
+
*
|
|
569
|
+
* @returns The deposit balance in wei as a bigint
|
|
570
|
+
*/
|
|
571
|
+
async getEntryPointDeposit(address, entryPoint, options) {
|
|
572
|
+
return (await this.getEntryPointDepositInfo(address, entryPoint, options)).deposit;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Get the full {@link DepositInfo} for an address from the EntryPoint
|
|
576
|
+
* contract.
|
|
577
|
+
*/
|
|
578
|
+
async getEntryPointDepositInfo(address, entryPoint, options) {
|
|
579
|
+
const getDepositInfoSelector = "0x5287ce12";
|
|
580
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
581
|
+
const data = getDepositInfoSelector + abiCoder.encode(["address"], [address]).slice(2);
|
|
582
|
+
const callResult = await this.call({
|
|
583
|
+
from: ZERO_ADDRESS,
|
|
584
|
+
to: entryPoint,
|
|
585
|
+
data
|
|
586
|
+
}, "latest", void 0, options);
|
|
587
|
+
try {
|
|
588
|
+
const decoded = abiCoder.decode([
|
|
589
|
+
"uint256",
|
|
590
|
+
"bool",
|
|
591
|
+
"uint112",
|
|
592
|
+
"uint32",
|
|
593
|
+
"uint48"
|
|
594
|
+
], callResult);
|
|
595
|
+
if (decoded.length !== 5) throw new AbstractionKitError("BAD_DATA", "getDepositInfo returned ill formed data", { context: JSON.stringify(decoded) });
|
|
596
|
+
return {
|
|
597
|
+
deposit: BigInt(decoded[0]),
|
|
598
|
+
staked: Boolean(decoded[1]),
|
|
599
|
+
stake: BigInt(decoded[2]),
|
|
600
|
+
unstakeDelaySec: BigInt(decoded[3]),
|
|
601
|
+
withdrawTime: BigInt(decoded[4])
|
|
602
|
+
};
|
|
603
|
+
} catch (err) {
|
|
604
|
+
if (err instanceof AbstractionKitError) throw err;
|
|
605
|
+
throw new AbstractionKitError("BAD_DATA", "getDepositInfo returned ill formed data", { cause: ensureError(err) });
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
353
609
|
/**
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* separate paymaster fields. Returns `0x` when no paymaster is set.
|
|
610
|
+
* Apply a fractional `gasLevel` multiplier (e.g. 1.2 = 120%) to a `bigint`
|
|
611
|
+
* gas price without going through JS number precision.
|
|
357
612
|
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
613
|
+
* The naive `BigInt(Math.ceil(Number(value) * gasLevel))` truncates any
|
|
614
|
+
* `value` above `Number.MAX_SAFE_INTEGER` (2^53 − 1 ≈ 9.0 × 10^15 wei),
|
|
615
|
+
* which is well within the range a chain can legitimately report
|
|
616
|
+
* (especially on testnets, fork networks, or anomalous mainnet spikes).
|
|
362
617
|
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
618
|
+
* Approach: scale the multiplier into integer space (three-decimal precision
|
|
619
|
+
* — sufficient for `GasOption` and any reasonable custom value), do the
|
|
620
|
+
* multiplication in `BigInt`, then ceiling-divide back down. Preserves the
|
|
621
|
+
* original `Math.ceil(...)` rounding behavior bit-for-bit on small values.
|
|
366
622
|
*
|
|
367
|
-
* @
|
|
368
|
-
* @param stripV9PaymasterSig - Whether to strip the v0.9 paymaster signature suffix
|
|
369
|
-
* @returns Hex-encoded paymasterAndData
|
|
623
|
+
* @internal
|
|
370
624
|
*/
|
|
371
|
-
function
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
let paymasterAndData = useroperation.paymaster;
|
|
375
|
-
if (useroperation.paymasterVerificationGasLimit != null) paymasterAndData += abiCoder.encode(["uint128"], [useroperation.paymasterVerificationGasLimit]).slice(34);
|
|
376
|
-
if (useroperation.paymasterPostOpGasLimit != null) paymasterAndData += abiCoder.encode(["uint128"], [useroperation.paymasterPostOpGasLimit]).slice(34);
|
|
377
|
-
if (useroperation.paymasterData != null) {
|
|
378
|
-
const PAYMASTER_SIG_MAGIC = "22e325a297439656";
|
|
379
|
-
if (stripV9PaymasterSig && useroperation.paymasterData.toLowerCase().endsWith(PAYMASTER_SIG_MAGIC)) {
|
|
380
|
-
const sigLenHex = useroperation.paymasterData.slice(useroperation.paymasterData.length - 16 - 4, useroperation.paymasterData.length - 16);
|
|
381
|
-
const sigLen = parseInt(sigLenHex, 16);
|
|
382
|
-
const prefixEnd = useroperation.paymasterData.length - 16 - 4 - sigLen * 2;
|
|
383
|
-
paymasterAndData += useroperation.paymasterData.slice(0, prefixEnd).replaceAll("0x", "") + PAYMASTER_SIG_MAGIC;
|
|
384
|
-
} else paymasterAndData += useroperation.paymasterData.slice(2);
|
|
385
|
-
}
|
|
386
|
-
return paymasterAndData;
|
|
625
|
+
function scaleBigIntByGasLevel(value, gasLevel) {
|
|
626
|
+
const scale = 1000n;
|
|
627
|
+
return (value * BigInt(Math.round(gasLevel * Number(scale))) + scale - 1n) / scale;
|
|
387
628
|
}
|
|
388
629
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
630
|
+
* Detect whether an error indicates the JSON-RPC method itself is not
|
|
631
|
+
* implemented by the node. Used by {@link JsonRpcNode.getFeeData} to fall
|
|
632
|
+
* back gracefully on chains that don't expose EIP-1559 fee methods, while
|
|
633
|
+
* still surfacing transport, auth, and parse errors to the caller.
|
|
391
634
|
*
|
|
392
|
-
* @
|
|
393
|
-
* @returns ABI-encoded packed UserOperation as a hex string
|
|
635
|
+
* @internal
|
|
394
636
|
*/
|
|
395
|
-
function
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
(0, ethers.keccak256)(useroperation.initCode),
|
|
400
|
-
(0, ethers.keccak256)(useroperation.callData),
|
|
401
|
-
useroperation.callGasLimit,
|
|
402
|
-
useroperation.verificationGasLimit,
|
|
403
|
-
useroperation.preVerificationGas,
|
|
404
|
-
useroperation.maxFeePerGas,
|
|
405
|
-
useroperation.maxPriorityFeePerGas,
|
|
406
|
-
(0, ethers.keccak256)(useroperation.paymasterAndData)
|
|
407
|
-
];
|
|
408
|
-
return ethers.AbiCoder.defaultAbiCoder().encode([
|
|
409
|
-
"address",
|
|
410
|
-
"uint256",
|
|
411
|
-
"bytes32",
|
|
412
|
-
"bytes32",
|
|
413
|
-
"uint256",
|
|
414
|
-
"uint256",
|
|
415
|
-
"uint256",
|
|
416
|
-
"uint256",
|
|
417
|
-
"uint256",
|
|
418
|
-
"bytes32"
|
|
419
|
-
], useroperationValuesArrayWithHashedByteValues);
|
|
637
|
+
function isMethodNotSupportedError(err) {
|
|
638
|
+
if (err?.code === -32601) return true;
|
|
639
|
+
const message = err?.message?.toLowerCase() ?? "";
|
|
640
|
+
return message.includes("method not found") || message.includes("not supported") || message.includes("unsupported");
|
|
420
641
|
}
|
|
421
642
|
/**
|
|
422
|
-
*
|
|
423
|
-
*
|
|
643
|
+
* Translate a transport-level error (or already-wrapped {@link AbstractionKitError})
|
|
644
|
+
* into the `NODE_ERROR` outer / specific inner shape used by {@link JsonRpcNode}.
|
|
424
645
|
*
|
|
425
|
-
*
|
|
426
|
-
* @
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
430
|
-
let initCode = "0x";
|
|
431
|
-
if (useroperation.factory != null) {
|
|
432
|
-
initCode = useroperation.factory;
|
|
433
|
-
if (useroperation.factoryData != null) initCode += useroperation.factoryData.slice(2);
|
|
434
|
-
}
|
|
435
|
-
const accountGasLimits = "0x" + abiCoder.encode(["uint128"], [useroperation.verificationGasLimit]).slice(34) + abiCoder.encode(["uint128"], [useroperation.callGasLimit]).slice(34);
|
|
436
|
-
const gasFees = "0x" + abiCoder.encode(["uint128"], [useroperation.maxPriorityFeePerGas]).slice(34) + abiCoder.encode(["uint128"], [useroperation.maxFeePerGas]).slice(34);
|
|
437
|
-
const paymasterAndData = buildPaymasterAndData(useroperation);
|
|
438
|
-
const useroperationValuesArrayWithHashedByteValues = [
|
|
439
|
-
useroperation.sender,
|
|
440
|
-
useroperation.nonce,
|
|
441
|
-
(0, ethers.keccak256)(initCode),
|
|
442
|
-
(0, ethers.keccak256)(useroperation.callData),
|
|
443
|
-
accountGasLimits,
|
|
444
|
-
useroperation.preVerificationGas,
|
|
445
|
-
gasFees,
|
|
446
|
-
(0, ethers.keccak256)(paymasterAndData)
|
|
447
|
-
];
|
|
448
|
-
return abiCoder.encode([
|
|
449
|
-
"address",
|
|
450
|
-
"uint256",
|
|
451
|
-
"bytes32",
|
|
452
|
-
"bytes32",
|
|
453
|
-
"bytes32",
|
|
454
|
-
"uint256",
|
|
455
|
-
"bytes32",
|
|
456
|
-
"bytes32"
|
|
457
|
-
], useroperationValuesArrayWithHashedByteValues);
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* ABI-encode and pack a UserOperation for hashing (EntryPoint v0.9 format).
|
|
646
|
+
* - `AbstractionKitError` passes through unchanged (already domain-translated).
|
|
647
|
+
* - {@link ProviderRpcError} with a known JSON-RPC code → inner code from
|
|
648
|
+
* {@link JsonRpcErrorDict}.
|
|
649
|
+
* - Anything else → inner `UNKNOWN_ERROR`.
|
|
461
650
|
*
|
|
462
|
-
* @
|
|
463
|
-
* @returns ABI-encoded packed UserOperation as a hex string
|
|
651
|
+
* @internal
|
|
464
652
|
*/
|
|
465
|
-
function
|
|
466
|
-
|
|
653
|
+
function translateNodeError(err, method) {
|
|
654
|
+
if (err instanceof AbstractionKitError) return err;
|
|
655
|
+
const code = err?.code;
|
|
656
|
+
const codeString = code != null ? String(code) : "";
|
|
657
|
+
const innerCode = codeString in JsonRpcErrorDict ? JsonRpcErrorDict[codeString] : "UNKNOWN_ERROR";
|
|
658
|
+
const error = ensureError(err);
|
|
659
|
+
return new AbstractionKitError("NODE_ERROR", `node ${method} rpc call failed`, {
|
|
660
|
+
cause: new AbstractionKitError(innerCode, error.message, { errno: code }),
|
|
661
|
+
errno: code
|
|
662
|
+
});
|
|
467
663
|
}
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/Bundler.ts
|
|
468
666
|
/**
|
|
469
|
-
*
|
|
667
|
+
* JSON-RPC client for an ERC-4337 bundler.
|
|
470
668
|
*
|
|
471
|
-
*
|
|
472
|
-
* @
|
|
669
|
+
* Accepts either a URL string (wrapped automatically in {@link HttpTransport})
|
|
670
|
+
* or any {@link Transport} — including a viem client, an EIP-1193 wallet
|
|
671
|
+
* provider, an in-process mock, or a user-composed fallback/retry transport.
|
|
672
|
+
*
|
|
673
|
+
* The class itself implements {@link Transport}, so a `Bundler` can be passed
|
|
674
|
+
* back into any other Transport position.
|
|
675
|
+
*
|
|
676
|
+
* Candide bundler endpoints:
|
|
677
|
+
* - `https://api.candide.dev/api/v3/{chainId}/{apiKey}` (authenticated)
|
|
678
|
+
* - `https://api.candide.dev/public/v3/{chainId}` (public)
|
|
679
|
+
*
|
|
680
|
+
* @example URL string (most common)
|
|
681
|
+
* ```ts
|
|
682
|
+
* const bundler = new Bundler("https://api.candide.dev/public/v3/11155111");
|
|
683
|
+
* const receipt = await bundler.getUserOperationReceipt(userOpHash);
|
|
684
|
+
* ```
|
|
685
|
+
*
|
|
686
|
+
* @example Custom transport (composed retry behavior)
|
|
687
|
+
* ```ts
|
|
688
|
+
* const retryingTransport: Transport = {
|
|
689
|
+
* async request(args, options) {
|
|
690
|
+
* for (let i = 0; i < 3; i++) {
|
|
691
|
+
* try { return await inner.request(args, options); }
|
|
692
|
+
* catch (e) { if (i === 2) throw e; await sleep(2 ** i * 100); }
|
|
693
|
+
* }
|
|
694
|
+
* },
|
|
695
|
+
* };
|
|
696
|
+
* const bundler = new Bundler(retryingTransport);
|
|
697
|
+
* ```
|
|
473
698
|
*/
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
(
|
|
494
|
-
(0, ethers.keccak256)(useroperation.callData),
|
|
495
|
-
accountGasLimits,
|
|
496
|
-
useroperation.preVerificationGas,
|
|
497
|
-
gasFees,
|
|
498
|
-
(0, ethers.keccak256)(paymasterAndData)
|
|
499
|
-
];
|
|
500
|
-
return abiCoder.encode([
|
|
501
|
-
"bytes32",
|
|
502
|
-
"address",
|
|
503
|
-
"uint256",
|
|
504
|
-
"bytes32",
|
|
505
|
-
"bytes32",
|
|
506
|
-
"bytes32",
|
|
507
|
-
"uint256",
|
|
508
|
-
"bytes32",
|
|
509
|
-
"bytes32"
|
|
510
|
-
], useroperationValuesArrayWithHashedByteValues);
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Encode a function call into ABI-encoded calldata.
|
|
514
|
-
*
|
|
515
|
-
* @param functionSelector - 4-byte hex function selector (e.g., "0xa9059cbb" for ERC-20 transfer)
|
|
516
|
-
* @param functionInputAbi - Array of ABI type strings (e.g., ["address", "uint256"])
|
|
517
|
-
* @param functionInputParameters - Array of parameter values matching the ABI types
|
|
518
|
-
* @returns ABI-encoded calldata as a hex string (selector + encoded parameters)
|
|
519
|
-
*
|
|
520
|
-
* @example
|
|
521
|
-
* const transferCallData = createCallData(
|
|
522
|
-
* "0xa9059cbb",
|
|
523
|
-
* ["address", "uint256"],
|
|
524
|
-
* ["0xRecipientAddress", 1000000n],
|
|
525
|
-
* );
|
|
526
|
-
*/
|
|
527
|
-
function createCallData(functionSelector, functionInputAbi, functionInputParameters) {
|
|
528
|
-
return functionSelector + ethers.AbiCoder.defaultAbiCoder().encode(functionInputAbi, functionInputParameters).slice(2);
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Send a JSON-RPC request to the specified endpoint.
|
|
532
|
-
* Automatically converts bigint values to hex strings in the request body.
|
|
533
|
-
*
|
|
534
|
-
* @param rpcUrl - The JSON-RPC endpoint URL (bundler, node, or paymaster)
|
|
535
|
-
* @param method - The JSON-RPC method name (e.g., "eth_call", "eth_sendUserOperation")
|
|
536
|
-
* @param params - The JSON-RPC parameters
|
|
537
|
-
* @param headers - Custom HTTP headers (defaults to Content-Type: application/json)
|
|
538
|
-
* @param paramsKeyName - Key name for the params field (defaults to "params")
|
|
539
|
-
* @returns The result field from the JSON-RPC response
|
|
540
|
-
* @throws AbstractionKitError if the RPC returns an error
|
|
541
|
-
*/
|
|
542
|
-
async function sendJsonRpcRequest(rpcUrl, method, params, headers = { "Content-Type": "application/json" }, paramsKeyName = "params") {
|
|
543
|
-
const requestOptions = {
|
|
544
|
-
method: "POST",
|
|
545
|
-
headers,
|
|
546
|
-
body: JSON.stringify({
|
|
547
|
-
method,
|
|
548
|
-
[paramsKeyName]: params,
|
|
549
|
-
id: Date.now(),
|
|
550
|
-
jsonrpc: "2.0"
|
|
551
|
-
}, (_key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value),
|
|
552
|
-
redirect: "follow"
|
|
553
|
-
};
|
|
554
|
-
const response = await (await fetch(rpcUrl, requestOptions)).json();
|
|
555
|
-
if ("result" in response) return response.result;
|
|
556
|
-
else if ("simulation_results" in response) return response.simulation_results;
|
|
557
|
-
else {
|
|
558
|
-
const err = response.error;
|
|
559
|
-
const codeString = String(err.code);
|
|
560
|
-
if (codeString in BundlerErrorCodeDict) throw new AbstractionKitError(BundlerErrorCodeDict[codeString], err.message, {
|
|
561
|
-
errno: err.code,
|
|
562
|
-
context: {
|
|
563
|
-
url: rpcUrl,
|
|
564
|
-
requestOptions: JSON.stringify(requestOptions)
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
else throw new AbstractionKitError("UNKNOWN_ERROR", err.message, {
|
|
568
|
-
errno: err.code,
|
|
569
|
-
context: {
|
|
570
|
-
url: rpcUrl,
|
|
571
|
-
requestOptions: JSON.stringify(requestOptions)
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Get a 4-byte function selector from a Solidity-style function signature.
|
|
578
|
-
* Computed as the first 4 bytes of keccak256(signature).
|
|
579
|
-
* @param functionSignature - Solidity-style function signature, e.g. "mint(address)"
|
|
580
|
-
* @returns Function selector as a 0x-prefixed 10-character hex string
|
|
581
|
-
*
|
|
582
|
-
* @example
|
|
583
|
-
* getFunctionSelector("getNonce(address,uint192)"); // "0x35567e1a"
|
|
584
|
-
*/
|
|
585
|
-
function getFunctionSelector(functionSignature) {
|
|
586
|
-
return (0, ethers.id)(functionSignature).slice(0, 10);
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Fetch the account's nonce from the EntryPoint contract.
|
|
590
|
-
*
|
|
591
|
-
* @param rpcUrl - Ethereum JSON-RPC node URL
|
|
592
|
-
* @param entryPoint - EntryPoint contract address
|
|
593
|
-
* @param account - Smart account address to query
|
|
594
|
-
* @param key - Nonce key (default 0). Different keys allow parallel nonce channels.
|
|
595
|
-
* @returns The current nonce as a bigint
|
|
596
|
-
* @throws AbstractionKitError with code "BAD_DATA" if the nonce call fails
|
|
597
|
-
*/
|
|
598
|
-
async function fetchAccountNonce(rpcUrl, entryPoint, account, key = 0) {
|
|
599
|
-
const params = [{
|
|
600
|
-
from: "0x0000000000000000000000000000000000000000",
|
|
601
|
-
to: entryPoint,
|
|
602
|
-
data: createCallData(getFunctionSelector("getNonce(address,uint192)"), ["address", "uint192"], [account, key])
|
|
603
|
-
}, "latest"];
|
|
604
|
-
try {
|
|
605
|
-
const nonce = await sendJsonRpcRequest(rpcUrl, "eth_call", params);
|
|
606
|
-
if (typeof nonce === "string") try {
|
|
607
|
-
return BigInt(nonce);
|
|
608
|
-
} catch (err) {
|
|
609
|
-
throw new AbstractionKitError("BAD_DATA", "getNonce returned ill formed data", { cause: ensureError(err) });
|
|
610
|
-
}
|
|
611
|
-
else throw new AbstractionKitError("BAD_DATA", "getNonce returned ill formed data", { context: JSON.stringify(nonce) });
|
|
612
|
-
} catch (err) {
|
|
613
|
-
throw new AbstractionKitError("BAD_DATA", "getNonce failed", { cause: ensureError(err) });
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Fetch current gas prices from a JSON-RPC node.
|
|
618
|
-
* Applies a gas level multiplier to adjust for faster or cheaper inclusion.
|
|
619
|
-
*
|
|
620
|
-
* @param provideRpc - Ethereum JSON-RPC node URL
|
|
621
|
-
* @param gasLevel - Gas price multiplier (default: GasOption.Medium = 1.2x)
|
|
622
|
-
* @returns A tuple of [maxFeePerGas, maxPriorityFeePerGas] as bigints
|
|
623
|
-
*/
|
|
624
|
-
async function fetchGasPrice(provideRpc, gasLevel = GasOption.Medium) {
|
|
625
|
-
try {
|
|
626
|
-
const feeData = await new ethers.JsonRpcProvider(provideRpc).getFeeData();
|
|
627
|
-
let maxFeePerGas;
|
|
628
|
-
let maxPriorityFeePerGas;
|
|
629
|
-
if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
|
|
630
|
-
maxFeePerGas = BigInt(Math.ceil(Number(feeData.maxFeePerGas) * gasLevel));
|
|
631
|
-
maxPriorityFeePerGas = BigInt(Math.ceil(Number(feeData.maxPriorityFeePerGas) * gasLevel));
|
|
632
|
-
} else if (feeData.gasPrice != null) {
|
|
633
|
-
maxFeePerGas = BigInt(Math.ceil(Number(feeData.gasPrice) * gasLevel));
|
|
634
|
-
maxPriorityFeePerGas = maxFeePerGas;
|
|
635
|
-
} else {
|
|
636
|
-
maxFeePerGas = BigInt(Math.ceil(1e9 * gasLevel));
|
|
637
|
-
maxPriorityFeePerGas = maxFeePerGas;
|
|
638
|
-
}
|
|
639
|
-
if (maxFeePerGas === 0n) maxFeePerGas = 1n;
|
|
640
|
-
if (maxPriorityFeePerGas === 0n) maxPriorityFeePerGas = 1n;
|
|
641
|
-
return [maxFeePerGas, maxPriorityFeePerGas];
|
|
642
|
-
} catch (err) {
|
|
643
|
-
throw new AbstractionKitError("BAD_DATA", "fetching gas prices from node failed.", { cause: ensureError(err) });
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Fetch current gas prices from the Polygon Gas Station API.
|
|
648
|
-
*
|
|
649
|
-
* @param polygonChain - Target Polygon chain (Mainnet, Amoy, etc.)
|
|
650
|
-
* @param gasLevel - Gas price level (Slow, Medium, Fast)
|
|
651
|
-
* @returns A tuple of [maxFeePerGas, maxPriorityFeePerGas] as bigints
|
|
652
|
-
*/
|
|
653
|
-
async function fetchGasPricePolygon(polygonChain, gasLevel = GasOption.Medium) {
|
|
654
|
-
const gasStationUrl = `https://gasstation.polygon.technology/${polygonChain}`;
|
|
655
|
-
try {
|
|
656
|
-
const response = await (await fetch(gasStationUrl)).json();
|
|
657
|
-
let gasPrice;
|
|
658
|
-
if (gasLevel === GasOption.Slow) gasPrice = response.safeLow;
|
|
659
|
-
else if (gasLevel === GasOption.Medium) gasPrice = response.standard;
|
|
660
|
-
else gasPrice = response.fast;
|
|
661
|
-
let maxFeePerGas = BigInt(Math.ceil(Number(gasPrice.maxFee) * 1e9));
|
|
662
|
-
let maxPriorityFeePerGas = BigInt(Math.ceil(Number(gasPrice.maxPriorityFee) * 1e9));
|
|
663
|
-
if (maxFeePerGas === 0n) maxFeePerGas = 1n;
|
|
664
|
-
if (maxPriorityFeePerGas === 0n) maxPriorityFeePerGas = 1n;
|
|
665
|
-
return [maxFeePerGas, maxPriorityFeePerGas];
|
|
666
|
-
} catch (err) {
|
|
667
|
-
const error = ensureError(err);
|
|
668
|
-
throw new AbstractionKitError("BAD_DATA", `fetching gas prices from ${gasStationUrl} failed.`, { cause: error });
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Calculate the maximum gas cost (in wei) that a UserOperation could consume.
|
|
673
|
-
* Uses different formulas for v0.6 (with paymaster multiplier) and v0.7+ UserOperations.
|
|
674
|
-
*
|
|
675
|
-
* @param useroperation - The UserOperation to calculate the max gas cost for
|
|
676
|
-
* @returns Maximum possible gas cost in wei as a bigint
|
|
677
|
-
*/
|
|
678
|
-
function calculateUserOperationMaxGasCost(useroperation) {
|
|
679
|
-
if ("initCode" in useroperation) {
|
|
680
|
-
const mul = useroperation.paymasterAndData !== "0x" && useroperation.paymasterAndData != null ? 3n : 0n;
|
|
681
|
-
return (useroperation.callGasLimit + useroperation.verificationGasLimit * mul + useroperation.preVerificationGas) * useroperation.maxFeePerGas;
|
|
682
|
-
} else return (useroperation.verificationGasLimit + useroperation.callGasLimit + (useroperation.paymasterVerificationGasLimit ?? 0n) + (useroperation.paymasterPostOpGasLimit ?? 0n) + useroperation.preVerificationGas) * useroperation.maxFeePerGas;
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* Get the deposit balance of an address in the EntryPoint contract.
|
|
686
|
-
*
|
|
687
|
-
* @param nodeRpcUrl - Ethereum JSON-RPC node URL
|
|
688
|
-
* @param address - Address to query the deposit for
|
|
689
|
-
* @param entrypointAddress - EntryPoint contract address
|
|
690
|
-
* @returns The deposit balance as a bigint
|
|
691
|
-
*/
|
|
692
|
-
async function getBalanceOf(nodeRpcUrl, address, entrypointAddress) {
|
|
693
|
-
return (await getDepositInfo(nodeRpcUrl, address, entrypointAddress)).deposit;
|
|
694
|
-
}
|
|
695
|
-
/**
|
|
696
|
-
* Get the full deposit info of an address from the EntryPoint contract.
|
|
697
|
-
*
|
|
698
|
-
* @param nodeRpcUrl - Ethereum JSON-RPC node URL
|
|
699
|
-
* @param address - Address to query
|
|
700
|
-
* @param entrypointAddress - EntryPoint contract address
|
|
701
|
-
* @returns DepositInfo with deposit, staked, stake, unstakeDelaySec, withdrawTime
|
|
702
|
-
*/
|
|
703
|
-
async function getDepositInfo(nodeRpcUrl, address, entrypointAddress) {
|
|
704
|
-
const params = {
|
|
705
|
-
from: "0x0000000000000000000000000000000000000000",
|
|
706
|
-
to: entrypointAddress,
|
|
707
|
-
data: createCallData("0x5287ce12", ["address"], [address])
|
|
708
|
-
};
|
|
709
|
-
try {
|
|
710
|
-
const depositInfoRequestResult = await sendEthCallRequest(nodeRpcUrl, params, "latest");
|
|
711
|
-
const decodedCalldata = ethers.AbiCoder.defaultAbiCoder().decode([
|
|
712
|
-
"uint256",
|
|
713
|
-
"bool",
|
|
714
|
-
"uint112",
|
|
715
|
-
"uint32",
|
|
716
|
-
"uint48"
|
|
717
|
-
], depositInfoRequestResult);
|
|
718
|
-
if (decodedCalldata.length === 5) try {
|
|
719
|
-
return {
|
|
720
|
-
deposit: BigInt(decodedCalldata[0]),
|
|
721
|
-
staked: Boolean(decodedCalldata[1]),
|
|
722
|
-
stake: BigInt(decodedCalldata[2]),
|
|
723
|
-
unstakeDelaySec: BigInt(decodedCalldata[3]),
|
|
724
|
-
withdrawTime: BigInt(decodedCalldata[4])
|
|
725
|
-
};
|
|
726
|
-
} catch (err) {
|
|
727
|
-
throw new AbstractionKitError("BAD_DATA", "getDepositInfo returned ill formed data", { cause: ensureError(err) });
|
|
728
|
-
}
|
|
729
|
-
else throw new AbstractionKitError("BAD_DATA", "getDepositInfo returned ill formed data", { context: JSON.stringify(decodedCalldata) });
|
|
730
|
-
} catch (err) {
|
|
731
|
-
throw new AbstractionKitError("BAD_DATA", "getDepositInfo failed", { cause: ensureError(err) });
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Send an eth_call JSON-RPC request with optional state overrides.
|
|
736
|
-
*
|
|
737
|
-
* @param nodeRpcUrl - Ethereum JSON-RPC node URL
|
|
738
|
-
* @param ethCallTransaction - The call transaction parameters
|
|
739
|
-
* @param blockNumber - Block number or "latest"
|
|
740
|
-
* @param stateOverrides - Optional state overrides for the call
|
|
741
|
-
* @returns The call result as a hex string
|
|
742
|
-
*/
|
|
743
|
-
async function sendEthCallRequest(nodeRpcUrl, ethCallTransaction, blockNumber, stateOverrides) {
|
|
744
|
-
let params = [];
|
|
745
|
-
if (stateOverrides == null) params = [ethCallTransaction, blockNumber];
|
|
746
|
-
else params = [
|
|
747
|
-
ethCallTransaction,
|
|
748
|
-
blockNumber,
|
|
749
|
-
stateOverrides
|
|
750
|
-
];
|
|
751
|
-
try {
|
|
752
|
-
const data = await sendJsonRpcRequest(nodeRpcUrl, "eth_call", params);
|
|
753
|
-
if (typeof data === "string") try {
|
|
754
|
-
return data;
|
|
755
|
-
} catch (err) {
|
|
756
|
-
throw new AbstractionKitError("BAD_DATA", "eth_call returned ill formed data", { cause: ensureError(err) });
|
|
757
|
-
}
|
|
758
|
-
else throw new AbstractionKitError("BAD_DATA", "eth_call returned ill formed data", { context: JSON.stringify(data) });
|
|
759
|
-
} catch (err) {
|
|
760
|
-
throw new AbstractionKitError("BAD_DATA", "eth_call failed", { cause: ensureError(err) });
|
|
699
|
+
var Bundler = class Bundler {
|
|
700
|
+
/**
|
|
701
|
+
* The raw transport the user passed in (or {@link HttpTransport} when a URL
|
|
702
|
+
* string was passed). Exposed for introspection — reading `.url`,
|
|
703
|
+
* `isHttpTransport(...)` checks, passing it back into another service.
|
|
704
|
+
*
|
|
705
|
+
* Calls made directly on this field (`bundler.transport.request(...)`) go
|
|
706
|
+
* to the raw transport and skip SDK-level behavior like bigint param
|
|
707
|
+
* normalization. For SDK-pipeline behavior, use {@link Bundler.request} or
|
|
708
|
+
* the typed methods.
|
|
709
|
+
*/
|
|
710
|
+
transport;
|
|
711
|
+
/** Normalizing wrapper around {@link transport}, used for every SDK-outbound call. */
|
|
712
|
+
outbound;
|
|
713
|
+
/**
|
|
714
|
+
* @param rpc - Bundler JSON-RPC endpoint URL, or any {@link Transport}.
|
|
715
|
+
*/
|
|
716
|
+
constructor(rpc) {
|
|
717
|
+
this.transport = typeof rpc === "string" ? new HttpTransport(rpc) : rpc;
|
|
718
|
+
this.outbound = normalizingTransport(this.transport);
|
|
761
719
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
const params = [contractAddress, blockNumber];
|
|
773
|
-
try {
|
|
774
|
-
const data = await sendJsonRpcRequest(nodeRpcUrl, "eth_getCode", params);
|
|
775
|
-
if (typeof data === "string") try {
|
|
776
|
-
return data;
|
|
777
|
-
} catch (err) {
|
|
778
|
-
throw new AbstractionKitError("BAD_DATA", "eth_getCode returned ill formed data", { cause: ensureError(err) });
|
|
779
|
-
}
|
|
780
|
-
else throw new AbstractionKitError("BAD_DATA", "eth_getCode returned ill formed data", { context: JSON.stringify(data) });
|
|
781
|
-
} catch (err) {
|
|
782
|
-
throw new AbstractionKitError("BAD_DATA", "eth_getCode failed", { cause: ensureError(err) });
|
|
720
|
+
/**
|
|
721
|
+
* Normalize any acceptable input into a `Bundler`. When the input is
|
|
722
|
+
* already a `Bundler` instance, it is returned by reference (so a user's
|
|
723
|
+
* pre-constructed Bundler is never re-wrapped and its transport is
|
|
724
|
+
* reused for follow-up calls like {@link SendUseroperationResponse.included}).
|
|
725
|
+
*
|
|
726
|
+
* @param input - URL string, Transport, or existing Bundler
|
|
727
|
+
*/
|
|
728
|
+
static from(input) {
|
|
729
|
+
return input instanceof Bundler ? input : new Bundler(input);
|
|
783
730
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
* @returns The checksummed delegatee address, or `null` if not delegated
|
|
792
|
-
*/
|
|
793
|
-
async function getDelegatedAddress(accountAddress, providerRpc) {
|
|
794
|
-
const code = (await sendEthGetCodeRequest(providerRpc, accountAddress, "latest")).toLowerCase();
|
|
795
|
-
if (code.length === 48 && code.startsWith("0xef0100")) return (0, ethers.getAddress)(`0x${code.slice(8)}`);
|
|
796
|
-
return null;
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
|
-
* Fetch gas prices using either the Polygon Gas Station or a standard JSON-RPC node.
|
|
800
|
-
*
|
|
801
|
-
* @param providerRpc - Ethereum JSON-RPC node URL (used if polygonGasStation is null)
|
|
802
|
-
* @param polygonGasStation - Polygon chain to use for gas station (takes priority)
|
|
803
|
-
* @param gasLevel - Gas price multiplier (default: GasOption.Medium)
|
|
804
|
-
* @returns A tuple of [maxFeePerGas, maxPriorityFeePerGas] as bigints
|
|
805
|
-
*/
|
|
806
|
-
async function handlefetchGasPrice(providerRpc, polygonGasStation, gasLevel = GasOption.Medium) {
|
|
807
|
-
let maxFeePerGas;
|
|
808
|
-
let maxPriorityFeePerGas;
|
|
809
|
-
if (polygonGasStation != null) [maxFeePerGas, maxPriorityFeePerGas] = await fetchGasPricePolygon(polygonGasStation, gasLevel);
|
|
810
|
-
else if (providerRpc != null) [maxFeePerGas, maxPriorityFeePerGas] = await fetchGasPrice(providerRpc, gasLevel);
|
|
811
|
-
else throw new AbstractionKitError("BAD_DATA", "providerRpc can't be null if maxFeePerGas and maxPriorityFeePerGas are not overridden");
|
|
812
|
-
return [maxFeePerGas, maxPriorityFeePerGas];
|
|
813
|
-
}
|
|
814
|
-
//#endregion
|
|
815
|
-
//#region src/Bundler.ts
|
|
816
|
-
/**
|
|
817
|
-
* JSON-RPC client for an ERC-4337 bundler.
|
|
818
|
-
*
|
|
819
|
-
* Candide bundler endpoints:
|
|
820
|
-
* - `https://api.candide.dev/api/v3/{chainId}/{apiKey}` (authenticated)
|
|
821
|
-
* - `https://api.candide.dev/public/v3/{chainId}` (public)
|
|
822
|
-
*
|
|
823
|
-
* @example
|
|
824
|
-
* const bundler = new Bundler("https://api.candide.dev/public/v3/11155111");
|
|
825
|
-
* const receipt = await bundler.getUserOperationReceipt(userOpHash);
|
|
826
|
-
*/
|
|
827
|
-
var Bundler = class {
|
|
828
|
-
rpcUrl;
|
|
829
|
-
/** @param rpcUrl - The bundler JSON-RPC endpoint URL */
|
|
830
|
-
constructor(rpcUrl) {
|
|
831
|
-
this.rpcUrl = rpcUrl;
|
|
731
|
+
/**
|
|
732
|
+
* Transport delegate. Forwards directly to the underlying
|
|
733
|
+
* {@link Transport.request}. Lets a `Bundler` itself slot into any other
|
|
734
|
+
* transport position.
|
|
735
|
+
*/
|
|
736
|
+
request(args, options) {
|
|
737
|
+
return this.outbound.request(args, options);
|
|
832
738
|
}
|
|
833
739
|
/**
|
|
834
740
|
* Get the bundler's chain ID.
|
|
@@ -836,11 +742,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
836
742
|
*/
|
|
837
743
|
async chainId() {
|
|
838
744
|
try {
|
|
839
|
-
const chainId = await
|
|
840
|
-
if (typeof chainId
|
|
841
|
-
|
|
745
|
+
const chainId = await this.outbound.request({ method: "eth_chainId" });
|
|
746
|
+
if (typeof chainId !== "string") throw new AbstractionKitError("BAD_DATA", "bundler eth_chainId rpc call failed");
|
|
747
|
+
return chainId;
|
|
842
748
|
} catch (err) {
|
|
843
|
-
throw
|
|
749
|
+
throw translateBundlerError(err, "eth_chainId");
|
|
844
750
|
}
|
|
845
751
|
}
|
|
846
752
|
/**
|
|
@@ -849,9 +755,9 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
849
755
|
*/
|
|
850
756
|
async supportedEntryPoints() {
|
|
851
757
|
try {
|
|
852
|
-
return await
|
|
758
|
+
return await this.outbound.request({ method: "eth_supportedEntryPoints" });
|
|
853
759
|
} catch (err) {
|
|
854
|
-
throw
|
|
760
|
+
throw translateBundlerError(err, "eth_supportedEntryPoints");
|
|
855
761
|
}
|
|
856
762
|
}
|
|
857
763
|
/**
|
|
@@ -863,14 +769,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
863
769
|
*/
|
|
864
770
|
async estimateUserOperationGas(useroperation, entrypointAddress, state_override_set) {
|
|
865
771
|
try {
|
|
866
|
-
|
|
867
|
-
if (typeof state_override_set === "undefined") jsonRpcResult = await sendJsonRpcRequest(this.rpcUrl, "eth_estimateUserOperationGas", [useroperation, entrypointAddress]);
|
|
868
|
-
else jsonRpcResult = await sendJsonRpcRequest(this.rpcUrl, "eth_estimateUserOperationGas", [
|
|
772
|
+
const params = state_override_set == null ? [useroperation, entrypointAddress] : [
|
|
869
773
|
useroperation,
|
|
870
774
|
entrypointAddress,
|
|
871
775
|
state_override_set
|
|
872
|
-
]
|
|
873
|
-
const res =
|
|
776
|
+
];
|
|
777
|
+
const res = await this.outbound.request({
|
|
778
|
+
method: "eth_estimateUserOperationGas",
|
|
779
|
+
params
|
|
780
|
+
});
|
|
874
781
|
const gasEstimationResult = {
|
|
875
782
|
callGasLimit: BigInt(res.callGasLimit),
|
|
876
783
|
preVerificationGas: BigInt(res.preVerificationGas),
|
|
@@ -880,7 +787,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
880
787
|
if (res.paymasterPostOpGasLimit != null) gasEstimationResult.paymasterPostOpGasLimit = BigInt(res.paymasterPostOpGasLimit);
|
|
881
788
|
return gasEstimationResult;
|
|
882
789
|
} catch (err) {
|
|
883
|
-
throw
|
|
790
|
+
throw translateBundlerError(err, "eth_estimateUserOperationGas");
|
|
884
791
|
}
|
|
885
792
|
}
|
|
886
793
|
/**
|
|
@@ -891,9 +798,12 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
891
798
|
*/
|
|
892
799
|
async sendUserOperation(useroperation, entrypointAddress) {
|
|
893
800
|
try {
|
|
894
|
-
return await
|
|
801
|
+
return await this.outbound.request({
|
|
802
|
+
method: "eth_sendUserOperation",
|
|
803
|
+
params: [useroperation, entrypointAddress]
|
|
804
|
+
});
|
|
895
805
|
} catch (err) {
|
|
896
|
-
throw
|
|
806
|
+
throw translateBundlerError(err, "eth_sendUserOperation");
|
|
897
807
|
}
|
|
898
808
|
}
|
|
899
809
|
/**
|
|
@@ -903,31 +813,31 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
903
813
|
*/
|
|
904
814
|
async getUserOperationReceipt(useroperationhash) {
|
|
905
815
|
try {
|
|
906
|
-
const
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
...res.receipt,
|
|
910
|
-
blockNumber: BigInt(res.receipt.blockNumber),
|
|
911
|
-
cumulativeGasUsed: BigInt(res.receipt.cumulativeGasUsed),
|
|
912
|
-
gasUsed: BigInt(res.receipt.gasUsed),
|
|
913
|
-
transactionIndex: BigInt(res.receipt.transactionIndex),
|
|
914
|
-
effectiveGasPrice: res.receipt.effectiveGasPrice == null ? void 0 : BigInt(res.receipt.effectiveGasPrice),
|
|
915
|
-
logs: JSON.stringify(res.receipt.logs)
|
|
916
|
-
};
|
|
917
|
-
return {
|
|
918
|
-
...res,
|
|
919
|
-
nonce: BigInt(res.nonce),
|
|
920
|
-
actualGasCost: BigInt(res.actualGasCost),
|
|
921
|
-
actualGasUsed: BigInt(res.actualGasUsed),
|
|
922
|
-
logs: JSON.stringify(res.logs),
|
|
923
|
-
receipt: userOperationReceipt
|
|
924
|
-
};
|
|
925
|
-
} else return null;
|
|
926
|
-
} catch (err) {
|
|
927
|
-
throw new AbstractionKitError("BUNDLER_ERROR", "bundler eth_getUserOperationReceipt rpc call failed", {
|
|
928
|
-
cause: ensureError(err),
|
|
929
|
-
context: { useroperationhash }
|
|
816
|
+
const jsonRpcResult = await this.outbound.request({
|
|
817
|
+
method: "eth_getUserOperationReceipt",
|
|
818
|
+
params: [useroperationhash]
|
|
930
819
|
});
|
|
820
|
+
if (jsonRpcResult == null) return null;
|
|
821
|
+
const res = jsonRpcResult;
|
|
822
|
+
const userOperationReceipt = {
|
|
823
|
+
...res.receipt,
|
|
824
|
+
blockNumber: BigInt(res.receipt.blockNumber),
|
|
825
|
+
cumulativeGasUsed: BigInt(res.receipt.cumulativeGasUsed),
|
|
826
|
+
gasUsed: BigInt(res.receipt.gasUsed),
|
|
827
|
+
transactionIndex: BigInt(res.receipt.transactionIndex),
|
|
828
|
+
effectiveGasPrice: res.receipt.effectiveGasPrice == null ? void 0 : BigInt(res.receipt.effectiveGasPrice),
|
|
829
|
+
logs: JSON.stringify(res.receipt.logs)
|
|
830
|
+
};
|
|
831
|
+
return {
|
|
832
|
+
...res,
|
|
833
|
+
nonce: BigInt(res.nonce),
|
|
834
|
+
actualGasCost: BigInt(res.actualGasCost),
|
|
835
|
+
actualGasUsed: BigInt(res.actualGasUsed),
|
|
836
|
+
logs: JSON.stringify(res.logs),
|
|
837
|
+
receipt: userOperationReceipt
|
|
838
|
+
};
|
|
839
|
+
} catch (err) {
|
|
840
|
+
throw translateBundlerError(err, "eth_getUserOperationReceipt", { useroperationhash });
|
|
931
841
|
}
|
|
932
842
|
}
|
|
933
843
|
/**
|
|
@@ -937,43 +847,233 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
937
847
|
*/
|
|
938
848
|
async getUserOperationByHash(useroperationhash) {
|
|
939
849
|
try {
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
850
|
+
const jsonRpcResult = await this.outbound.request({
|
|
851
|
+
method: "eth_getUserOperationByHash",
|
|
852
|
+
params: [useroperationhash]
|
|
853
|
+
});
|
|
854
|
+
if (jsonRpcResult == null) return null;
|
|
855
|
+
return {
|
|
856
|
+
...jsonRpcResult,
|
|
857
|
+
blockNumber: jsonRpcResult.blockNumber == null ? null : BigInt(jsonRpcResult.blockNumber)
|
|
944
858
|
};
|
|
945
|
-
else return null;
|
|
946
859
|
} catch (err) {
|
|
947
|
-
throw
|
|
948
|
-
cause: ensureError(err),
|
|
949
|
-
context: { useroperationhash }
|
|
950
|
-
});
|
|
860
|
+
throw translateBundlerError(err, "eth_getUserOperationByHash", { useroperationhash });
|
|
951
861
|
}
|
|
952
862
|
}
|
|
953
863
|
};
|
|
954
|
-
//#endregion
|
|
955
|
-
//#region src/signer/negotiate.ts
|
|
956
864
|
/**
|
|
957
|
-
*
|
|
958
|
-
*
|
|
959
|
-
*
|
|
865
|
+
* Translate a transport-level error (or already-wrapped
|
|
866
|
+
* {@link AbstractionKitError}) into the `BUNDLER_ERROR` outer / specific
|
|
867
|
+
* 4337-code inner shape used by {@link Bundler}.
|
|
960
868
|
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
*
|
|
869
|
+
* - `AbstractionKitError` passes through unchanged (already domain-translated).
|
|
870
|
+
* - {@link ProviderRpcError} with a known 4337 code → inner code from
|
|
871
|
+
* {@link BundlerErrorCodeDict}.
|
|
872
|
+
* - Anything else → inner `UNKNOWN_ERROR`.
|
|
873
|
+
*
|
|
874
|
+
* @internal
|
|
964
875
|
*/
|
|
965
|
-
function
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
876
|
+
function translateBundlerError(err, method, context) {
|
|
877
|
+
if (err instanceof AbstractionKitError) {
|
|
878
|
+
if (err.code === "BUNDLER_ERROR") return err;
|
|
879
|
+
return new AbstractionKitError("BUNDLER_ERROR", `bundler ${method} rpc call failed`, {
|
|
880
|
+
cause: err,
|
|
881
|
+
errno: err.errno,
|
|
882
|
+
context
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
const code = err?.code;
|
|
886
|
+
const codeString = code != null ? String(code) : "";
|
|
887
|
+
const innerCode = codeString in BundlerErrorCodeDict ? BundlerErrorCodeDict[codeString] : "UNKNOWN_ERROR";
|
|
888
|
+
const error = ensureError(err);
|
|
889
|
+
return new AbstractionKitError("BUNDLER_ERROR", `bundler ${method} rpc call failed`, {
|
|
890
|
+
cause: new AbstractionKitError(innerCode, error.message, { errno: code }),
|
|
891
|
+
errno: code,
|
|
892
|
+
context
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region src/constants.ts
|
|
897
|
+
/** The Ethereum zero address (0x0000...0000), used as a placeholder for empty/null addresses */
|
|
898
|
+
const ZeroAddress = "0x0000000000000000000000000000000000000000";
|
|
899
|
+
/** EntryPoint v0.9 contract address */
|
|
900
|
+
const ENTRYPOINT_V9 = "0x433709009B8330FDa32311DF1C2AFA402eD8D009";
|
|
901
|
+
/** EntryPoint v0.8 contract address */
|
|
902
|
+
const ENTRYPOINT_V8 = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108";
|
|
903
|
+
/** EntryPoint v0.7 contract address */
|
|
904
|
+
const ENTRYPOINT_V7 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
905
|
+
/** EntryPoint v0.6 contract address */
|
|
906
|
+
const ENTRYPOINT_V6 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
|
|
907
|
+
/** Safe L2 singleton v1.5.0 address and init hash */
|
|
908
|
+
const Safe_L2_V1_5_0 = {
|
|
909
|
+
singletonAddress: "0xEdd160fEBBD92E350D4D398fb636302fccd67C7e",
|
|
910
|
+
singletonInitHash: "0x1b94aebb5a7df6dff11d93589204a6bbc99b4b8c9014bf1d386d006c2c17a881"
|
|
911
|
+
};
|
|
912
|
+
/** Safe L2 singleton v1.4.1 address and init hash */
|
|
913
|
+
const Safe_L2_V1_4_1 = {
|
|
914
|
+
singletonAddress: "0x29fcB43b46531BcA003ddC8FCB67FFE91900C762",
|
|
915
|
+
singletonInitHash: "0xe298282cefe913ab5d282047161268a8222e4bd4ed106300c547894bbefd31ee"
|
|
916
|
+
};
|
|
917
|
+
/** Default placeholder values for gas estimation before actual values are known */
|
|
918
|
+
const BaseUserOperationDummyValues = {
|
|
919
|
+
sender: ZeroAddress,
|
|
920
|
+
nonce: 0n,
|
|
921
|
+
callData: "0x",
|
|
922
|
+
callGasLimit: 0n,
|
|
923
|
+
verificationGasLimit: 0n,
|
|
924
|
+
preVerificationGas: 0n,
|
|
925
|
+
maxFeePerGas: 0n,
|
|
926
|
+
maxPriorityFeePerGas: 0n,
|
|
927
|
+
signature: "0x"
|
|
928
|
+
};
|
|
929
|
+
/** EIP-712 primary type string used when signing Safe UserOperations. */
|
|
930
|
+
const EIP712_SAFE_OPERATION_PRIMARY_TYPE = "SafeOp";
|
|
931
|
+
/** EIP-712 type definition for Safe UserOperation signing (EntryPoint v0.6) */
|
|
932
|
+
const EIP712_SAFE_OPERATION_V6_TYPE = { SafeOp: [
|
|
933
|
+
{
|
|
934
|
+
type: "address",
|
|
935
|
+
name: "safe"
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
type: "uint256",
|
|
939
|
+
name: "nonce"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
type: "bytes",
|
|
943
|
+
name: "initCode"
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
type: "bytes",
|
|
947
|
+
name: "callData"
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
type: "uint256",
|
|
951
|
+
name: "callGasLimit"
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
type: "uint256",
|
|
955
|
+
name: "verificationGasLimit"
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
type: "uint256",
|
|
959
|
+
name: "preVerificationGas"
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
type: "uint256",
|
|
963
|
+
name: "maxFeePerGas"
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
type: "uint256",
|
|
967
|
+
name: "maxPriorityFeePerGas"
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
type: "bytes",
|
|
971
|
+
name: "paymasterAndData"
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
type: "uint48",
|
|
975
|
+
name: "validAfter"
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
type: "uint48",
|
|
979
|
+
name: "validUntil"
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
type: "address",
|
|
983
|
+
name: "entryPoint"
|
|
984
|
+
}
|
|
985
|
+
] };
|
|
986
|
+
/** EIP-712 type definition for Safe UserOperation signing (EntryPoint v0.7) */
|
|
987
|
+
const EIP712_SAFE_OPERATION_V7_TYPE = { SafeOp: [
|
|
988
|
+
{
|
|
989
|
+
type: "address",
|
|
990
|
+
name: "safe"
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
type: "uint256",
|
|
994
|
+
name: "nonce"
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
type: "bytes",
|
|
998
|
+
name: "initCode"
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
type: "bytes",
|
|
1002
|
+
name: "callData"
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
type: "uint128",
|
|
1006
|
+
name: "verificationGasLimit"
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
type: "uint128",
|
|
1010
|
+
name: "callGasLimit"
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
type: "uint256",
|
|
1014
|
+
name: "preVerificationGas"
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
type: "uint128",
|
|
1018
|
+
name: "maxPriorityFeePerGas"
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
type: "uint128",
|
|
1022
|
+
name: "maxFeePerGas"
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
type: "bytes",
|
|
1026
|
+
name: "paymasterAndData"
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
type: "uint48",
|
|
1030
|
+
name: "validAfter"
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
type: "uint48",
|
|
1034
|
+
name: "validUntil"
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
type: "address",
|
|
1038
|
+
name: "entryPoint"
|
|
1039
|
+
}
|
|
1040
|
+
] };
|
|
1041
|
+
/** EIP-712 primary type string used when signing multi-chain Safe operations. */
|
|
1042
|
+
const EIP712_MULTI_CHAIN_OPERATIONS_PRIMARY_TYPE = "MerkleTreeRoot";
|
|
1043
|
+
/** EIP-712 type definition for multi-chain Safe operations using Merkle tree roots */
|
|
1044
|
+
const EIP712_MULTI_CHAIN_OPERATIONS_TYPE = { MerkleTreeRoot: [{
|
|
1045
|
+
type: "bytes32",
|
|
1046
|
+
name: "merkleTreeRoot"
|
|
1047
|
+
}] };
|
|
1048
|
+
/** Default address for the secp256r1 (P-256) precompile used by WebAuthn verification */
|
|
1049
|
+
const DEFAULT_SECP256R1_PRECOMPILE_ADDRESS = "0x0000000000000000000000000000000000000100";
|
|
1050
|
+
/** Uniswap Calibur singleton v1.0.0 (EntryPoint v0.8) */
|
|
1051
|
+
const CALIBUR_UNISWAP_V1_0_0_SINGLETON_ADDRESS = "0x000000009B1D0aF20D8C6d0A44e162d11F9b8f00";
|
|
1052
|
+
/** Candide Calibur singleton v0.1.0 (EntryPoint v0.9, unaudited) */
|
|
1053
|
+
const CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS = "0x71032285A847c4311Eb7ec2E7A636aB94A9805Aa";
|
|
1054
|
+
//#endregion
|
|
1055
|
+
//#region src/signer/negotiate.ts
|
|
1056
|
+
/**
|
|
1057
|
+
* Pick the best mutually-supported signing scheme for one signer against an
|
|
1058
|
+
* account's accepted schemes. Later in the `accepted` array = lower preference;
|
|
1059
|
+
* the account ranks by preference.
|
|
1060
|
+
*
|
|
1061
|
+
* Throws a detailed {@link AbstractionKitError} if no scheme overlaps,
|
|
1062
|
+
* citing the signer's address, what the account accepts, and what the
|
|
1063
|
+
* signer can do.
|
|
1064
|
+
*/
|
|
1065
|
+
function pickScheme(signer, accepted, context) {
|
|
1066
|
+
const signerCan = [];
|
|
1067
|
+
if (typeof signer.signTypedData === "function") signerCan.push("typedData");
|
|
1068
|
+
if (typeof signer.signHash === "function") signerCan.push("hash");
|
|
1069
|
+
for (const scheme of accepted) if (signerCan.includes(scheme)) return scheme;
|
|
1070
|
+
throw new AbstractionKitError("BAD_DATA", buildMismatchMessage({
|
|
1071
|
+
accountName: context.accountName,
|
|
1072
|
+
signerIndex: context.signerIndex,
|
|
1073
|
+
signerAddress: signer.address,
|
|
1074
|
+
accepted,
|
|
1075
|
+
signerCan
|
|
1076
|
+
}));
|
|
977
1077
|
}
|
|
978
1078
|
function buildMismatchMessage(params) {
|
|
979
1079
|
const { accountName, signerIndex, signerAddress, accepted, signerCan } = params;
|
|
@@ -983,7 +1083,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
983
1083
|
/**
|
|
984
1084
|
* Invoke a signer for one scheme. Keeps the dispatch in one place so the
|
|
985
1085
|
* account-side code stays linear. `typedData` is optional: accounts that
|
|
986
|
-
* only accept the `"hash"` scheme
|
|
1086
|
+
* only accept the `"hash"` scheme can pass just `hash`.
|
|
987
1087
|
*
|
|
988
1088
|
* `context` is always forwarded to the signer so power-user implementations
|
|
989
1089
|
* can inspect the userOp.
|
|
@@ -1206,45 +1306,540 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1206
1306
|
}
|
|
1207
1307
|
return encoded_access_list;
|
|
1208
1308
|
}
|
|
1209
|
-
/** Converts a bigint to a Uint8Array of its big-endian byte representation. */
|
|
1210
|
-
function bigintToBytes(bi) {
|
|
1211
|
-
return (0, ethers.getBytes)((0, ethers.toBeArray)(bi));
|
|
1309
|
+
/** Converts a bigint to a Uint8Array of its big-endian byte representation. */
|
|
1310
|
+
function bigintToBytes(bi) {
|
|
1311
|
+
return (0, ethers.getBytes)((0, ethers.toBeArray)(bi));
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Parse a raw ECDSA signature into its components.
|
|
1315
|
+
* Supports standard 65-byte (r + s + v) and EIP-2098 64-byte compact formats.
|
|
1316
|
+
* @param rawSig - Hex string: 128 chars (EIP-2098 compact), or 130/132 chars (standard with 0x prefix)
|
|
1317
|
+
* @returns An object with yParity (0 or 1), r, and s components
|
|
1318
|
+
*/
|
|
1319
|
+
function parseRawSignature(rawSig) {
|
|
1320
|
+
const sig = rawSig.startsWith("0x") ? rawSig.slice(2) : rawSig;
|
|
1321
|
+
if (sig.length !== 128 && sig.length !== 130) throw new RangeError(`invalid signature length: expected 128 (EIP-2098 compact) or 130 (standard) hex chars, got ${sig.length}`);
|
|
1322
|
+
const r = BigInt(`0x${sig.slice(0, 64)}`);
|
|
1323
|
+
if (sig.length === 128) {
|
|
1324
|
+
const yParityAndS = BigInt(`0x${sig.slice(64, 128)}`);
|
|
1325
|
+
return {
|
|
1326
|
+
yParity: Number(yParityAndS >> 255n & 1n),
|
|
1327
|
+
r,
|
|
1328
|
+
s: yParityAndS & (1n << 255n) - 1n
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
const s = BigInt(`0x${sig.slice(64, 128)}`);
|
|
1332
|
+
const v = parseInt(sig.slice(128, 130), 16);
|
|
1333
|
+
if (v !== 0 && v !== 1 && v !== 27 && v !== 28) throw new RangeError(`invalid signature v value: ${v}`);
|
|
1334
|
+
return {
|
|
1335
|
+
yParity: v >= 27 ? v - 27 : v,
|
|
1336
|
+
r,
|
|
1337
|
+
s
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Converts a bigint to a 0x-prefixed hex string with even-length padding.
|
|
1342
|
+
* @param value - The bigint value to convert.
|
|
1343
|
+
* @returns The hex string representation (e.g., "0x01", "0xff").
|
|
1344
|
+
*/
|
|
1345
|
+
function bigintToHex(value) {
|
|
1346
|
+
const hex = value.toString(16);
|
|
1347
|
+
return hex.length % 2 ? `0x0${hex}` : `0x${hex}`;
|
|
1348
|
+
}
|
|
1349
|
+
//#endregion
|
|
1350
|
+
//#region src/utils.ts
|
|
1351
|
+
function buildDomainSeparator(chainId, entrypoint) {
|
|
1352
|
+
return (0, ethers.keccak256)(ethers.AbiCoder.defaultAbiCoder().encode(["(bytes32,bytes32,bytes32,uint256,address)"], [[
|
|
1353
|
+
"0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f",
|
|
1354
|
+
"0x364da28a5c92bcc87fe97c8813a6c6b8a3a049b0ea0a328fcb0b4f0e00337586",
|
|
1355
|
+
"0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6",
|
|
1356
|
+
chainId,
|
|
1357
|
+
entrypoint
|
|
1358
|
+
]]));
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Compute the UserOperation hash for any supported EntryPoint version.
|
|
1362
|
+
* This hash is what gets signed by the account owner(s).
|
|
1363
|
+
* Automatically selects the correct packing format based on the entrypoint address.
|
|
1364
|
+
*
|
|
1365
|
+
* @param useroperation - UserOperation to hash
|
|
1366
|
+
* @param entrypointAddress - EntryPoint contract address (determines hash format)
|
|
1367
|
+
* @param chainId - Target chain ID
|
|
1368
|
+
* @returns The UserOperation hash as a hex string
|
|
1369
|
+
*/
|
|
1370
|
+
function createUserOperationHash(useroperation, entrypointAddress, chainId) {
|
|
1371
|
+
let packedUserOperationHash;
|
|
1372
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1373
|
+
let userOperationHash;
|
|
1374
|
+
if (entrypointAddress.toLowerCase() === "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".toLowerCase()) {
|
|
1375
|
+
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV6(useroperation));
|
|
1376
|
+
userOperationHash = (0, ethers.keccak256)(abiCoder.encode([
|
|
1377
|
+
"bytes32",
|
|
1378
|
+
"address",
|
|
1379
|
+
"uint256"
|
|
1380
|
+
], [
|
|
1381
|
+
packedUserOperationHash,
|
|
1382
|
+
entrypointAddress,
|
|
1383
|
+
chainId
|
|
1384
|
+
]));
|
|
1385
|
+
} else if (entrypointAddress.toLowerCase() === "0x0000000071727De22E5E9d8BAf0edAc6f37da032".toLowerCase()) {
|
|
1386
|
+
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV7(useroperation));
|
|
1387
|
+
userOperationHash = (0, ethers.keccak256)(abiCoder.encode([
|
|
1388
|
+
"bytes32",
|
|
1389
|
+
"address",
|
|
1390
|
+
"uint256"
|
|
1391
|
+
], [
|
|
1392
|
+
packedUserOperationHash,
|
|
1393
|
+
entrypointAddress,
|
|
1394
|
+
chainId
|
|
1395
|
+
]));
|
|
1396
|
+
} else if (entrypointAddress.toLowerCase() === "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108".toLowerCase()) {
|
|
1397
|
+
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV8(useroperation));
|
|
1398
|
+
userOperationHash = (0, ethers.keccak256)(`0x1901${buildDomainSeparator(chainId, entrypointAddress).slice(2)}${packedUserOperationHash.slice(2)}`);
|
|
1399
|
+
} else if (entrypointAddress.toLowerCase() === "0x433709009B8330FDa32311DF1C2AFA402eD8D009".toLowerCase()) {
|
|
1400
|
+
packedUserOperationHash = (0, ethers.keccak256)(createPackedUserOperationV9(useroperation));
|
|
1401
|
+
userOperationHash = (0, ethers.keccak256)(`0x1901${buildDomainSeparator(chainId, entrypointAddress).slice(2)}${packedUserOperationHash.slice(2)}`);
|
|
1402
|
+
} else throw new RangeError(`unsupported entrypoint address: ${entrypointAddress}`);
|
|
1403
|
+
return userOperationHash;
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* @internal
|
|
1407
|
+
* Reconstruct the packed `initCode` field for an EntryPoint v0.8/v0.9
|
|
1408
|
+
* UserOperation. When `eip7702Auth.address` is set, the EIP-7702 delegatee
|
|
1409
|
+
* address replaces the factory address in initCode (only `factoryData` is
|
|
1410
|
+
* concatenated). Otherwise, behaves like v0.7 (`factory + factoryData`).
|
|
1411
|
+
*
|
|
1412
|
+
* Shared by {@link createPackedUserOperationV8} /
|
|
1413
|
+
* {@link createPackedUserOperationV9} and Simple7702Account's typed-data
|
|
1414
|
+
* builder. Not part of the public API; only `export`ed for cross-module
|
|
1415
|
+
* use within the package and not re-exported from `src/abstractionkit.ts`.
|
|
1416
|
+
*
|
|
1417
|
+
* @param useroperation - V8 or V9 UserOperation to read fields from
|
|
1418
|
+
* @returns Hex-encoded initCode
|
|
1419
|
+
*/
|
|
1420
|
+
function buildPackedInitCodeV8V9(useroperation) {
|
|
1421
|
+
if (useroperation.factory == null) return "0x";
|
|
1422
|
+
const eip7702Auth = useroperation.eip7702Auth;
|
|
1423
|
+
return (eip7702Auth != null && eip7702Auth.address != null ? eip7702Auth.address : useroperation.factory) + (useroperation.factoryData != null ? useroperation.factoryData.slice(2) : "");
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* @internal
|
|
1427
|
+
* Pack `(verificationGasLimit, callGasLimit)` into a single `bytes32`
|
|
1428
|
+
* (two uint128 values, big-endian). Matches the on-chain
|
|
1429
|
+
* `PackedUserOperation.accountGasLimits` layout used by EntryPoint v0.7+.
|
|
1430
|
+
*/
|
|
1431
|
+
function packAccountGasLimits(verificationGasLimit, callGasLimit) {
|
|
1432
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1433
|
+
return "0x" + abiCoder.encode(["uint128"], [verificationGasLimit]).slice(34) + abiCoder.encode(["uint128"], [callGasLimit]).slice(34);
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* @internal
|
|
1437
|
+
* Pack `(maxPriorityFeePerGas, maxFeePerGas)` into a single `bytes32`
|
|
1438
|
+
* (two uint128 values, big-endian). Matches the on-chain
|
|
1439
|
+
* `PackedUserOperation.gasFees` layout used by EntryPoint v0.7+.
|
|
1440
|
+
*/
|
|
1441
|
+
function packGasFees(maxPriorityFeePerGas, maxFeePerGas) {
|
|
1442
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1443
|
+
return "0x" + abiCoder.encode(["uint128"], [maxPriorityFeePerGas]).slice(34) + abiCoder.encode(["uint128"], [maxFeePerGas]).slice(34);
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* @internal
|
|
1447
|
+
* Reconstruct the packed `paymasterAndData` field from a UserOperation's
|
|
1448
|
+
* separate paymaster fields. Returns `0x` when no paymaster is set.
|
|
1449
|
+
*
|
|
1450
|
+
* For EntryPoint v0.9, when `paymasterData` ends with the parallel-paymaster
|
|
1451
|
+
* signature magic suffix (`0x22e325a297439656`), the embedded signature is
|
|
1452
|
+
* stripped so the userOpHash does not commit to the paymaster's signature
|
|
1453
|
+
* over itself. Pass `stripV9PaymasterSig=false` to preserve the wire format.
|
|
1454
|
+
*
|
|
1455
|
+
* Shared by v7/v8/v9 packers and Simple7702Account's typed-data builder.
|
|
1456
|
+
* Not part of the public API; only `export`ed for cross-module use within
|
|
1457
|
+
* the package and not re-exported from `src/abstractionkit.ts`.
|
|
1458
|
+
*
|
|
1459
|
+
* @param useroperation - V7/V8/V9 UserOperation to read fields from
|
|
1460
|
+
* @param stripV9PaymasterSig - Whether to strip the v0.9 paymaster signature suffix
|
|
1461
|
+
* @returns Hex-encoded paymasterAndData
|
|
1462
|
+
*/
|
|
1463
|
+
function buildPaymasterAndData(useroperation, stripV9PaymasterSig = false) {
|
|
1464
|
+
if (useroperation.paymaster == null) return "0x";
|
|
1465
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1466
|
+
let paymasterAndData = useroperation.paymaster;
|
|
1467
|
+
if (useroperation.paymasterVerificationGasLimit != null) paymasterAndData += abiCoder.encode(["uint128"], [useroperation.paymasterVerificationGasLimit]).slice(34);
|
|
1468
|
+
if (useroperation.paymasterPostOpGasLimit != null) paymasterAndData += abiCoder.encode(["uint128"], [useroperation.paymasterPostOpGasLimit]).slice(34);
|
|
1469
|
+
if (useroperation.paymasterData != null) {
|
|
1470
|
+
const PAYMASTER_SIG_MAGIC = "22e325a297439656";
|
|
1471
|
+
if (stripV9PaymasterSig && useroperation.paymasterData.toLowerCase().endsWith(PAYMASTER_SIG_MAGIC)) {
|
|
1472
|
+
const sigLenHex = useroperation.paymasterData.slice(useroperation.paymasterData.length - 16 - 4, useroperation.paymasterData.length - 16);
|
|
1473
|
+
const sigLen = parseInt(sigLenHex, 16);
|
|
1474
|
+
const prefixEnd = useroperation.paymasterData.length - 16 - 4 - sigLen * 2;
|
|
1475
|
+
paymasterAndData += useroperation.paymasterData.slice(0, prefixEnd).replaceAll("0x", "") + PAYMASTER_SIG_MAGIC;
|
|
1476
|
+
} else paymasterAndData += useroperation.paymasterData.slice(2);
|
|
1477
|
+
}
|
|
1478
|
+
return paymasterAndData;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Build the EIP-712 typed data payload for a UserOperation under the
|
|
1482
|
+
* EntryPoint v0.8 / v0.9 domain. The digest of the returned payload equals
|
|
1483
|
+
* the `userOpHash` from {@link createUserOperationHash}, so signing it via
|
|
1484
|
+
* `signTypedData` produces a signature that validates against the same hash
|
|
1485
|
+
* as raw ECDSA over the `userOpHash`.
|
|
1486
|
+
*
|
|
1487
|
+
* Shared by EIP-7702 accounts (Simple7702, Calibur). Earlier EntryPoints
|
|
1488
|
+
* define the userOpHash differently and don't fit this typed-data shape.
|
|
1489
|
+
*
|
|
1490
|
+
* @param userOperation - Unsigned UserOperation to wrap
|
|
1491
|
+
* @param entrypointAddress - The EntryPoint contract address (must be v0.8 or v0.9)
|
|
1492
|
+
* @param chainId - Target chain ID (must match the chain that will validate the signature)
|
|
1493
|
+
* @returns EIP-712 {@link TypedData} payload ready for `signTypedData`
|
|
1494
|
+
* @throws {AbstractionKitError} if `entrypointAddress` is not v0.8 / v0.9
|
|
1495
|
+
*/
|
|
1496
|
+
function getUserOperationEip712DataV8V9(userOperation, entrypointAddress, chainId) {
|
|
1497
|
+
const ep = entrypointAddress.toLowerCase();
|
|
1498
|
+
const isV9 = ep === ENTRYPOINT_V9.toLowerCase();
|
|
1499
|
+
if (ep !== "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108".toLowerCase() && !isV9) throw new AbstractionKitError("BAD_DATA", `getUserOperationEip712Data supports EntryPoint v0.8 / v0.9 only; got ${entrypointAddress}. Earlier EntryPoints define the userOpHash differently and require raw-hash signing.`);
|
|
1500
|
+
const initCode = buildPackedInitCodeV8V9(userOperation);
|
|
1501
|
+
const accountGasLimits = packAccountGasLimits(userOperation.verificationGasLimit, userOperation.callGasLimit);
|
|
1502
|
+
const gasFees = packGasFees(userOperation.maxPriorityFeePerGas, userOperation.maxFeePerGas);
|
|
1503
|
+
const paymasterAndData = buildPaymasterAndData(userOperation, isV9);
|
|
1504
|
+
return {
|
|
1505
|
+
domain: {
|
|
1506
|
+
name: "ERC4337",
|
|
1507
|
+
version: "1",
|
|
1508
|
+
chainId,
|
|
1509
|
+
verifyingContract: entrypointAddress
|
|
1510
|
+
},
|
|
1511
|
+
types: { PackedUserOperation: [
|
|
1512
|
+
{
|
|
1513
|
+
name: "sender",
|
|
1514
|
+
type: "address"
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
name: "nonce",
|
|
1518
|
+
type: "uint256"
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
name: "initCode",
|
|
1522
|
+
type: "bytes"
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
name: "callData",
|
|
1526
|
+
type: "bytes"
|
|
1527
|
+
},
|
|
1528
|
+
{
|
|
1529
|
+
name: "accountGasLimits",
|
|
1530
|
+
type: "bytes32"
|
|
1531
|
+
},
|
|
1532
|
+
{
|
|
1533
|
+
name: "preVerificationGas",
|
|
1534
|
+
type: "uint256"
|
|
1535
|
+
},
|
|
1536
|
+
{
|
|
1537
|
+
name: "gasFees",
|
|
1538
|
+
type: "bytes32"
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
name: "paymasterAndData",
|
|
1542
|
+
type: "bytes"
|
|
1543
|
+
}
|
|
1544
|
+
] },
|
|
1545
|
+
primaryType: "PackedUserOperation",
|
|
1546
|
+
message: {
|
|
1547
|
+
sender: userOperation.sender,
|
|
1548
|
+
nonce: userOperation.nonce,
|
|
1549
|
+
initCode,
|
|
1550
|
+
callData: userOperation.callData,
|
|
1551
|
+
accountGasLimits,
|
|
1552
|
+
preVerificationGas: userOperation.preVerificationGas,
|
|
1553
|
+
gasFees,
|
|
1554
|
+
paymasterAndData
|
|
1555
|
+
}
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* Compute the EIP-712 digest of a UserOperation under the EntryPoint
|
|
1560
|
+
* v0.8 / v0.9 domain. For these EntryPoints this digest IS the
|
|
1561
|
+
* `userOpHash` ({@link createUserOperationHash}).
|
|
1562
|
+
*
|
|
1563
|
+
* @param userOperation - Unsigned UserOperation to hash
|
|
1564
|
+
* @param entrypointAddress - The EntryPoint contract address (must be v0.8 or v0.9)
|
|
1565
|
+
* @param chainId - Target chain ID
|
|
1566
|
+
* @returns The EIP-712 digest as a hex string
|
|
1567
|
+
* @throws {AbstractionKitError} if `entrypointAddress` is not v0.8 / v0.9
|
|
1568
|
+
*/
|
|
1569
|
+
function getUserOperationEip712HashV8V9(userOperation, entrypointAddress, chainId) {
|
|
1570
|
+
const data = getUserOperationEip712DataV8V9(userOperation, entrypointAddress, chainId);
|
|
1571
|
+
return ethers.TypedDataEncoder.hash(data.domain, data.types, data.message);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* ABI-encode and pack a UserOperation for hashing (EntryPoint v0.6 format).
|
|
1575
|
+
* Bytes fields (initCode, callData, paymasterAndData) are keccak256-hashed before packing.
|
|
1576
|
+
*
|
|
1577
|
+
* @param useroperation - UserOperation to pack
|
|
1578
|
+
* @returns ABI-encoded packed UserOperation as a hex string
|
|
1579
|
+
*/
|
|
1580
|
+
function createPackedUserOperationV6(useroperation) {
|
|
1581
|
+
const useroperationValuesArrayWithHashedByteValues = [
|
|
1582
|
+
useroperation.sender,
|
|
1583
|
+
useroperation.nonce,
|
|
1584
|
+
(0, ethers.keccak256)(useroperation.initCode),
|
|
1585
|
+
(0, ethers.keccak256)(useroperation.callData),
|
|
1586
|
+
useroperation.callGasLimit,
|
|
1587
|
+
useroperation.verificationGasLimit,
|
|
1588
|
+
useroperation.preVerificationGas,
|
|
1589
|
+
useroperation.maxFeePerGas,
|
|
1590
|
+
useroperation.maxPriorityFeePerGas,
|
|
1591
|
+
(0, ethers.keccak256)(useroperation.paymasterAndData)
|
|
1592
|
+
];
|
|
1593
|
+
return ethers.AbiCoder.defaultAbiCoder().encode([
|
|
1594
|
+
"address",
|
|
1595
|
+
"uint256",
|
|
1596
|
+
"bytes32",
|
|
1597
|
+
"bytes32",
|
|
1598
|
+
"uint256",
|
|
1599
|
+
"uint256",
|
|
1600
|
+
"uint256",
|
|
1601
|
+
"uint256",
|
|
1602
|
+
"uint256",
|
|
1603
|
+
"bytes32"
|
|
1604
|
+
], useroperationValuesArrayWithHashedByteValues);
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* ABI-encode and pack a UserOperation for hashing (EntryPoint v0.7 format).
|
|
1608
|
+
* Reconstructs initCode, accountGasLimits, gasFees, and paymasterAndData from separate fields.
|
|
1609
|
+
*
|
|
1610
|
+
* @param useroperation - UserOperation to pack
|
|
1611
|
+
* @returns ABI-encoded packed UserOperation as a hex string
|
|
1612
|
+
*/
|
|
1613
|
+
function createPackedUserOperationV7(useroperation) {
|
|
1614
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1615
|
+
let initCode = "0x";
|
|
1616
|
+
if (useroperation.factory != null) {
|
|
1617
|
+
initCode = useroperation.factory;
|
|
1618
|
+
if (useroperation.factoryData != null) initCode += useroperation.factoryData.slice(2);
|
|
1619
|
+
}
|
|
1620
|
+
const accountGasLimits = packAccountGasLimits(useroperation.verificationGasLimit, useroperation.callGasLimit);
|
|
1621
|
+
const gasFees = packGasFees(useroperation.maxPriorityFeePerGas, useroperation.maxFeePerGas);
|
|
1622
|
+
const paymasterAndData = buildPaymasterAndData(useroperation);
|
|
1623
|
+
const useroperationValuesArrayWithHashedByteValues = [
|
|
1624
|
+
useroperation.sender,
|
|
1625
|
+
useroperation.nonce,
|
|
1626
|
+
(0, ethers.keccak256)(initCode),
|
|
1627
|
+
(0, ethers.keccak256)(useroperation.callData),
|
|
1628
|
+
accountGasLimits,
|
|
1629
|
+
useroperation.preVerificationGas,
|
|
1630
|
+
gasFees,
|
|
1631
|
+
(0, ethers.keccak256)(paymasterAndData)
|
|
1632
|
+
];
|
|
1633
|
+
return abiCoder.encode([
|
|
1634
|
+
"address",
|
|
1635
|
+
"uint256",
|
|
1636
|
+
"bytes32",
|
|
1637
|
+
"bytes32",
|
|
1638
|
+
"bytes32",
|
|
1639
|
+
"uint256",
|
|
1640
|
+
"bytes32",
|
|
1641
|
+
"bytes32"
|
|
1642
|
+
], useroperationValuesArrayWithHashedByteValues);
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* ABI-encode and pack a UserOperation for hashing (EntryPoint v0.9 format).
|
|
1646
|
+
*
|
|
1647
|
+
* @param useroperation - UserOperation to pack
|
|
1648
|
+
* @returns ABI-encoded packed UserOperation as a hex string
|
|
1649
|
+
*/
|
|
1650
|
+
function createPackedUserOperationV9(useroperation) {
|
|
1651
|
+
return baseCreatePackedUserOperationV8V9(useroperation, true);
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* ABI-encode and pack a UserOperation for hashing (EntryPoint v0.8 format).
|
|
1655
|
+
*
|
|
1656
|
+
* @param useroperation - UserOperation to pack
|
|
1657
|
+
* @returns ABI-encoded packed UserOperation as a hex string
|
|
1658
|
+
*/
|
|
1659
|
+
function createPackedUserOperationV8(useroperation) {
|
|
1660
|
+
return baseCreatePackedUserOperationV8V9(useroperation, false);
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Shared packer for EntryPoint v0.8 and v0.9 UserOperations.
|
|
1664
|
+
* @param useroperation - UserOperation to pack
|
|
1665
|
+
* @param is_v9 - If true, strips the paymaster signature suffix (v0.9-specific)
|
|
1666
|
+
* @returns ABI-encoded packed UserOperation as a hex string
|
|
1667
|
+
*/
|
|
1668
|
+
function baseCreatePackedUserOperationV8V9(useroperation, is_v9) {
|
|
1669
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1670
|
+
const initCode = buildPackedInitCodeV8V9(useroperation);
|
|
1671
|
+
const accountGasLimits = packAccountGasLimits(useroperation.verificationGasLimit, useroperation.callGasLimit);
|
|
1672
|
+
const gasFees = packGasFees(useroperation.maxPriorityFeePerGas, useroperation.maxFeePerGas);
|
|
1673
|
+
const paymasterAndData = buildPaymasterAndData(useroperation, is_v9);
|
|
1674
|
+
const useroperationValuesArrayWithHashedByteValues = [
|
|
1675
|
+
"0x29a0bca4af4be3421398da00295e58e6d7de38cb492214754cb6a47507dd6f8e",
|
|
1676
|
+
useroperation.sender,
|
|
1677
|
+
useroperation.nonce,
|
|
1678
|
+
(0, ethers.keccak256)(initCode),
|
|
1679
|
+
(0, ethers.keccak256)(useroperation.callData),
|
|
1680
|
+
accountGasLimits,
|
|
1681
|
+
useroperation.preVerificationGas,
|
|
1682
|
+
gasFees,
|
|
1683
|
+
(0, ethers.keccak256)(paymasterAndData)
|
|
1684
|
+
];
|
|
1685
|
+
return abiCoder.encode([
|
|
1686
|
+
"bytes32",
|
|
1687
|
+
"address",
|
|
1688
|
+
"uint256",
|
|
1689
|
+
"bytes32",
|
|
1690
|
+
"bytes32",
|
|
1691
|
+
"bytes32",
|
|
1692
|
+
"uint256",
|
|
1693
|
+
"bytes32",
|
|
1694
|
+
"bytes32"
|
|
1695
|
+
], useroperationValuesArrayWithHashedByteValues);
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Encode a function call into ABI-encoded calldata.
|
|
1699
|
+
*
|
|
1700
|
+
* @param functionSelector - 4-byte hex function selector (e.g., "0xa9059cbb" for ERC-20 transfer)
|
|
1701
|
+
* @param functionInputAbi - Array of ABI type strings (e.g., ["address", "uint256"])
|
|
1702
|
+
* @param functionInputParameters - Array of parameter values matching the ABI types
|
|
1703
|
+
* @returns ABI-encoded calldata as a hex string (selector + encoded parameters)
|
|
1704
|
+
*
|
|
1705
|
+
* @example
|
|
1706
|
+
* const transferCallData = createCallData(
|
|
1707
|
+
* "0xa9059cbb",
|
|
1708
|
+
* ["address", "uint256"],
|
|
1709
|
+
* ["0xRecipientAddress", 1000000n],
|
|
1710
|
+
* );
|
|
1711
|
+
*/
|
|
1712
|
+
function createCallData(functionSelector, functionInputAbi, functionInputParameters) {
|
|
1713
|
+
return functionSelector + ethers.AbiCoder.defaultAbiCoder().encode(functionInputAbi, functionInputParameters).slice(2);
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Send a JSON-RPC 2.0 request to the specified endpoint.
|
|
1717
|
+
*
|
|
1718
|
+
* **External escape hatch.** Most SDK consumers should use one of the
|
|
1719
|
+
* high-level service classes ({@link Bundler}, {@link CandidePaymaster},
|
|
1720
|
+
* {@link Erc7677Paymaster}, {@link JsonRpcNode}) which translate errors into
|
|
1721
|
+
* the SDK's domain vocabulary. This function is intentionally low-level: it
|
|
1722
|
+
* speaks plain JSON-RPC and throws {@link TransportRpcError}
|
|
1723
|
+
* (an EIP-1193-shaped `ProviderRpcError`) on RPC errors.
|
|
1724
|
+
*
|
|
1725
|
+
* Two execution modes:
|
|
1726
|
+
* - **URL string:** issues a `fetch` POST directly. Supports custom `headers`
|
|
1727
|
+
* and a custom `paramsKeyName` for non-standard servers (e.g. APIs that
|
|
1728
|
+
* expect `"simulations"` instead of `"params"`).
|
|
1729
|
+
* - **Transport / JsonRpcNode:** delegates to `.request({ method, params })`.
|
|
1730
|
+
* `headers` and `paramsKeyName` are ignored (those concerns belong to the
|
|
1731
|
+
* transport implementation).
|
|
1732
|
+
*
|
|
1733
|
+
* Automatically serializes `bigint` values in `params` as `0x`-prefixed hex.
|
|
1734
|
+
*
|
|
1735
|
+
* @param rpc - JSON-RPC endpoint URL, {@link Transport}, or {@link JsonRpcNode}
|
|
1736
|
+
* @param method - The JSON-RPC method name (e.g., `"eth_call"`)
|
|
1737
|
+
* @param params - The JSON-RPC parameters
|
|
1738
|
+
* @param headers - Custom HTTP headers (URL inputs only; default Content-Type: application/json)
|
|
1739
|
+
* @param paramsKeyName - Override the params key in the envelope (URL inputs only; default `"params"`)
|
|
1740
|
+
* @returns The `result` (or non-standard equivalent) field from the JSON-RPC response
|
|
1741
|
+
* @throws {@link TransportRpcError} when the response contains an `error` field
|
|
1742
|
+
*/
|
|
1743
|
+
async function sendJsonRpcRequest(rpc, method, params, headers = { "Content-Type": "application/json" }, paramsKeyName = "params") {
|
|
1744
|
+
const normalizedParams = JSON.parse(JSON.stringify(params, (_key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value));
|
|
1745
|
+
if (typeof rpc !== "string") return JsonRpcNode.from(rpc).request({
|
|
1746
|
+
method,
|
|
1747
|
+
params: normalizedParams
|
|
1748
|
+
});
|
|
1749
|
+
const raw = JSON.stringify({
|
|
1750
|
+
method,
|
|
1751
|
+
[paramsKeyName]: normalizedParams,
|
|
1752
|
+
id: Date.now(),
|
|
1753
|
+
jsonrpc: "2.0"
|
|
1754
|
+
});
|
|
1755
|
+
const response = await (await fetch(rpc, {
|
|
1756
|
+
method: "POST",
|
|
1757
|
+
headers,
|
|
1758
|
+
body: raw,
|
|
1759
|
+
redirect: "follow"
|
|
1760
|
+
})).json();
|
|
1761
|
+
if ("result" in response) return response.result;
|
|
1762
|
+
const err = response.error;
|
|
1763
|
+
throw new TransportRpcError(err.code, err.message);
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Get a 4-byte function selector from a Solidity-style function signature.
|
|
1767
|
+
* Computed as the first 4 bytes of keccak256(signature).
|
|
1768
|
+
* @param functionSignature - Solidity-style function signature, e.g. "mint(address)"
|
|
1769
|
+
* @returns Function selector as a 0x-prefixed 10-character hex string
|
|
1770
|
+
*
|
|
1771
|
+
* @example
|
|
1772
|
+
* getFunctionSelector("getNonce(address,uint192)"); // "0x35567e1a"
|
|
1773
|
+
*/
|
|
1774
|
+
function getFunctionSelector(functionSignature) {
|
|
1775
|
+
return (0, ethers.id)(functionSignature).slice(0, 10);
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Fetch the account's nonce from the EntryPoint contract.
|
|
1779
|
+
*
|
|
1780
|
+
* Equivalent to `JsonRpcNode.from(rpc).getEntryPointNonce(entryPoint, account, key)`.
|
|
1781
|
+
* Kept as a top-level export for backward compatibility with existing call
|
|
1782
|
+
* sites; the first parameter widens from `string` to
|
|
1783
|
+
* `string | Transport | JsonRpcNode` so users can pass a configured transport
|
|
1784
|
+
* (with custom headers, retries, etc.) without restructuring their code.
|
|
1785
|
+
*
|
|
1786
|
+
* @param rpc - Ethereum JSON-RPC node URL, {@link Transport}, or {@link JsonRpcNode}
|
|
1787
|
+
* @param entryPoint - EntryPoint contract address
|
|
1788
|
+
* @param account - Smart account address to query
|
|
1789
|
+
* @param key - Nonce key (default 0). Different keys allow parallel nonce channels.
|
|
1790
|
+
* @returns The current nonce as a bigint
|
|
1791
|
+
*/
|
|
1792
|
+
async function fetchAccountNonce(rpc, entryPoint, account, key = 0) {
|
|
1793
|
+
return JsonRpcNode.from(rpc).getEntryPointNonce(entryPoint, account, BigInt(key));
|
|
1212
1794
|
}
|
|
1213
1795
|
/**
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
* @param
|
|
1217
|
-
* @
|
|
1796
|
+
* Fetch current gas prices from the Polygon Gas Station API.
|
|
1797
|
+
*
|
|
1798
|
+
* @param polygonChain - Target Polygon chain (Mainnet, Amoy, etc.)
|
|
1799
|
+
* @param gasLevel - Gas price level (Slow, Medium, Fast)
|
|
1800
|
+
* @returns A tuple of [maxFeePerGas, maxPriorityFeePerGas] as bigints
|
|
1218
1801
|
*/
|
|
1219
|
-
function
|
|
1220
|
-
const
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1802
|
+
async function fetchGasPricePolygon(polygonChain, gasLevel = GasOption.Medium) {
|
|
1803
|
+
const gasStationUrl = `https://gasstation.polygon.technology/${polygonChain}`;
|
|
1804
|
+
try {
|
|
1805
|
+
const response = await (await fetch(gasStationUrl)).json();
|
|
1806
|
+
let gasPrice;
|
|
1807
|
+
if (gasLevel === GasOption.Slow) gasPrice = response.safeLow;
|
|
1808
|
+
else if (gasLevel === GasOption.Medium) gasPrice = response.standard;
|
|
1809
|
+
else gasPrice = response.fast;
|
|
1810
|
+
let maxFeePerGas = BigInt(Math.ceil(Number(gasPrice.maxFee) * 1e9));
|
|
1811
|
+
let maxPriorityFeePerGas = BigInt(Math.ceil(Number(gasPrice.maxPriorityFee) * 1e9));
|
|
1812
|
+
if (maxFeePerGas === 0n) maxFeePerGas = 1n;
|
|
1813
|
+
if (maxPriorityFeePerGas === 0n) maxPriorityFeePerGas = 1n;
|
|
1814
|
+
return [maxFeePerGas, maxPriorityFeePerGas];
|
|
1815
|
+
} catch (err) {
|
|
1816
|
+
const error = ensureError(err);
|
|
1817
|
+
throw new AbstractionKitError("BAD_DATA", `fetching gas prices from ${gasStationUrl} failed.`, { cause: error });
|
|
1230
1818
|
}
|
|
1231
|
-
const s = BigInt(`0x${sig.slice(64, 128)}`);
|
|
1232
|
-
const v = parseInt(sig.slice(128, 130), 16);
|
|
1233
|
-
if (v !== 0 && v !== 1 && v !== 27 && v !== 28) throw new RangeError(`invalid signature v value: ${v}`);
|
|
1234
|
-
return {
|
|
1235
|
-
yParity: v >= 27 ? v - 27 : v,
|
|
1236
|
-
r,
|
|
1237
|
-
s
|
|
1238
|
-
};
|
|
1239
1819
|
}
|
|
1240
1820
|
/**
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1821
|
+
* Calculate the maximum gas cost (in wei) that a UserOperation could consume.
|
|
1822
|
+
* Uses different formulas for v0.6 (with paymaster multiplier) and v0.7+ UserOperations.
|
|
1823
|
+
*
|
|
1824
|
+
* @param useroperation - The UserOperation to calculate the max gas cost for
|
|
1825
|
+
* @returns Maximum possible gas cost in wei as a bigint
|
|
1244
1826
|
*/
|
|
1245
|
-
function
|
|
1246
|
-
|
|
1247
|
-
|
|
1827
|
+
function calculateUserOperationMaxGasCost(useroperation) {
|
|
1828
|
+
if ("initCode" in useroperation) {
|
|
1829
|
+
const mul = useroperation.paymasterAndData !== "0x" && useroperation.paymasterAndData != null ? 3n : 0n;
|
|
1830
|
+
return (useroperation.callGasLimit + useroperation.verificationGasLimit * mul + useroperation.preVerificationGas) * useroperation.maxFeePerGas;
|
|
1831
|
+
} else return (useroperation.verificationGasLimit + useroperation.callGasLimit + (useroperation.paymasterVerificationGasLimit ?? 0n) + (useroperation.paymasterPostOpGasLimit ?? 0n) + useroperation.preVerificationGas) * useroperation.maxFeePerGas;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* @internal
|
|
1835
|
+
* Internal dispatcher: routes to the Polygon Gas Station when a chain is
|
|
1836
|
+
* provided, otherwise delegates to {@link JsonRpcNode.getFeeData}. Used by
|
|
1837
|
+
* the account classes when assembling base UserOperation gas fields.
|
|
1838
|
+
*/
|
|
1839
|
+
async function handlefetchGasPrice(providerRpc, polygonGasStation, gasLevel = GasOption.Medium) {
|
|
1840
|
+
if (polygonGasStation != null) return fetchGasPricePolygon(polygonGasStation, gasLevel);
|
|
1841
|
+
if (providerRpc != null) return JsonRpcNode.from(providerRpc).getFeeData(gasLevel);
|
|
1842
|
+
throw new AbstractionKitError("BAD_DATA", "providerRpc can't be null if maxFeePerGas and maxPriorityFeePerGas are not overridden");
|
|
1248
1843
|
}
|
|
1249
1844
|
//#endregion
|
|
1250
1845
|
//#region src/account/SendUseroperationResponse.ts
|
|
@@ -1452,6 +2047,29 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1452
2047
|
hookData
|
|
1453
2048
|
]);
|
|
1454
2049
|
}
|
|
2050
|
+
/**
|
|
2051
|
+
* Format a raw EIP-712 signature (from `signTypedData` over the payload
|
|
2052
|
+
* returned by {@link getUserOperationEip712Data}) into Calibur's
|
|
2053
|
+
* `userOp.signature` layout. Provided for API parity with Safe's
|
|
2054
|
+
* `formatEip712SingleSignatureToUseroperationSignature`.
|
|
2055
|
+
*
|
|
2056
|
+
* Under EntryPoint v0.8 / v0.9 the userOpHash IS the EIP-712 digest of
|
|
2057
|
+
* the PackedUserOperation, so a raw-hash signature and a typed-data
|
|
2058
|
+
* signature are byte-identical for deterministic-ECDSA signers; this
|
|
2059
|
+
* method is therefore equivalent to {@link wrapSignature} with the same
|
|
2060
|
+
* `keyHash` / `hookData`. The default `keyHash` is the root-key hash
|
|
2061
|
+
* (`bytes32(0)`), which selects the EOA's own secp256k1 key.
|
|
2062
|
+
*
|
|
2063
|
+
* @param signature - Raw ECDSA signature (65 bytes, hex-encoded) from
|
|
2064
|
+
* `signTypedData` over the payload from {@link getUserOperationEip712Data}
|
|
2065
|
+
* @param overrides - Optional `keyHash` / `hookData` overrides
|
|
2066
|
+
* @returns Hex-encoded wrapped signature ready for `userOp.signature`
|
|
2067
|
+
*/
|
|
2068
|
+
static formatEip712SingleSignatureToUseroperationSignature(signature, overrides = {}) {
|
|
2069
|
+
const keyHash = overrides.keyHash ?? ROOT_KEY_HASH;
|
|
2070
|
+
const hookData = overrides.hookData ?? "0x";
|
|
2071
|
+
return Calibur7702Account.wrapSignature(keyHash, signature, hookData);
|
|
2072
|
+
}
|
|
1455
2073
|
/** The EntryPoint contract address this account targets */
|
|
1456
2074
|
entrypointAddress;
|
|
1457
2075
|
/** The Calibur singleton (delegatee) contract address */
|
|
@@ -1481,6 +2099,46 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1481
2099
|
return createUserOperationHash(userOperation, this.entrypointAddress, chainId);
|
|
1482
2100
|
}
|
|
1483
2101
|
/**
|
|
2102
|
+
* Build the EIP-712 typed data payload for a UserOperation under the
|
|
2103
|
+
* EntryPoint v0.8 / v0.9 domain. Useful for wallets that can only sign
|
|
2104
|
+
* typed data (`eth_signTypedData_v4`) — the digest of the returned payload
|
|
2105
|
+
* equals the `userOpHash`, so a typed-data signature over it produces a
|
|
2106
|
+
* wrapped Calibur signature that validates against the same hash on-chain.
|
|
2107
|
+
*
|
|
2108
|
+
* Intended for the secp256k1 key path (root key or any registered
|
|
2109
|
+
* secondary secp256k1 key), since `eth_signTypedData_v4` only produces
|
|
2110
|
+
* secp256k1 signatures. P-256 and WebAuthn-P256 keys sign with their
|
|
2111
|
+
* own primitives — for those, use {@link getUserOperationEip712Hash}
|
|
2112
|
+
* (the digest), which is the value-to-be-signed regardless of key type.
|
|
2113
|
+
*
|
|
2114
|
+
* @param userOperation - Unsigned UserOperation to wrap
|
|
2115
|
+
* @param chainId - Target chain ID
|
|
2116
|
+
* @param overrides - Override the entrypoint address (defaults to EntryPoint v0.8)
|
|
2117
|
+
* @returns EIP-712 {@link TypedData} payload ready for `signTypedData`
|
|
2118
|
+
* @throws {AbstractionKitError} if the target EntryPoint is not v0.8 / v0.9.
|
|
2119
|
+
*/
|
|
2120
|
+
static getUserOperationEip712Data(userOperation, chainId, overrides = {}) {
|
|
2121
|
+
return getUserOperationEip712DataV8V9(userOperation, overrides.entrypointAddress ?? "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108", chainId);
|
|
2122
|
+
}
|
|
2123
|
+
/**
|
|
2124
|
+
* Compute the EIP-712 digest of a UserOperation under the EntryPoint
|
|
2125
|
+
* v0.8 / v0.9 domain. For these EntryPoints this digest IS the
|
|
2126
|
+
* `userOpHash`; the wrapped Calibur signature is verified against this
|
|
2127
|
+
* hash on-chain.
|
|
2128
|
+
*
|
|
2129
|
+
* Universal across Calibur key types: secp256k1 and P-256 keys sign
|
|
2130
|
+
* this digest directly, each with their own signing primitive.
|
|
2131
|
+
*
|
|
2132
|
+
* @param userOperation - Unsigned UserOperation to hash
|
|
2133
|
+
* @param chainId - Target chain ID
|
|
2134
|
+
* @param overrides - Override the entrypoint address (defaults to EntryPoint v0.8)
|
|
2135
|
+
* @returns The EIP-712 digest as a hex string
|
|
2136
|
+
* @throws {AbstractionKitError} if the target EntryPoint is not v0.8 / v0.9.
|
|
2137
|
+
*/
|
|
2138
|
+
static getUserOperationEip712Hash(userOperation, chainId, overrides = {}) {
|
|
2139
|
+
return getUserOperationEip712HashV8V9(userOperation, overrides.entrypointAddress ?? "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108", chainId);
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
1484
2142
|
* Encode calldata for `executeUserOp(bytes)` with BatchedCall format.
|
|
1485
2143
|
* All transactions (even single ones) go through the same BatchedCall path.
|
|
1486
2144
|
*
|
|
@@ -1532,7 +2190,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1532
2190
|
}
|
|
1533
2191
|
let skipEip7702Auth = false;
|
|
1534
2192
|
let delegationCheckOp = null;
|
|
1535
|
-
if (overrides.eip7702Auth != null && providerRpc != null) delegationCheckOp = getDelegatedAddress(this.accountAddress
|
|
2193
|
+
if (overrides.eip7702Auth != null && providerRpc != null) delegationCheckOp = JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress).catch(() => null);
|
|
1536
2194
|
if (overrides.eip7702Auth != null && eip7702AuthNonce == null) {
|
|
1537
2195
|
let eip7702AuthNonceOp;
|
|
1538
2196
|
if (providerRpc != null) eip7702AuthNonceOp = sendJsonRpcRequest(providerRpc, "eth_getTransactionCount", [this.accountAddress, "latest"]);
|
|
@@ -1634,7 +2292,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1634
2292
|
userOperation.maxPriorityFeePerGas = 0n;
|
|
1635
2293
|
const userOperationToEstimate = { ...userOperation };
|
|
1636
2294
|
userOperationToEstimate.signature = overrides.dummySignature ?? Calibur7702Account.dummySignature;
|
|
1637
|
-
const estimation = await
|
|
2295
|
+
const estimation = await Bundler.from(bundlerRpc).estimateUserOperationGas(userOperationToEstimate, this.entrypointAddress, overrides.state_override_set);
|
|
1638
2296
|
preVerificationGas = BigInt(estimation.preVerificationGas);
|
|
1639
2297
|
verificationGasLimit = BigInt(estimation.verificationGasLimit);
|
|
1640
2298
|
callGasLimit = BigInt(estimation.callGasLimit);
|
|
@@ -1680,38 +2338,46 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1680
2338
|
return Calibur7702Account.wrapSignature(keyHash, ecdsaSig, hookData);
|
|
1681
2339
|
}
|
|
1682
2340
|
/**
|
|
1683
|
-
* Schemes Calibur accepts from a Signer.
|
|
1684
|
-
*
|
|
1685
|
-
*
|
|
2341
|
+
* Schemes Calibur accepts from a Signer. EntryPoint v0.8/v0.9 introduced
|
|
2342
|
+
* an EIP-712 domain at the EntryPoint contract, and the userOpHash IS the
|
|
2343
|
+
* EIP-712 digest of the PackedUserOperation under that domain — so signing
|
|
2344
|
+
* the typed data and signing the raw hash produce signatures that verify
|
|
2345
|
+
* against the same `userOpHash` (and recover to the same signer address).
|
|
2346
|
+
* Deterministic-ECDSA signers (ethers, viem, MetaMask) yield byte-identical
|
|
2347
|
+
* bytes; signers that differ in `s` / `v` normalization still validate the
|
|
2348
|
+
* same on-chain.
|
|
2349
|
+
*
|
|
2350
|
+
* `typedData` is listed first so JSON-RPC wallets that can only sign typed
|
|
2351
|
+
* data work without a separate code path; `hash` remains a valid fallback
|
|
2352
|
+
* for local-key signers.
|
|
1686
2353
|
*/
|
|
1687
|
-
static ACCEPTED_SIGNING_SCHEMES = ["hash"];
|
|
2354
|
+
static ACCEPTED_SIGNING_SCHEMES = ["typedData", "hash"];
|
|
1688
2355
|
/**
|
|
1689
|
-
* Sign a UserOperation
|
|
1690
|
-
*
|
|
1691
|
-
*
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
* `fromPrivateKey(pk)`. For secondary (non-root) keys, pass the key
|
|
1696
|
-
* hash via `overrides.keyHash`.
|
|
2356
|
+
* Sign a UserOperation with an {@link AkSigner}. The signer can implement
|
|
2357
|
+
* either `signTypedData` (preferred — JSON-RPC wallets, viem `WalletClient`)
|
|
2358
|
+
* or `signHash` (local keys, hardware wallets). Both schemes produce
|
|
2359
|
+
* signatures that validate against the same `userOpHash` because the
|
|
2360
|
+
* v0.8 / v0.9 userOpHash IS the EIP-712 digest of the PackedUserOperation
|
|
2361
|
+
* (deterministic-ECDSA signers yield byte-identical bytes).
|
|
1697
2362
|
*
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1700
|
-
* userOp.signature = await account.signUserOperationWithSigner(
|
|
1701
|
-
* userOp, fromViem(privateKeyToAccount(pk)), chainId,
|
|
1702
|
-
* );
|
|
2363
|
+
* Signers that implement neither method fail offline with an actionable
|
|
2364
|
+
* error.
|
|
1703
2365
|
*/
|
|
1704
2366
|
async signUserOperationWithSigner(userOperation, signer, chainId, overrides = {}) {
|
|
1705
|
-
const
|
|
2367
|
+
const scheme = pickScheme(signer, Calibur7702Account.ACCEPTED_SIGNING_SCHEMES, {
|
|
1706
2368
|
accountName: "Calibur (raw ECDSA over userOpHash)",
|
|
1707
2369
|
signerIndex: 0
|
|
1708
|
-
})
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
2370
|
+
});
|
|
2371
|
+
const hash = createUserOperationHash(userOperation, this.entrypointAddress, chainId);
|
|
2372
|
+
const context = {
|
|
2373
|
+
userOperation,
|
|
2374
|
+
chainId,
|
|
2375
|
+
entryPoint: this.entrypointAddress
|
|
2376
|
+
};
|
|
2377
|
+
const signature = await invokeSigner(signer, scheme, {
|
|
2378
|
+
hash,
|
|
2379
|
+
typedData: scheme === "typedData" ? Calibur7702Account.getUserOperationEip712Data(userOperation, chainId, { entrypointAddress: this.entrypointAddress }) : void 0,
|
|
2380
|
+
context
|
|
1715
2381
|
});
|
|
1716
2382
|
const keyHash = overrides.keyHash ?? ROOT_KEY_HASH;
|
|
1717
2383
|
const hookData = overrides.hookData ?? "0x";
|
|
@@ -1755,7 +2421,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1755
2421
|
* @returns A {@link SendUseroperationResponse} that can be used to wait for inclusion
|
|
1756
2422
|
*/
|
|
1757
2423
|
async sendUserOperation(userOperation, bundlerRpc) {
|
|
1758
|
-
const bundler =
|
|
2424
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
1759
2425
|
return new SendUseroperationResponse(await bundler.sendUserOperation(userOperation, this.entrypointAddress), bundler, this.entrypointAddress);
|
|
1760
2426
|
}
|
|
1761
2427
|
/**
|
|
@@ -1941,7 +2607,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
1941
2607
|
*/
|
|
1942
2608
|
async createRevokeDelegationRawTransaction(chainId, eoaPrivateKey, providerRpc, overrides = {}) {
|
|
1943
2609
|
if (new ethers.Wallet(eoaPrivateKey).address.toLowerCase() !== this.accountAddress.toLowerCase()) throw new AbstractionKitError("BAD_DATA", `eoaPrivateKey does not match accountAddress (${this.accountAddress})`);
|
|
1944
|
-
const delegatedTo = await getDelegatedAddress(this.accountAddress
|
|
2610
|
+
const delegatedTo = await JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress);
|
|
1945
2611
|
if (delegatedTo === null) throw new AbstractionKitError("BAD_DATA", "Account is not delegated — nothing to revoke");
|
|
1946
2612
|
if (delegatedTo.toLowerCase() !== this.delegateeAddress.toLowerCase()) throw new AbstractionKitError("BAD_DATA", "Account is delegated to a different address (" + delegatedTo + "), not " + this.delegateeAddress + " — use the correct account class to revoke");
|
|
1947
2613
|
const results = {};
|
|
@@ -2005,14 +2671,14 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
2005
2671
|
/**
|
|
2006
2672
|
* Check if this EOA is delegated to this account's singleton (delegatee).
|
|
2007
2673
|
* Returns `false` if not delegated at all or delegated to a different
|
|
2008
|
-
* singleton. Use
|
|
2009
|
-
*
|
|
2674
|
+
* singleton. Use {@link JsonRpcNode.getDelegatedAddress} to get the raw
|
|
2675
|
+
* delegatee address regardless of which singleton it is.
|
|
2010
2676
|
*
|
|
2011
2677
|
* @param providerRpc - JSON-RPC endpoint
|
|
2012
2678
|
* @returns True if the account is delegated to `this.delegateeAddress`
|
|
2013
2679
|
*/
|
|
2014
2680
|
async isDelegatedToThisAccount(providerRpc) {
|
|
2015
|
-
const address = await getDelegatedAddress(this.accountAddress
|
|
2681
|
+
const address = await JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress);
|
|
2016
2682
|
if (address === null) return false;
|
|
2017
2683
|
return address.toLowerCase() === this.delegateeAddress.toLowerCase();
|
|
2018
2684
|
}
|
|
@@ -2560,7 +3226,8 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
2560
3226
|
* @returns The simulation results from Tenderly.
|
|
2561
3227
|
*/
|
|
2562
3228
|
async function callTenderlySimulateBundle(tenderlyAccountSlug, tenderlyProjectSlug, tenderlyAccessKey, transactions) {
|
|
2563
|
-
|
|
3229
|
+
const tenderlyUrl = "https://api.tenderly.co/api/v1/account/" + tenderlyAccountSlug + "/project/" + tenderlyProjectSlug + "/simulate-bundle";
|
|
3230
|
+
const simulations = transactions.map((transaction) => {
|
|
2564
3231
|
const transactionObject = {
|
|
2565
3232
|
network_id: transaction.chainId.toString(),
|
|
2566
3233
|
save: transaction.save ?? true,
|
|
@@ -2589,11 +3256,53 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
2589
3256
|
if (transaction.generateAccessList != null) transactionObject.generate_access_list = transaction.generateAccessList;
|
|
2590
3257
|
if (transaction.accessList != null) transactionObject.access_list = transaction.accessList;
|
|
2591
3258
|
return transactionObject;
|
|
2592
|
-
})
|
|
3259
|
+
});
|
|
3260
|
+
const headers = {
|
|
2593
3261
|
Accept: "application/json",
|
|
2594
3262
|
"Content-Type": "application/json",
|
|
2595
3263
|
"X-Access-Key": tenderlyAccessKey
|
|
2596
|
-
}
|
|
3264
|
+
};
|
|
3265
|
+
const body = JSON.stringify({
|
|
3266
|
+
method: "tenderly_simulateBundle",
|
|
3267
|
+
simulations,
|
|
3268
|
+
id: Date.now(),
|
|
3269
|
+
jsonrpc: "2.0"
|
|
3270
|
+
}, (_key, value) => typeof value === "bigint" ? `0x${value.toString(16)}` : value);
|
|
3271
|
+
let response;
|
|
3272
|
+
try {
|
|
3273
|
+
response = await fetch(tenderlyUrl, {
|
|
3274
|
+
method: "POST",
|
|
3275
|
+
headers,
|
|
3276
|
+
body,
|
|
3277
|
+
redirect: "follow"
|
|
3278
|
+
});
|
|
3279
|
+
} catch (err) {
|
|
3280
|
+
const e = ensureError(err);
|
|
3281
|
+
throw new AbstractionKitError("TENDERLY_NETWORK_ERROR", `tenderly_simulateBundle network error: ${e.message}`, { cause: e });
|
|
3282
|
+
}
|
|
3283
|
+
if (!response.ok) throw new AbstractionKitError("TENDERLY_HTTP_ERROR", `tenderly_simulateBundle HTTP ${response.status}: ${response.statusText}`, {
|
|
3284
|
+
errno: response.status,
|
|
3285
|
+
context: {
|
|
3286
|
+
status: response.status,
|
|
3287
|
+
statusText: response.statusText
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
3290
|
+
const responseText = await response.text();
|
|
3291
|
+
let json;
|
|
3292
|
+
try {
|
|
3293
|
+
json = JSON.parse(responseText);
|
|
3294
|
+
} catch (err) {
|
|
3295
|
+
const e = ensureError(err);
|
|
3296
|
+
throw new AbstractionKitError("TENDERLY_INVALID_JSON", `tenderly_simulateBundle returned invalid JSON: ${e.message}`, {
|
|
3297
|
+
cause: e,
|
|
3298
|
+
context: { responseText }
|
|
3299
|
+
});
|
|
3300
|
+
}
|
|
3301
|
+
if (json.simulation_results != null) return json.simulation_results;
|
|
3302
|
+
throw new AbstractionKitError("TENDERLY_SIMULATION_ERROR", "tenderly_simulateBundle failed", {
|
|
3303
|
+
errno: json.error?.code,
|
|
3304
|
+
context: JSON.stringify(json)
|
|
3305
|
+
});
|
|
2597
3306
|
}
|
|
2598
3307
|
//#endregion
|
|
2599
3308
|
//#region src/account/Safe/multisend.ts
|
|
@@ -2819,7 +3528,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
2819
3528
|
* ```
|
|
2820
3529
|
*/
|
|
2821
3530
|
static async isDeployed(accountAddress, nodeRpcUrl) {
|
|
2822
|
-
return (await
|
|
3531
|
+
return (await JsonRpcNode.from(nodeRpcUrl).getCode(accountAddress, "latest")).length > 2;
|
|
2823
3532
|
}
|
|
2824
3533
|
/**
|
|
2825
3534
|
* encode calldata for a single MetaTransaction to be executed by Safe account
|
|
@@ -3203,11 +3912,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
3203
3912
|
/**
|
|
3204
3913
|
* sends a useroperation to a bundler rpc
|
|
3205
3914
|
* @param userOperation - useroperation to send
|
|
3206
|
-
* @param bundlerRpc - bundler rpc
|
|
3915
|
+
* @param bundlerRpc - bundler rpc URL, {@link Transport}, or pre-constructed {@link Bundler}
|
|
3207
3916
|
* @returns promise with SendUseroperationResponse
|
|
3208
3917
|
*/
|
|
3209
3918
|
async sendUserOperation(userOperation, bundlerRpc) {
|
|
3210
|
-
const bundler =
|
|
3919
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
3211
3920
|
return new SendUseroperationResponse(await bundler.sendUserOperation(userOperation, this.entrypointAddress), bundler, this.entrypointAddress);
|
|
3212
3921
|
}
|
|
3213
3922
|
/**
|
|
@@ -3390,7 +4099,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
3390
4099
|
validUntil,
|
|
3391
4100
|
isMultiChainSignature: overrides.isMultiChainSignature
|
|
3392
4101
|
});
|
|
3393
|
-
const bundler =
|
|
4102
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
3394
4103
|
const inputMaxFeePerGas = userOperation.maxFeePerGas;
|
|
3395
4104
|
const inputMaxPriorityFeePerGas = userOperation.maxPriorityFeePerGas;
|
|
3396
4105
|
userOperation.maxFeePerGas = 0n;
|
|
@@ -3913,7 +4622,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
3913
4622
|
webAuthnSignerSingleton: overrides.webAuthnSignerSingleton,
|
|
3914
4623
|
webAuthnSignerProxyCreationCode
|
|
3915
4624
|
});
|
|
3916
|
-
if ((await
|
|
4625
|
+
if ((await JsonRpcNode.from(nodeRpcUrl).getCode(newOwnerT, "latest")).length < 3) deployNewOwnerSignerMetaTransaction = SafeAccount.createDeployWebAuthnVerifierMetaTransaction(newOwner.x, newOwner.y, {
|
|
3917
4626
|
eip7212WebAuthnPrecompileVerifier: overrides.eip7212WebAuthnPrecompileVerifier,
|
|
3918
4627
|
eip7212WebAuthnContractVerifier: overrides.eip7212WebAuthnContractVerifier,
|
|
3919
4628
|
webAuthnSignerFactory: overrides.webAuthnSignerFactory
|
|
@@ -3996,7 +4705,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
3996
4705
|
webAuthnSignerProxyCreationCode
|
|
3997
4706
|
});
|
|
3998
4707
|
if (overrides.nodeRpcUrl == null) throw new RangeError("overrides.nodeRpcUrl can't be null if adding a webauthn owner");
|
|
3999
|
-
if ((await
|
|
4708
|
+
if ((await JsonRpcNode.from(overrides.nodeRpcUrl).getCode(newOwnerT, "latest")).length < 3) deployNewOwnerSignerMetaTransaction = SafeAccount.createDeployWebAuthnVerifierMetaTransaction(newOwner.x, newOwner.y, {
|
|
4000
4709
|
eip7212WebAuthnPrecompileVerifier: overrides.eip7212WebAuthnPrecompileVerifier,
|
|
4001
4710
|
eip7212WebAuthnContractVerifier: overrides.eip7212WebAuthnContractVerifier,
|
|
4002
4711
|
webAuthnSignerFactory: overrides.webAuthnSignerFactory
|
|
@@ -4124,10 +4833,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4124
4833
|
*/
|
|
4125
4834
|
async getOwners(nodeRpcUrl) {
|
|
4126
4835
|
const callData = createCallData(getFunctionSelector("getOwners()"), [], []);
|
|
4127
|
-
const
|
|
4836
|
+
const ethCallParams = {
|
|
4128
4837
|
to: this.accountAddress,
|
|
4129
4838
|
data: callData
|
|
4130
|
-
}
|
|
4839
|
+
};
|
|
4840
|
+
const getOwnersResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4131
4841
|
return ethers.AbiCoder.defaultAbiCoder().decode(["address[]"], getOwnersResult)[0];
|
|
4132
4842
|
}
|
|
4133
4843
|
/**
|
|
@@ -4137,10 +4847,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4137
4847
|
*/
|
|
4138
4848
|
async getThreshold(nodeRpcUrl) {
|
|
4139
4849
|
const callData = createCallData("0xe75235b8", [], []);
|
|
4140
|
-
const
|
|
4850
|
+
const ethCallParams = {
|
|
4141
4851
|
to: this.accountAddress,
|
|
4142
4852
|
data: callData
|
|
4143
|
-
}
|
|
4853
|
+
};
|
|
4854
|
+
const getThresholdResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4144
4855
|
const decodedCalldata = ethers.AbiCoder.defaultAbiCoder().decode(["uint256"], getThresholdResult);
|
|
4145
4856
|
return Number(decodedCalldata[0]);
|
|
4146
4857
|
}
|
|
@@ -4159,10 +4870,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4159
4870
|
let pageSize = overrides.pageSize;
|
|
4160
4871
|
if (pageSize == null) pageSize = 10n;
|
|
4161
4872
|
const callData = createCallData("0xcc2f8452", ["address", "uint256"], [start, pageSize]);
|
|
4162
|
-
const
|
|
4873
|
+
const ethCallParams = {
|
|
4163
4874
|
to: this.accountAddress,
|
|
4164
4875
|
data: callData
|
|
4165
|
-
}
|
|
4876
|
+
};
|
|
4877
|
+
const getModulesResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4166
4878
|
if (getModulesResult === "0x") throw new AbstractionKitError("BAD_DATA", "getModules returned an empty result, the target account is probably not deployed yet.");
|
|
4167
4879
|
const decodedCalldata = ethers.AbiCoder.defaultAbiCoder().decode(["address[]", "address"], getModulesResult);
|
|
4168
4880
|
return [decodedCalldata[0], decodedCalldata[1]];
|
|
@@ -4178,10 +4890,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4178
4890
|
*/
|
|
4179
4891
|
async isModuleEnabled(nodeRpcUrl, moduleAddress) {
|
|
4180
4892
|
const callData = createCallData(getFunctionSelector("isModuleEnabled(address)"), ["address"], [moduleAddress]);
|
|
4181
|
-
const
|
|
4893
|
+
const ethCallParams = {
|
|
4182
4894
|
to: this.accountAddress,
|
|
4183
4895
|
data: callData
|
|
4184
|
-
}
|
|
4896
|
+
};
|
|
4897
|
+
const isModuleEnabledResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4185
4898
|
return ethers.AbiCoder.defaultAbiCoder().decode(["bool"], isModuleEnabledResult)[0];
|
|
4186
4899
|
}
|
|
4187
4900
|
/**
|
|
@@ -4248,7 +4961,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4248
4961
|
data: callData
|
|
4249
4962
|
};
|
|
4250
4963
|
const deployedByteCode = SafeAccount.createSafeWebAuthnSignerProxyDeployedByteCode(signer, eip7212WebAuthnPrecompileVerifier, eip7212WebAuthnContractVerifier, webAuthnSignerSingleton);
|
|
4251
|
-
const isModuleEnabledResult = await
|
|
4964
|
+
const isModuleEnabledResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest", { [arbitraryAddress]: { code: deployedByteCode } });
|
|
4252
4965
|
return ethers.AbiCoder.defaultAbiCoder().decode(["bool"], isModuleEnabledResult)[0];
|
|
4253
4966
|
}
|
|
4254
4967
|
static createSafeWebAuthnSignerProxyDeployedByteCode(signer, eip7212WebAuthnPrecompileVerifier, eip7212WebAuthnContractVerifier, webAuthnSignerSingleton) {
|
|
@@ -4368,7 +5081,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4368
5081
|
* @param toolVersion - tool version; defaults to the current abstractionkit version
|
|
4369
5082
|
* @returns the on-chain identifier as a hex string (not 0x prefixed)
|
|
4370
5083
|
*/
|
|
4371
|
-
function generateOnChainIdentifier(project, platform = "Web", tool = "abstractionkit", toolVersion = "0.3.
|
|
5084
|
+
function generateOnChainIdentifier(project, platform = "Web", tool = "abstractionkit", toolVersion = "0.3.8") {
|
|
4372
5085
|
const identifierPrefix = "5afe";
|
|
4373
5086
|
const identifierVersion = "00";
|
|
4374
5087
|
const projectHash = (0, ethers.keccak256)(`0x${Buffer.from(project, "utf8").toString("hex")}`).slice(-20);
|
|
@@ -4631,10 +5344,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4631
5344
|
*/
|
|
4632
5345
|
async getTokens(nodeRpcUrl, safeAddress, delegate) {
|
|
4633
5346
|
const callData = createCallData("0x8d0e8e1d", ["address", "address"], [safeAddress, delegate]);
|
|
4634
|
-
const
|
|
5347
|
+
const ethCallParams = {
|
|
4635
5348
|
to: this.moduleAddress,
|
|
4636
5349
|
data: callData
|
|
4637
|
-
}
|
|
5350
|
+
};
|
|
5351
|
+
const tokens = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4638
5352
|
this.checkForEmptyResultAndRevert(tokens, "getTokens");
|
|
4639
5353
|
return this.abiCoder.decode(["address[]"], tokens)[0];
|
|
4640
5354
|
}
|
|
@@ -4656,10 +5370,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4656
5370
|
delegate,
|
|
4657
5371
|
token
|
|
4658
5372
|
]);
|
|
4659
|
-
const
|
|
5373
|
+
const ethCallParams = {
|
|
4660
5374
|
to: this.moduleAddress,
|
|
4661
5375
|
data: callData
|
|
4662
|
-
}
|
|
5376
|
+
};
|
|
5377
|
+
const tokenAllowance = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4663
5378
|
this.checkForEmptyResultAndRevert(tokenAllowance, "getTokenAllowance");
|
|
4664
5379
|
const allowance = this.abiCoder.decode(["uint256[5]"], tokenAllowance)[0];
|
|
4665
5380
|
return {
|
|
@@ -4711,10 +5426,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4711
5426
|
start,
|
|
4712
5427
|
pageSize
|
|
4713
5428
|
]);
|
|
4714
|
-
const
|
|
5429
|
+
const ethCallParams = {
|
|
4715
5430
|
to: this.moduleAddress,
|
|
4716
5431
|
data: callData
|
|
4717
|
-
}
|
|
5432
|
+
};
|
|
5433
|
+
const delegates = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4718
5434
|
this.checkForEmptyResultAndRevert(delegates, "getDelegates");
|
|
4719
5435
|
const decodedCalldata = this.abiCoder.decode(["address[]", "uint48"], delegates);
|
|
4720
5436
|
return {
|
|
@@ -4799,13 +5515,19 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4799
5515
|
"address",
|
|
4800
5516
|
"address[]",
|
|
4801
5517
|
"uint256",
|
|
4802
|
-
"(address,bytes)",
|
|
5518
|
+
"(address,bytes)[]",
|
|
4803
5519
|
"bool"
|
|
4804
5520
|
], [
|
|
4805
5521
|
accountAddress,
|
|
4806
5522
|
newOwners,
|
|
4807
5523
|
newThreshold,
|
|
4808
|
-
signaturePairList.
|
|
5524
|
+
[...signaturePairList].sort((a, b) => {
|
|
5525
|
+
const aSigner = BigInt(a.signer);
|
|
5526
|
+
const bSigner = BigInt(b.signer);
|
|
5527
|
+
if (aSigner < bSigner) return -1;
|
|
5528
|
+
if (aSigner > bSigner) return 1;
|
|
5529
|
+
throw new AbstractionKitError("BAD_DATA", `Duplicate signer in recovery signaturePairList: ${a.signer}`);
|
|
5530
|
+
}).map((signaturePair) => [signaturePair.signer, signaturePair.signature]),
|
|
4809
5531
|
execute
|
|
4810
5532
|
]);
|
|
4811
5533
|
return {
|
|
@@ -4957,10 +5679,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4957
5679
|
newThreshold,
|
|
4958
5680
|
nonce
|
|
4959
5681
|
]);
|
|
4960
|
-
const
|
|
5682
|
+
const ethCallParams = {
|
|
4961
5683
|
to: this.moduleAddress,
|
|
4962
5684
|
data: callData
|
|
4963
|
-
}
|
|
5685
|
+
};
|
|
5686
|
+
const recoveryHashResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4964
5687
|
this.checkForEmptyResultAndRevert(recoveryHashResult, "getRecoveryHash");
|
|
4965
5688
|
return this.abiCoder.decode(["bytes32"], recoveryHashResult)[0];
|
|
4966
5689
|
}
|
|
@@ -4972,10 +5695,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
4972
5695
|
*/
|
|
4973
5696
|
async getRecoveryRequest(nodeRpcUrl, accountAddress) {
|
|
4974
5697
|
const callData = createCallData("0x4f9a28b9", ["address"], [accountAddress]);
|
|
4975
|
-
const
|
|
5698
|
+
const ethCallParams = {
|
|
4976
5699
|
to: this.moduleAddress,
|
|
4977
5700
|
data: callData
|
|
4978
|
-
}
|
|
5701
|
+
};
|
|
5702
|
+
const recoveryRequestResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
4979
5703
|
this.checkForEmptyResultAndRevert(recoveryRequestResult, "getRecoveryRequest");
|
|
4980
5704
|
const decodedCalldata = this.abiCoder.decode(["(uint256,uint256,uint64,address[])"], recoveryRequestResult);
|
|
4981
5705
|
return {
|
|
@@ -5003,10 +5727,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5003
5727
|
newOwners,
|
|
5004
5728
|
newThreshold
|
|
5005
5729
|
]);
|
|
5006
|
-
const
|
|
5730
|
+
const ethCallParams = {
|
|
5007
5731
|
to: this.moduleAddress,
|
|
5008
5732
|
data: callData
|
|
5009
|
-
}
|
|
5733
|
+
};
|
|
5734
|
+
const recoveryApprovalResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5010
5735
|
this.checkForEmptyResultAndRevert(recoveryApprovalResult, "getRecoveryApprovals");
|
|
5011
5736
|
const decodedCalldata = this.abiCoder.decode(["uint256"], recoveryApprovalResult);
|
|
5012
5737
|
return BigInt(decodedCalldata[0]);
|
|
@@ -5032,10 +5757,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5032
5757
|
newOwners,
|
|
5033
5758
|
newThreshold
|
|
5034
5759
|
]);
|
|
5035
|
-
const
|
|
5760
|
+
const ethCallParams = {
|
|
5036
5761
|
to: this.moduleAddress,
|
|
5037
5762
|
data: callData
|
|
5038
|
-
}
|
|
5763
|
+
};
|
|
5764
|
+
const hasGuardianApprovedResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5039
5765
|
this.checkForEmptyResultAndRevert(hasGuardianApprovedResult, "hasGuardianApproved");
|
|
5040
5766
|
const decodedCalldata = this.abiCoder.decode(["bool"], hasGuardianApprovedResult);
|
|
5041
5767
|
return Boolean(decodedCalldata[0]);
|
|
@@ -5050,10 +5776,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5050
5776
|
*/
|
|
5051
5777
|
async isGuardian(nodeRpcUrl, accountAddress, guardian) {
|
|
5052
5778
|
const callData = createCallData("0xd4ee9734", ["address", "address"], [accountAddress, guardian]);
|
|
5053
|
-
const
|
|
5779
|
+
const ethCallParams = {
|
|
5054
5780
|
to: this.moduleAddress,
|
|
5055
5781
|
data: callData
|
|
5056
|
-
}
|
|
5782
|
+
};
|
|
5783
|
+
const isGuardianResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5057
5784
|
this.checkForEmptyResultAndRevert(isGuardianResult, "isGuardian");
|
|
5058
5785
|
const decodedCalldata = this.abiCoder.decode(["bool"], isGuardianResult);
|
|
5059
5786
|
return Boolean(decodedCalldata[0]);
|
|
@@ -5066,10 +5793,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5066
5793
|
*/
|
|
5067
5794
|
async guardiansCount(nodeRpcUrl, accountAddress) {
|
|
5068
5795
|
const callData = createCallData("0xc026e7ee", ["address"], [accountAddress]);
|
|
5069
|
-
const
|
|
5796
|
+
const ethCallParams = {
|
|
5070
5797
|
to: this.moduleAddress,
|
|
5071
5798
|
data: callData
|
|
5072
|
-
}
|
|
5799
|
+
};
|
|
5800
|
+
const guardiansCountResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5073
5801
|
this.checkForEmptyResultAndRevert(guardiansCountResult, "guardiansCount");
|
|
5074
5802
|
const decodedCalldata = this.abiCoder.decode(["uint256"], guardiansCountResult);
|
|
5075
5803
|
return BigInt(decodedCalldata[0]);
|
|
@@ -5082,10 +5810,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5082
5810
|
*/
|
|
5083
5811
|
async threshold(nodeRpcUrl, accountAddress) {
|
|
5084
5812
|
const callData = createCallData("0xc86ec2bf", ["address"], [accountAddress]);
|
|
5085
|
-
const
|
|
5813
|
+
const ethCallParams = {
|
|
5086
5814
|
to: this.moduleAddress,
|
|
5087
5815
|
data: callData
|
|
5088
|
-
}
|
|
5816
|
+
};
|
|
5817
|
+
const thresholdResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5089
5818
|
this.checkForEmptyResultAndRevert(thresholdResult, "threshold");
|
|
5090
5819
|
const decodedCalldata = this.abiCoder.decode(["uint256"], thresholdResult);
|
|
5091
5820
|
return BigInt(decodedCalldata[0]);
|
|
@@ -5098,10 +5827,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5098
5827
|
*/
|
|
5099
5828
|
async getGuardians(nodeRpcUrl, accountAddress) {
|
|
5100
5829
|
const callData = createCallData("0xf18858ab", ["address"], [accountAddress]);
|
|
5101
|
-
const
|
|
5830
|
+
const ethCallParams = {
|
|
5102
5831
|
to: this.moduleAddress,
|
|
5103
5832
|
data: callData
|
|
5104
|
-
}
|
|
5833
|
+
};
|
|
5834
|
+
const getGuardiansResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5105
5835
|
this.checkForEmptyResultAndRevert(getGuardiansResult, "threshold");
|
|
5106
5836
|
return this.abiCoder.decode(["address[]"], getGuardiansResult)[0];
|
|
5107
5837
|
}
|
|
@@ -5113,10 +5843,11 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
5113
5843
|
*/
|
|
5114
5844
|
async nonce(nodeRpcUrl, accountAddress) {
|
|
5115
5845
|
const callData = createCallData("0x70ae92d2", ["address"], [accountAddress]);
|
|
5116
|
-
const
|
|
5846
|
+
const ethCallParams = {
|
|
5117
5847
|
to: this.moduleAddress,
|
|
5118
5848
|
data: callData
|
|
5119
|
-
}
|
|
5849
|
+
};
|
|
5850
|
+
const nonceResult = await JsonRpcNode.from(nodeRpcUrl).call(ethCallParams, "latest");
|
|
5120
5851
|
this.checkForEmptyResultAndRevert(nonceResult, "threshold");
|
|
5121
5852
|
const decodedCalldata = this.abiCoder.decode(["uint256"], nonceResult);
|
|
5122
5853
|
return BigInt(decodedCalldata[0]);
|
|
@@ -6196,6 +6927,14 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6196
6927
|
* {@link SafeAccountV0_3_0.signUserOperationWithSigners} for the full
|
|
6197
6928
|
* design rationale. Sets the multi-chain flag automatically.
|
|
6198
6929
|
*
|
|
6930
|
+
* Note the chainId plumbing asymmetry vs the multi-op variant:
|
|
6931
|
+
* - **Singular** (this method): `chainId` is a positional argument.
|
|
6932
|
+
* - **Plural** ({@link signUserOperationsWithSigners}): `chainId` lives
|
|
6933
|
+
* inside each `UserOperationToSign` element, since each op may
|
|
6934
|
+
* target a different chain.
|
|
6935
|
+
* Pick the variant that matches your bundle shape; don't pass the same
|
|
6936
|
+
* chainId twice.
|
|
6937
|
+
*
|
|
6199
6938
|
* @param userOperation - UserOperation to sign
|
|
6200
6939
|
* @param signers - one ExternalSigner per owner (any order)
|
|
6201
6940
|
* @param chainId - target chain id
|
|
@@ -6272,17 +7011,26 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6272
7011
|
/**
|
|
6273
7012
|
* Sign a list of UserOperations with a single multi-chain signature. Each
|
|
6274
7013
|
* signer signs the Merkle root of the UserOperation EIP-712 hashes via
|
|
6275
|
-
*
|
|
6276
|
-
*
|
|
7014
|
+
* either `signTypedData` (the root is wrapped in an EIP-712 `MerkleTreeRoot`
|
|
7015
|
+
* message) or raw-hash signing; both schemes produce signatures that
|
|
7016
|
+
* validate against the same on-chain digest.
|
|
6277
7017
|
*
|
|
6278
7018
|
* Signers always receive {@link MultiOpSignContext}. The built-in adapters
|
|
6279
|
-
* `fromPrivateKey`, `fromViem`, and `
|
|
6280
|
-
*
|
|
6281
|
-
*
|
|
6282
|
-
*
|
|
6283
|
-
* (`Signer<SignContext>`) also don't work — they'd receive a context shape
|
|
7019
|
+
* `fromPrivateKey`, `fromViem`, `fromEthersWallet`, and `fromViemWalletClient`
|
|
7020
|
+
* all work here without retyping (`fromViemWalletClient` will sign the
|
|
7021
|
+
* typed-data Merkle wrapper). User-defined single-op signers
|
|
7022
|
+
* (`Signer<SignContext>`) still don't work — they'd receive a context shape
|
|
6284
7023
|
* they didn't declare.
|
|
6285
7024
|
*
|
|
7025
|
+
* Note the chainId plumbing asymmetry vs the single-op variant:
|
|
7026
|
+
* - **Plural** (this method): each `UserOperationToSign` carries its
|
|
7027
|
+
* own `chainId`, since a multichain bundle's ops target different
|
|
7028
|
+
* chains.
|
|
7029
|
+
* - **Singular** ({@link signUserOperationWithSigners}): `chainId` is
|
|
7030
|
+
* a positional argument.
|
|
7031
|
+
* For a length-1 bundle on this method, set `chainId` on the single
|
|
7032
|
+
* element rather than reaching for the singular variant.
|
|
7033
|
+
*
|
|
6286
7034
|
* @param userOperationsToSign - UserOperations + chain IDs + validity windows
|
|
6287
7035
|
* @param signers - one Signer per owner (any order; sorted by address on-chain)
|
|
6288
7036
|
* @returns one signature per input UserOperation, in the same order
|
|
@@ -6311,14 +7059,19 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6311
7059
|
const [root, proofs] = generateMerkleProofs(userOperationsHashes);
|
|
6312
7060
|
const merkleTreeRootHash = ethers.TypedDataEncoder.hash({ verifyingContract: this.safe4337ModuleAddress }, EIP712_MULTI_CHAIN_OPERATIONS_TYPE, { merkleTreeRoot: root });
|
|
6313
7061
|
const normalizedAddresses = signers.map((signer) => (0, ethers.getAddress)(signer.address));
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
}
|
|
6319
|
-
}
|
|
6320
|
-
const
|
|
7062
|
+
const typedDataForBundle = {
|
|
7063
|
+
domain: { verifyingContract: this.safe4337ModuleAddress },
|
|
7064
|
+
types: EIP712_MULTI_CHAIN_OPERATIONS_TYPE,
|
|
7065
|
+
primaryType: EIP712_MULTI_CHAIN_OPERATIONS_PRIMARY_TYPE,
|
|
7066
|
+
message: { merkleTreeRoot: root }
|
|
7067
|
+
};
|
|
7068
|
+
const schemes = signers.map((signer, i) => pickScheme(signer, ["typedData", "hash"], {
|
|
7069
|
+
accountName: "SafeMultiChainSigAccountV1 (multi-op Merkle root)",
|
|
7070
|
+
signerIndex: i
|
|
7071
|
+
}));
|
|
7072
|
+
const signatures = await Promise.all(signers.map((signer, i) => invokeSigner(signer, schemes[i], {
|
|
6321
7073
|
hash: merkleTreeRootHash,
|
|
7074
|
+
typedData: typedDataForBundle,
|
|
6322
7075
|
context
|
|
6323
7076
|
})));
|
|
6324
7077
|
const signerSignaturePairs = signers.map((_signer, i) => ({
|
|
@@ -6542,13 +7295,13 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6542
7295
|
/**
|
|
6543
7296
|
* Check if this EOA is delegated to the expected delegatee address via EIP-7702.
|
|
6544
7297
|
* Returns `true` only when delegated to `this.delegateeAddress`.
|
|
6545
|
-
* Use `getDelegatedAddress()` directly to get the raw delegatee address.
|
|
7298
|
+
* Use `JsonRpcNode.getDelegatedAddress()` directly to get the raw delegatee address.
|
|
6546
7299
|
*
|
|
6547
7300
|
* @param providerRpc - Ethereum JSON-RPC node URL
|
|
6548
7301
|
* @returns `true` if delegated to the expected address, `false` otherwise
|
|
6549
7302
|
*/
|
|
6550
7303
|
async isDelegatedToThisAccount(providerRpc) {
|
|
6551
|
-
const address = await getDelegatedAddress(this.accountAddress
|
|
7304
|
+
const address = await JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress);
|
|
6552
7305
|
if (address === null) return false;
|
|
6553
7306
|
return address.toLowerCase() === this.delegateeAddress.toLowerCase();
|
|
6554
7307
|
}
|
|
@@ -6569,7 +7322,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6569
7322
|
* @returns Signed raw transaction hex, ready for `eth_sendRawTransaction`
|
|
6570
7323
|
*/
|
|
6571
7324
|
async createRevokeDelegationTransaction(eoaPrivateKey, providerRpc, overrides = {}) {
|
|
6572
|
-
const delegatedTo = await getDelegatedAddress(this.accountAddress
|
|
7325
|
+
const delegatedTo = await JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress);
|
|
6573
7326
|
if (delegatedTo === null) throw new AbstractionKitError("BAD_DATA", "Account is not delegated — nothing to revoke");
|
|
6574
7327
|
if (delegatedTo.toLowerCase() !== this.delegateeAddress.toLowerCase()) throw new AbstractionKitError("BAD_DATA", "Account is delegated to a different address (" + delegatedTo + "), not " + this.delegateeAddress + " — use the correct account class to revoke");
|
|
6575
7328
|
const results = {};
|
|
@@ -6672,7 +7425,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6672
7425
|
eip7702AuthNonce = overrides.eip7702Auth.nonce ?? null;
|
|
6673
7426
|
}
|
|
6674
7427
|
let delegationCheckOp = null;
|
|
6675
|
-
if (overrides.eip7702Auth != null && providerRpc != null) delegationCheckOp = getDelegatedAddress(this.accountAddress
|
|
7428
|
+
if (overrides.eip7702Auth != null && providerRpc != null) delegationCheckOp = JsonRpcNode.from(providerRpc).getDelegatedAddress(this.accountAddress).catch(() => null);
|
|
6676
7429
|
if (overrides.eip7702Auth != null && eip7702AuthNonce == null) {
|
|
6677
7430
|
let eip7702AuthNonceOp;
|
|
6678
7431
|
if (providerRpc != null) eip7702AuthNonceOp = sendJsonRpcRequest(providerRpc, "eth_getTransactionCount", [this.accountAddress, "latest"]);
|
|
@@ -6807,7 +7560,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6807
7560
|
*/
|
|
6808
7561
|
async baseEstimateUserOperationGas(userOperation, bundlerRpc, overrides = {}) {
|
|
6809
7562
|
userOperation.signature = overrides.dummySignature ?? BaseSimple7702Account.dummySignature;
|
|
6810
|
-
const bundler =
|
|
7563
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
6811
7564
|
const inputMaxFeePerGas = userOperation.maxFeePerGas;
|
|
6812
7565
|
const inputMaxPriorityFeePerGas = userOperation.maxPriorityFeePerGas;
|
|
6813
7566
|
userOperation.maxFeePerGas = 0n;
|
|
@@ -6863,83 +7616,35 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6863
7616
|
* Deterministic-ECDSA signers yield byte-identical signatures; signers
|
|
6864
7617
|
* that differ in `s` / `v` normalization still validate the same on-chain.
|
|
6865
7618
|
*
|
|
6866
|
-
*
|
|
6867
|
-
*
|
|
6868
|
-
* - Render a custom confirmation UI before delegating to a wallet's
|
|
6869
|
-
* `signTypedData`.
|
|
6870
|
-
* - Drive non-`ExternalSigner`-shaped signers (HSM, MPC service,
|
|
6871
|
-
* backend signing pipelines).
|
|
7619
|
+
* The base class defaults to EntryPoint v0.8; subclasses
|
|
7620
|
+
* ({@link Simple7702AccountV09}) override with their own default.
|
|
6872
7621
|
*
|
|
6873
7622
|
* @param userOperation - Unsigned UserOperation to wrap
|
|
6874
7623
|
* @param chainId - Target chain ID (must match the chain that will validate
|
|
6875
7624
|
* the signature)
|
|
7625
|
+
* @param overrides - Override the entrypoint address
|
|
6876
7626
|
* @returns EIP-712 {@link TypedData} payload ready for `signTypedData`
|
|
6877
|
-
* @throws {AbstractionKitError} if
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
{
|
|
6899
|
-
name: "sender",
|
|
6900
|
-
type: "address"
|
|
6901
|
-
},
|
|
6902
|
-
{
|
|
6903
|
-
name: "nonce",
|
|
6904
|
-
type: "uint256"
|
|
6905
|
-
},
|
|
6906
|
-
{
|
|
6907
|
-
name: "initCode",
|
|
6908
|
-
type: "bytes"
|
|
6909
|
-
},
|
|
6910
|
-
{
|
|
6911
|
-
name: "callData",
|
|
6912
|
-
type: "bytes"
|
|
6913
|
-
},
|
|
6914
|
-
{
|
|
6915
|
-
name: "accountGasLimits",
|
|
6916
|
-
type: "bytes32"
|
|
6917
|
-
},
|
|
6918
|
-
{
|
|
6919
|
-
name: "preVerificationGas",
|
|
6920
|
-
type: "uint256"
|
|
6921
|
-
},
|
|
6922
|
-
{
|
|
6923
|
-
name: "gasFees",
|
|
6924
|
-
type: "bytes32"
|
|
6925
|
-
},
|
|
6926
|
-
{
|
|
6927
|
-
name: "paymasterAndData",
|
|
6928
|
-
type: "bytes"
|
|
6929
|
-
}
|
|
6930
|
-
] },
|
|
6931
|
-
primaryType: "PackedUserOperation",
|
|
6932
|
-
message: {
|
|
6933
|
-
sender: userOperation.sender,
|
|
6934
|
-
nonce: userOperation.nonce,
|
|
6935
|
-
initCode,
|
|
6936
|
-
callData: userOperation.callData,
|
|
6937
|
-
accountGasLimits,
|
|
6938
|
-
preVerificationGas: userOperation.preVerificationGas,
|
|
6939
|
-
gasFees,
|
|
6940
|
-
paymasterAndData
|
|
6941
|
-
}
|
|
6942
|
-
};
|
|
7627
|
+
* @throws {AbstractionKitError} if the target EntryPoint is not v0.8 / v0.9.
|
|
7628
|
+
*/
|
|
7629
|
+
static getUserOperationEip712Data(userOperation, chainId, overrides = {}) {
|
|
7630
|
+
return getUserOperationEip712DataV8V9(userOperation, overrides.entrypointAddress ?? "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108", chainId);
|
|
7631
|
+
}
|
|
7632
|
+
/**
|
|
7633
|
+
* Compute the EIP-712 digest of a UserOperation under the EntryPoint
|
|
7634
|
+
* v0.8 / v0.9 domain. For these EntryPoints this digest IS the
|
|
7635
|
+
* `userOpHash` ({@link createUserOperationHash}); signing it with raw
|
|
7636
|
+
* ECDSA or via `signTypedData` over the data from
|
|
7637
|
+
* {@link getUserOperationEip712Data} produces a signature that validates
|
|
7638
|
+
* against the same hash on-chain.
|
|
7639
|
+
*
|
|
7640
|
+
* @param userOperation - Unsigned UserOperation to hash
|
|
7641
|
+
* @param chainId - Target chain ID
|
|
7642
|
+
* @param overrides - Override the entrypoint address (defaults to EntryPoint v0.8)
|
|
7643
|
+
* @returns The EIP-712 digest as a hex string
|
|
7644
|
+
* @throws {AbstractionKitError} if the target EntryPoint is not v0.8 / v0.9.
|
|
7645
|
+
*/
|
|
7646
|
+
static getUserOperationEip712Hash(userOperation, chainId, overrides = {}) {
|
|
7647
|
+
return getUserOperationEip712HashV8V9(userOperation, overrides.entrypointAddress ?? "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108", chainId);
|
|
6943
7648
|
}
|
|
6944
7649
|
/**
|
|
6945
7650
|
* Sign a UserOperation with an {@link AkSigner}. The signer can implement
|
|
@@ -6965,7 +7670,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6965
7670
|
};
|
|
6966
7671
|
return invokeSigner(signer, scheme, {
|
|
6967
7672
|
hash,
|
|
6968
|
-
typedData: scheme === "typedData" ?
|
|
7673
|
+
typedData: scheme === "typedData" ? BaseSimple7702Account.getUserOperationEip712Data(useroperation, chainId, { entrypointAddress: this.entrypointAddress }) : void 0,
|
|
6969
7674
|
context
|
|
6970
7675
|
});
|
|
6971
7676
|
}
|
|
@@ -6976,7 +7681,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
6976
7681
|
* @returns A {@link SendUseroperationResponse} that can be used to wait for inclusion
|
|
6977
7682
|
*/
|
|
6978
7683
|
async baseSendUserOperation(userOperation, bundlerRpc) {
|
|
6979
|
-
const bundler =
|
|
7684
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
6980
7685
|
return new SendUseroperationResponse(await bundler.sendUserOperation(userOperation, this.entrypointAddress), bundler, this.entrypointAddress);
|
|
6981
7686
|
}
|
|
6982
7687
|
/**
|
|
@@ -7104,8 +7809,8 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7104
7809
|
* {@link signUserOperation} method, or wrap explicitly with
|
|
7105
7810
|
* `fromPrivateKey(pk)`.
|
|
7106
7811
|
*
|
|
7107
|
-
* @see {@link BaseSimple7702Account.
|
|
7108
|
-
*
|
|
7812
|
+
* @see {@link BaseSimple7702Account.getUserOperationEip712Data} for the
|
|
7813
|
+
* lower-level escape hatch when you need the typed data outside the
|
|
7109
7814
|
* dispatcher (e.g., to render a custom confirmation UI or feed an HSM
|
|
7110
7815
|
* that doesn't fit the {@link ExternalSigner} shape).
|
|
7111
7816
|
*/
|
|
@@ -7133,6 +7838,22 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7133
7838
|
var Simple7702AccountV09 = class Simple7702AccountV09 extends BaseSimple7702Account {
|
|
7134
7839
|
static DEFAULT_DELEGATEE_ADDRESS = "0xa46cc63eBF4Bd77888AA327837d20b23A63a56B5";
|
|
7135
7840
|
/**
|
|
7841
|
+
* Build the EIP-712 typed data payload for a {@link UserOperationV9}
|
|
7842
|
+
* under the EntryPoint v0.9 domain. See
|
|
7843
|
+
* {@link BaseSimple7702Account.getUserOperationEip712Data} for the
|
|
7844
|
+
* full semantics; this override just defaults `entrypointAddress` to v0.9.
|
|
7845
|
+
*/
|
|
7846
|
+
static getUserOperationEip712Data(userOperation, chainId, overrides = {}) {
|
|
7847
|
+
return BaseSimple7702Account.getUserOperationEip712Data(userOperation, chainId, { entrypointAddress: overrides.entrypointAddress ?? "0x433709009B8330FDa32311DF1C2AFA402eD8D009" });
|
|
7848
|
+
}
|
|
7849
|
+
/**
|
|
7850
|
+
* Compute the EIP-712 digest of a {@link UserOperationV9} under the
|
|
7851
|
+
* EntryPoint v0.9 domain. Defaults `entrypointAddress` to v0.9.
|
|
7852
|
+
*/
|
|
7853
|
+
static getUserOperationEip712Hash(userOperation, chainId, overrides = {}) {
|
|
7854
|
+
return BaseSimple7702Account.getUserOperationEip712Hash(userOperation, chainId, { entrypointAddress: overrides.entrypointAddress ?? "0x433709009B8330FDa32311DF1C2AFA402eD8D009" });
|
|
7855
|
+
}
|
|
7856
|
+
/**
|
|
7136
7857
|
* @param accountAddress - The EOA address that will be delegated via EIP-7702
|
|
7137
7858
|
* @param overrides - Optional overrides for entrypoint and delegatee addresses
|
|
7138
7859
|
* @param overrides.entrypointAddress - Custom EntryPoint address (defaults to EntryPoint v0.9)
|
|
@@ -7202,8 +7923,8 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7202
7923
|
* {@link signUserOperation} method, or wrap explicitly with
|
|
7203
7924
|
* `fromPrivateKey(pk)`.
|
|
7204
7925
|
*
|
|
7205
|
-
* @see {@link BaseSimple7702Account.
|
|
7206
|
-
*
|
|
7926
|
+
* @see {@link BaseSimple7702Account.getUserOperationEip712Data} for the
|
|
7927
|
+
* lower-level escape hatch when you need the typed data outside the
|
|
7207
7928
|
* dispatcher.
|
|
7208
7929
|
*/
|
|
7209
7930
|
async signUserOperationWithSigner(useroperation, signer, chainId) {
|
|
@@ -7305,8 +8026,19 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7305
8026
|
* const { userOperation: sponsoredOp } = await paymaster.createSponsorPaymasterUserOperation(userOp, bundlerRpcUrl);
|
|
7306
8027
|
*/
|
|
7307
8028
|
var CandidePaymaster = class CandidePaymaster extends Paymaster {
|
|
7308
|
-
/**
|
|
7309
|
-
|
|
8029
|
+
/**
|
|
8030
|
+
* The raw transport the user passed in (or {@link HttpTransport} when a URL
|
|
8031
|
+
* string was passed). Exposed for introspection — reading `.url`,
|
|
8032
|
+
* `isHttpTransport(...)` checks, passing it back into another service.
|
|
8033
|
+
*
|
|
8034
|
+
* Calls made directly on this field (`paymaster.transport.request(...)`)
|
|
8035
|
+
* go to the raw transport and skip SDK-level behavior like bigint param
|
|
8036
|
+
* normalization. For SDK-pipeline behavior, use
|
|
8037
|
+
* {@link CandidePaymaster.request} or the typed methods.
|
|
8038
|
+
*/
|
|
8039
|
+
transport;
|
|
8040
|
+
/** Normalizing wrapper around {@link transport}, used for every SDK-outbound call. */
|
|
8041
|
+
outbound;
|
|
7310
8042
|
/** Cached token/metadata per EntryPoint address (lowercase keys) */
|
|
7311
8043
|
entrypointData = /* @__PURE__ */ new Map();
|
|
7312
8044
|
/** Per-entrypoint initialization promises (lowercase keys) */
|
|
@@ -7314,11 +8046,30 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7314
8046
|
/** Cached chain ID (hex string), resolved from URL or pm_chainId RPC */
|
|
7315
8047
|
chainId = null;
|
|
7316
8048
|
chainIdPromise = null;
|
|
7317
|
-
/**
|
|
7318
|
-
|
|
8049
|
+
/**
|
|
8050
|
+
* @param rpc - The Candide paymaster JSON-RPC endpoint URL, or any {@link Transport}.
|
|
8051
|
+
* When a URL string is passed, the chain id is inferred from the URL path
|
|
8052
|
+
* when possible; otherwise it's resolved lazily via `pm_chainId`.
|
|
8053
|
+
*/
|
|
8054
|
+
constructor(rpc) {
|
|
7319
8055
|
super();
|
|
7320
|
-
this.
|
|
7321
|
-
this.
|
|
8056
|
+
this.transport = typeof rpc === "string" ? new HttpTransport(rpc) : rpc;
|
|
8057
|
+
this.outbound = normalizingTransport(this.transport);
|
|
8058
|
+
this.chainId = typeof rpc === "string" ? CandidePaymaster.extractChainIdFromUrl(rpc) : null;
|
|
8059
|
+
}
|
|
8060
|
+
/**
|
|
8061
|
+
* Normalize any acceptable input into a `CandidePaymaster`. Returns the
|
|
8062
|
+
* input by reference when it's already a `CandidePaymaster`.
|
|
8063
|
+
*/
|
|
8064
|
+
static from(input) {
|
|
8065
|
+
return input instanceof CandidePaymaster ? input : new CandidePaymaster(input);
|
|
8066
|
+
}
|
|
8067
|
+
/**
|
|
8068
|
+
* Transport delegate. Forwards directly to {@link Transport.request}, so a
|
|
8069
|
+
* `CandidePaymaster` can be slotted into any other transport position.
|
|
8070
|
+
*/
|
|
8071
|
+
request(args, options) {
|
|
8072
|
+
return this.outbound.request(args, options);
|
|
7322
8073
|
}
|
|
7323
8074
|
/**
|
|
7324
8075
|
* Extract chain ID from a Candide paymaster URL.
|
|
@@ -7346,7 +8097,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7346
8097
|
}
|
|
7347
8098
|
async fetchChainId() {
|
|
7348
8099
|
try {
|
|
7349
|
-
return await
|
|
8100
|
+
return await this.outbound.request({ method: "pm_chainId" });
|
|
7350
8101
|
} catch (err) {
|
|
7351
8102
|
throw new AbstractionKitError("PAYMASTER_ERROR", "pm_chainId failed", { cause: ensureError(err) });
|
|
7352
8103
|
}
|
|
@@ -7446,7 +8197,10 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7446
8197
|
}
|
|
7447
8198
|
}
|
|
7448
8199
|
async fetchSupportedTokensRpc(entrypoint) {
|
|
7449
|
-
return await
|
|
8200
|
+
return await this.outbound.request({
|
|
8201
|
+
method: "pm_supportedERC20Tokens",
|
|
8202
|
+
params: [entrypoint]
|
|
8203
|
+
});
|
|
7450
8204
|
}
|
|
7451
8205
|
/**
|
|
7452
8206
|
* Get the EntryPoint addresses supported by this paymaster.
|
|
@@ -7455,7 +8209,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7455
8209
|
*/
|
|
7456
8210
|
async getSupportedEntrypoints() {
|
|
7457
8211
|
try {
|
|
7458
|
-
return await
|
|
8212
|
+
return await this.outbound.request({ method: "pm_supportedEntryPoints" });
|
|
7459
8213
|
} catch (err) {
|
|
7460
8214
|
throw new AbstractionKitError("PAYMASTER_ERROR", "pm_supportedEntryPoints failed", { cause: ensureError(err) });
|
|
7461
8215
|
}
|
|
@@ -7522,7 +8276,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7522
8276
|
let callGasLimit = userOp.callGasLimit;
|
|
7523
8277
|
if (overrides.preVerificationGas == null || overrides.verificationGasLimit == null || overrides.callGasLimit == null) {
|
|
7524
8278
|
if (bundlerRpc == null) throw new AbstractionKitError("BAD_DATA", "bundlerRpc can't be null if preVerificationGas,verificationGasLimit and callGasLimit are not overridden");
|
|
7525
|
-
const bundler =
|
|
8279
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
7526
8280
|
userOp.callGasLimit = 0n;
|
|
7527
8281
|
userOp.verificationGasLimit = 0n;
|
|
7528
8282
|
userOp.preVerificationGas = 0n;
|
|
@@ -7570,12 +8324,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7570
8324
|
try {
|
|
7571
8325
|
const entrypoint = overrides.entrypoint ?? this.resolveEntrypoint(smartAccount, userOperation);
|
|
7572
8326
|
const chainId = await this.getChainId();
|
|
7573
|
-
const jsonRpcResult = await
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
8327
|
+
const jsonRpcResult = await this.outbound.request({
|
|
8328
|
+
method: "pm_getPaymasterData",
|
|
8329
|
+
params: [
|
|
8330
|
+
userOperation,
|
|
8331
|
+
entrypoint,
|
|
8332
|
+
chainId,
|
|
8333
|
+
context
|
|
8334
|
+
]
|
|
8335
|
+
});
|
|
7579
8336
|
return {
|
|
7580
8337
|
userOperation,
|
|
7581
8338
|
sponsorMetadata: this.applyPaymasterResult(userOperation, jsonRpcResult)
|
|
@@ -7759,8 +8516,19 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7759
8516
|
*/
|
|
7760
8517
|
const CANDIDE_TOKEN_QUOTE_TTL_MS = 45e3;
|
|
7761
8518
|
var Erc7677Paymaster = class Erc7677Paymaster extends Paymaster {
|
|
7762
|
-
/**
|
|
7763
|
-
|
|
8519
|
+
/**
|
|
8520
|
+
* The raw transport the user passed in (or {@link HttpTransport} when a URL
|
|
8521
|
+
* string was passed). Exposed for introspection — reading `.url`,
|
|
8522
|
+
* `isHttpTransport(...)` checks, passing it back into another service.
|
|
8523
|
+
*
|
|
8524
|
+
* Calls made directly on this field (`paymaster.transport.request(...)`)
|
|
8525
|
+
* go to the raw transport and skip SDK-level behavior like bigint param
|
|
8526
|
+
* normalization. For SDK-pipeline behavior, use
|
|
8527
|
+
* {@link Erc7677Paymaster.request} or the typed methods.
|
|
8528
|
+
*/
|
|
8529
|
+
transport;
|
|
8530
|
+
/** Normalizing wrapper around {@link transport}, used for every SDK-outbound call. */
|
|
8531
|
+
outbound;
|
|
7764
8532
|
/** Cached chain ID (hex string). Passed via constructor or resolved from the bundler at first use. */
|
|
7765
8533
|
chainId;
|
|
7766
8534
|
/** Detected or explicitly set paymaster provider. `null` means no provider-specific features. */
|
|
@@ -7794,29 +8562,49 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7794
8562
|
return null;
|
|
7795
8563
|
}
|
|
7796
8564
|
/**
|
|
7797
|
-
* @param
|
|
7798
|
-
* bundler when the provider bundles both
|
|
7799
|
-
* can also be a separate paymaster-only
|
|
8565
|
+
* @param rpc - Paymaster JSON-RPC endpoint URL, or any {@link Transport}.
|
|
8566
|
+
* Can be the same URL as the bundler when the provider bundles both
|
|
8567
|
+
* (Candide, Pimlico, Alchemy); can also be a separate paymaster-only
|
|
8568
|
+
* endpoint, or a fully custom transport.
|
|
7800
8569
|
* @param options
|
|
7801
8570
|
* @param options.chainId - Optional chain id as a bigint (e.g. `1n` for
|
|
7802
8571
|
* mainnet). When provided, avoids a lookup at first use. Otherwise,
|
|
7803
8572
|
* resolved from the bundler via `eth_chainId` on the first call.
|
|
7804
8573
|
* @param options.provider - Paymaster provider. `"auto"` (default) detects
|
|
7805
|
-
* from the RPC URL
|
|
8574
|
+
* from the RPC URL (only when a URL string is passed; non-string inputs
|
|
8575
|
+
* default to `null` unless overridden here). Set explicitly to override,
|
|
8576
|
+
* or `null` to disable provider-specific features.
|
|
7806
8577
|
*/
|
|
7807
|
-
constructor(
|
|
8578
|
+
constructor(rpc, options = {}) {
|
|
7808
8579
|
super();
|
|
7809
|
-
this.
|
|
8580
|
+
this.transport = typeof rpc === "string" ? new HttpTransport(rpc) : rpc;
|
|
8581
|
+
this.outbound = normalizingTransport(this.transport);
|
|
7810
8582
|
this.chainId = options.chainId != null ? `0x${options.chainId.toString(16)}` : null;
|
|
7811
|
-
if (options.provider === void 0 || options.provider === "auto") this.provider = Erc7677Paymaster.detectProvider(
|
|
8583
|
+
if (options.provider === void 0 || options.provider === "auto") this.provider = typeof rpc === "string" ? Erc7677Paymaster.detectProvider(rpc) : null;
|
|
7812
8584
|
else this.provider = options.provider;
|
|
7813
8585
|
}
|
|
7814
8586
|
/**
|
|
8587
|
+
* Normalize any acceptable input into an `Erc7677Paymaster`. Returns the
|
|
8588
|
+
* input by reference when it's already an `Erc7677Paymaster` (in which
|
|
8589
|
+
* case the second `options` argument is ignored — the existing instance's
|
|
8590
|
+
* configuration is preserved).
|
|
8591
|
+
*/
|
|
8592
|
+
static from(input, options) {
|
|
8593
|
+
return input instanceof Erc7677Paymaster ? input : new Erc7677Paymaster(input, options);
|
|
8594
|
+
}
|
|
8595
|
+
/**
|
|
8596
|
+
* Transport delegate. Forwards directly to {@link Transport.request}, so
|
|
8597
|
+
* an `Erc7677Paymaster` can be slotted into any other transport position.
|
|
8598
|
+
*/
|
|
8599
|
+
request(args, options) {
|
|
8600
|
+
return this.outbound.request(args, options);
|
|
8601
|
+
}
|
|
8602
|
+
/**
|
|
7815
8603
|
* Resolve the chain id, querying the bundler if not provided at construction.
|
|
7816
8604
|
*/
|
|
7817
8605
|
async getChainId(bundlerRpc) {
|
|
7818
8606
|
if (this.chainId != null) return this.chainId;
|
|
7819
|
-
const id = await
|
|
8607
|
+
const id = await Bundler.from(bundlerRpc).chainId();
|
|
7820
8608
|
this.chainId = id;
|
|
7821
8609
|
return id;
|
|
7822
8610
|
}
|
|
@@ -7840,12 +8628,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7840
8628
|
*/
|
|
7841
8629
|
async getPaymasterStubData(userOperation, entrypoint, chainIdHex, context = {}) {
|
|
7842
8630
|
try {
|
|
7843
|
-
return await
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
8631
|
+
return await this.outbound.request({
|
|
8632
|
+
method: "pm_getPaymasterStubData",
|
|
8633
|
+
params: [
|
|
8634
|
+
userOperation,
|
|
8635
|
+
entrypoint,
|
|
8636
|
+
chainIdHex,
|
|
8637
|
+
context
|
|
8638
|
+
]
|
|
8639
|
+
});
|
|
7849
8640
|
} catch (err) {
|
|
7850
8641
|
throw new AbstractionKitError("PAYMASTER_ERROR", "pm_getPaymasterStubData failed", { cause: ensureError(err) });
|
|
7851
8642
|
}
|
|
@@ -7856,12 +8647,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7856
8647
|
*/
|
|
7857
8648
|
async getPaymasterData(userOperation, entrypoint, chainIdHex, context = {}) {
|
|
7858
8649
|
try {
|
|
7859
|
-
return await
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
8650
|
+
return await this.outbound.request({
|
|
8651
|
+
method: "pm_getPaymasterData",
|
|
8652
|
+
params: [
|
|
8653
|
+
userOperation,
|
|
8654
|
+
entrypoint,
|
|
8655
|
+
chainIdHex,
|
|
8656
|
+
context
|
|
8657
|
+
]
|
|
8658
|
+
});
|
|
7865
8659
|
} catch (err) {
|
|
7866
8660
|
throw new AbstractionKitError("PAYMASTER_ERROR", "pm_getPaymasterData failed", { cause: ensureError(err) });
|
|
7867
8661
|
}
|
|
@@ -7876,7 +8670,10 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7876
8670
|
*/
|
|
7877
8671
|
async sendRPCRequest(method, params = []) {
|
|
7878
8672
|
try {
|
|
7879
|
-
return await
|
|
8673
|
+
return await this.outbound.request({
|
|
8674
|
+
method,
|
|
8675
|
+
params
|
|
8676
|
+
});
|
|
7880
8677
|
} catch (err) {
|
|
7881
8678
|
throw new AbstractionKitError("PAYMASTER_ERROR", `sendRPCRequest(${method}) failed`, { cause: ensureError(err) });
|
|
7882
8679
|
}
|
|
@@ -7938,7 +8735,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7938
8735
|
let callGasLimit = userOp.callGasLimit;
|
|
7939
8736
|
if (overrides.preVerificationGas == null || overrides.verificationGasLimit == null || overrides.callGasLimit == null) {
|
|
7940
8737
|
if (bundlerRpc == null) throw new AbstractionKitError("BAD_DATA", "bundlerRpc can't be null if preVerificationGas, verificationGasLimit and callGasLimit are not overridden");
|
|
7941
|
-
const bundler =
|
|
8738
|
+
const bundler = Bundler.from(bundlerRpc);
|
|
7942
8739
|
userOp.callGasLimit = 0n;
|
|
7943
8740
|
userOp.verificationGasLimit = 0n;
|
|
7944
8741
|
userOp.preVerificationGas = 0n;
|
|
@@ -7978,11 +8775,14 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
7978
8775
|
* approval amount via `(exchangeRate * gasCostWei) / 10^18`.
|
|
7979
8776
|
*/
|
|
7980
8777
|
async fetchPimlicoTokenQuote(tokenAddress, entrypoint, chainIdHex) {
|
|
7981
|
-
const quotes = (await
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
8778
|
+
const quotes = (await this.outbound.request({
|
|
8779
|
+
method: "pimlico_getTokenQuotes",
|
|
8780
|
+
params: [
|
|
8781
|
+
{ tokens: [tokenAddress] },
|
|
8782
|
+
entrypoint,
|
|
8783
|
+
chainIdHex
|
|
8784
|
+
]
|
|
8785
|
+
}))?.quotes;
|
|
7986
8786
|
if (!Array.isArray(quotes) || quotes.length === 0) throw new AbstractionKitError("PAYMASTER_ERROR", `pimlico_getTokenQuotes returned no quotes for token ${tokenAddress}`);
|
|
7987
8787
|
const quote = quotes.find((q) => q.token.toLowerCase() === tokenAddress.toLowerCase());
|
|
7988
8788
|
if (quote == null) throw new AbstractionKitError("PAYMASTER_ERROR", `pimlico_getTokenQuotes did not include token ${tokenAddress}`);
|
|
@@ -8008,7 +8808,10 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8008
8808
|
const cached = this.candideCache.get(key);
|
|
8009
8809
|
const isStale = cached != null && options.enforceTTL === true && Date.now() - cached.fetchedAt > CANDIDE_TOKEN_QUOTE_TTL_MS;
|
|
8010
8810
|
if (cached != null && !isStale) return cached.data;
|
|
8011
|
-
const result = await
|
|
8811
|
+
const result = await this.outbound.request({
|
|
8812
|
+
method: "pm_supportedERC20Tokens",
|
|
8813
|
+
params: [entrypoint]
|
|
8814
|
+
});
|
|
8012
8815
|
this.candideCache.set(key, {
|
|
8013
8816
|
data: result,
|
|
8014
8817
|
fetchedAt: Date.now()
|
|
@@ -8185,7 +8988,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8185
8988
|
let verificationGasLimit = userOperation.verificationGasLimit;
|
|
8186
8989
|
let callGasLimit = userOperation.callGasLimit;
|
|
8187
8990
|
userOperation.preVerificationGas = 0n;
|
|
8188
|
-
const estimation = await
|
|
8991
|
+
const estimation = await Bundler.from(bundlerRpc).estimateUserOperationGas(userOperation, entrypointAddress, overrides.state_override_set);
|
|
8189
8992
|
if (preVerificationGas < estimation.preVerificationGas) preVerificationGas = estimation.preVerificationGas;
|
|
8190
8993
|
if (verificationGasLimit < estimation.verificationGasLimit) verificationGasLimit = estimation.verificationGasLimit;
|
|
8191
8994
|
if (callGasLimit < estimation.callGasLimit) callGasLimit = estimation.callGasLimit;
|
|
@@ -8570,6 +9373,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8570
9373
|
ALLOWANCE_MODULE_V0_1_0_ADDRESS: () => ALLOWANCE_MODULE_V0_1_0_ADDRESS,
|
|
8571
9374
|
AbstractionKitError: () => AbstractionKitError,
|
|
8572
9375
|
AllowanceModule: () => AllowanceModule,
|
|
9376
|
+
BaseRpcTransport: () => BaseRpcTransport,
|
|
8573
9377
|
BaseUserOperationDummyValues: () => BaseUserOperationDummyValues,
|
|
8574
9378
|
Bundler: () => Bundler,
|
|
8575
9379
|
CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS: () => CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS,
|
|
@@ -8593,6 +9397,8 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8593
9397
|
Erc7677Paymaster: () => Erc7677Paymaster,
|
|
8594
9398
|
ExperimentalAllowAllParallelPaymaster: () => ExperimentalAllowAllParallelPaymaster,
|
|
8595
9399
|
GasOption: () => GasOption,
|
|
9400
|
+
HttpTransport: () => HttpTransport,
|
|
9401
|
+
JsonRpcNode: () => JsonRpcNode,
|
|
8596
9402
|
Operation: () => Operation,
|
|
8597
9403
|
PolygonChain: () => PolygonChain,
|
|
8598
9404
|
SAFE_MESSAGE_MODULE_TYPE: () => SAFE_MESSAGE_MODULE_TYPE,
|
|
@@ -8610,6 +9416,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8610
9416
|
SmartAccountFactory: () => SmartAccountFactory,
|
|
8611
9417
|
SocialRecoveryModule: () => SocialRecoveryModule,
|
|
8612
9418
|
SocialRecoveryModuleGracePeriodSelector: () => SocialRecoveryModuleGracePeriodSelector,
|
|
9419
|
+
TransportRpcError: () => TransportRpcError,
|
|
8613
9420
|
WebauthnDummySignerSignaturePair: () => WebauthnDummySignerSignaturePair,
|
|
8614
9421
|
WorldIdPermissionlessPaymaster: () => WorldIdPermissionlessPaymaster,
|
|
8615
9422
|
ZeroAddress: () => ZeroAddress,
|
|
@@ -8624,17 +9431,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8624
9431
|
createUserOperationHash: () => createUserOperationHash,
|
|
8625
9432
|
createWorldIdSignal: () => createWorldIdSignal,
|
|
8626
9433
|
fetchAccountNonce: () => fetchAccountNonce,
|
|
8627
|
-
fetchGasPrice: () => fetchGasPrice,
|
|
8628
9434
|
fromEthersWallet: () => fromEthersWallet,
|
|
8629
9435
|
fromPrivateKey: () => fromPrivateKey,
|
|
8630
9436
|
fromSafeWebauthn: () => fromSafeWebauthn,
|
|
8631
9437
|
fromViem: () => fromViem,
|
|
8632
9438
|
fromViemWalletClient: () => fromViemWalletClient,
|
|
8633
|
-
getBalanceOf: () => getBalanceOf,
|
|
8634
|
-
getDelegatedAddress: () => getDelegatedAddress,
|
|
8635
|
-
getDepositInfo: () => getDepositInfo,
|
|
8636
9439
|
getFunctionSelector: () => getFunctionSelector,
|
|
8637
9440
|
getSafeMessageEip712Data: () => getSafeMessageEip712Data,
|
|
9441
|
+
isEventfulTransport: () => isEventfulTransport,
|
|
9442
|
+
isHttpTransport: () => isHttpTransport,
|
|
8638
9443
|
pubkeyCoordinatesFromJson: () => pubkeyCoordinatesFromJson,
|
|
8639
9444
|
pubkeyCoordinatesToJson: () => pubkeyCoordinatesToJson,
|
|
8640
9445
|
sendJsonRpcRequest: () => sendJsonRpcRequest,
|
|
@@ -8652,6 +9457,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8652
9457
|
exports.ALLOWANCE_MODULE_V0_1_0_ADDRESS = ALLOWANCE_MODULE_V0_1_0_ADDRESS;
|
|
8653
9458
|
exports.AbstractionKitError = AbstractionKitError;
|
|
8654
9459
|
exports.AllowanceModule = AllowanceModule;
|
|
9460
|
+
exports.BaseRpcTransport = BaseRpcTransport;
|
|
8655
9461
|
exports.BaseUserOperationDummyValues = BaseUserOperationDummyValues;
|
|
8656
9462
|
exports.Bundler = Bundler;
|
|
8657
9463
|
exports.CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS = CALIBUR_CANDIDE_V0_1_0_SINGLETON_ADDRESS;
|
|
@@ -8675,6 +9481,8 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8675
9481
|
exports.Erc7677Paymaster = Erc7677Paymaster;
|
|
8676
9482
|
exports.ExperimentalAllowAllParallelPaymaster = ExperimentalAllowAllParallelPaymaster;
|
|
8677
9483
|
exports.GasOption = GasOption;
|
|
9484
|
+
exports.HttpTransport = HttpTransport;
|
|
9485
|
+
exports.JsonRpcNode = JsonRpcNode;
|
|
8678
9486
|
exports.Operation = Operation;
|
|
8679
9487
|
exports.PolygonChain = PolygonChain;
|
|
8680
9488
|
exports.SAFE_MESSAGE_MODULE_TYPE = SAFE_MESSAGE_MODULE_TYPE;
|
|
@@ -8692,6 +9500,7 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8692
9500
|
exports.SmartAccountFactory = SmartAccountFactory;
|
|
8693
9501
|
exports.SocialRecoveryModule = SocialRecoveryModule;
|
|
8694
9502
|
exports.SocialRecoveryModuleGracePeriodSelector = SocialRecoveryModuleGracePeriodSelector;
|
|
9503
|
+
exports.TransportRpcError = TransportRpcError;
|
|
8695
9504
|
exports.WebauthnDummySignerSignaturePair = WebauthnDummySignerSignaturePair;
|
|
8696
9505
|
exports.WorldIdPermissionlessPaymaster = WorldIdPermissionlessPaymaster;
|
|
8697
9506
|
exports.ZeroAddress = ZeroAddress;
|
|
@@ -8712,17 +9521,15 @@ var abstractionkit = (function(exports, ethers) {
|
|
|
8712
9521
|
exports.createUserOperationHash = createUserOperationHash;
|
|
8713
9522
|
exports.createWorldIdSignal = createWorldIdSignal;
|
|
8714
9523
|
exports.fetchAccountNonce = fetchAccountNonce;
|
|
8715
|
-
exports.fetchGasPrice = fetchGasPrice;
|
|
8716
9524
|
exports.fromEthersWallet = fromEthersWallet;
|
|
8717
9525
|
exports.fromPrivateKey = fromPrivateKey;
|
|
8718
9526
|
exports.fromSafeWebauthn = fromSafeWebauthn;
|
|
8719
9527
|
exports.fromViem = fromViem;
|
|
8720
9528
|
exports.fromViemWalletClient = fromViemWalletClient;
|
|
8721
|
-
exports.getBalanceOf = getBalanceOf;
|
|
8722
|
-
exports.getDelegatedAddress = getDelegatedAddress;
|
|
8723
|
-
exports.getDepositInfo = getDepositInfo;
|
|
8724
9529
|
exports.getFunctionSelector = getFunctionSelector;
|
|
8725
9530
|
exports.getSafeMessageEip712Data = getSafeMessageEip712Data;
|
|
9531
|
+
exports.isEventfulTransport = isEventfulTransport;
|
|
9532
|
+
exports.isHttpTransport = isHttpTransport;
|
|
8726
9533
|
exports.pubkeyCoordinatesFromJson = pubkeyCoordinatesFromJson;
|
|
8727
9534
|
exports.pubkeyCoordinatesToJson = pubkeyCoordinatesToJson;
|
|
8728
9535
|
exports.sendJsonRpcRequest = sendJsonRpcRequest;
|