@safe-global/relay-kit 3.3.1 → 3.4.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/cjs/src/index.cjs +1323 -0
  2. package/dist/cjs/test-utils/index.cjs +1171 -0
  3. package/dist/esm/src/index.mjs +1326 -0
  4. package/dist/esm/test-utils/index.mjs +1172 -0
  5. package/dist/src/RelayKitBasePack.d.ts +1 -0
  6. package/dist/src/RelayKitBasePack.d.ts.map +1 -0
  7. package/dist/src/constants.d.ts +1 -0
  8. package/dist/src/constants.d.ts.map +1 -0
  9. package/dist/src/deprecated.d.ts +1 -0
  10. package/dist/src/deprecated.d.ts.map +1 -0
  11. package/dist/src/index.d.ts +2 -0
  12. package/dist/src/index.d.ts.map +1 -0
  13. package/dist/src/packs/gelato/GelatoRelayPack.d.ts +1 -0
  14. package/dist/src/packs/gelato/GelatoRelayPack.d.ts.map +1 -0
  15. package/dist/src/packs/gelato/types.d.ts +1 -0
  16. package/dist/src/packs/gelato/types.d.ts.map +1 -0
  17. package/dist/src/packs/safe-4337/Safe4337Pack.d.ts +3 -1
  18. package/dist/src/packs/safe-4337/Safe4337Pack.d.ts.map +1 -0
  19. package/dist/src/packs/safe-4337/SafeOperation.d.ts +1 -0
  20. package/dist/src/packs/safe-4337/SafeOperation.d.ts.map +1 -0
  21. package/dist/src/packs/safe-4337/constants.d.ts +1 -0
  22. package/dist/src/packs/safe-4337/constants.d.ts.map +1 -0
  23. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.d.ts +1 -0
  24. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.d.ts.map +1 -0
  25. package/dist/src/packs/safe-4337/estimators/index.d.ts +1 -0
  26. package/dist/src/packs/safe-4337/estimators/index.d.ts.map +1 -0
  27. package/dist/src/packs/safe-4337/types.d.ts +4 -1
  28. package/dist/src/packs/safe-4337/types.d.ts.map +1 -0
  29. package/dist/src/packs/safe-4337/utils/entrypoint.d.ts +1 -0
  30. package/dist/src/packs/safe-4337/utils/entrypoint.d.ts.map +1 -0
  31. package/dist/src/packs/safe-4337/utils/getRelayKitVersion.d.ts +2 -0
  32. package/dist/src/packs/safe-4337/utils/getRelayKitVersion.d.ts.map +1 -0
  33. package/dist/src/packs/safe-4337/utils.d.ts +1 -0
  34. package/dist/src/packs/safe-4337/utils.d.ts.map +1 -0
  35. package/dist/{src/packs/safe-4337/testing-utils → test-utils}/fixtures.d.ts +1 -0
  36. package/dist/test-utils/fixtures.d.ts.map +1 -0
  37. package/dist/{src/packs/safe-4337/testing-utils → test-utils}/helpers.d.ts +3 -2
  38. package/dist/test-utils/helpers.d.ts.map +1 -0
  39. package/dist/test-utils/index.d.ts +4 -0
  40. package/dist/test-utils/index.d.ts.map +1 -0
  41. package/dist/tsconfig.build.tsbuildinfo +1 -1
  42. package/package.json +23 -6
  43. package/dist/src/RelayKitBasePack.js +0 -26
  44. package/dist/src/RelayKitBasePack.js.map +0 -1
  45. package/dist/src/constants.js +0 -12
  46. package/dist/src/constants.js.map +0 -1
  47. package/dist/src/deprecated.js +0 -3
  48. package/dist/src/deprecated.js.map +0 -1
  49. package/dist/src/index.js +0 -30
  50. package/dist/src/index.js.map +0 -1
  51. package/dist/src/packs/gelato/GelatoRelayPack.js +0 -327
  52. package/dist/src/packs/gelato/GelatoRelayPack.js.map +0 -1
  53. package/dist/src/packs/gelato/types.js +0 -3
  54. package/dist/src/packs/gelato/types.js.map +0 -1
  55. package/dist/src/packs/safe-4337/Safe4337Pack.js +0 -619
  56. package/dist/src/packs/safe-4337/Safe4337Pack.js.map +0 -1
  57. package/dist/src/packs/safe-4337/SafeOperation.js +0 -68
  58. package/dist/src/packs/safe-4337/SafeOperation.js.map +0 -1
  59. package/dist/src/packs/safe-4337/constants.js +0 -55
  60. package/dist/src/packs/safe-4337/constants.js.map +0 -1
  61. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.js +0 -49
  62. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.js.map +0 -1
  63. package/dist/src/packs/safe-4337/estimators/index.js +0 -6
  64. package/dist/src/packs/safe-4337/estimators/index.js.map +0 -1
  65. package/dist/src/packs/safe-4337/testing-utils/fixtures.js +0 -128
  66. package/dist/src/packs/safe-4337/testing-utils/fixtures.js.map +0 -1
  67. package/dist/src/packs/safe-4337/testing-utils/helpers.js +0 -58
  68. package/dist/src/packs/safe-4337/testing-utils/helpers.js.map +0 -1
  69. package/dist/src/packs/safe-4337/types.js +0 -3
  70. package/dist/src/packs/safe-4337/types.js.map +0 -1
  71. package/dist/src/packs/safe-4337/utils/entrypoint.js +0 -23
  72. package/dist/src/packs/safe-4337/utils/entrypoint.js.map +0 -1
  73. package/dist/src/packs/safe-4337/utils.js +0 -190
  74. package/dist/src/packs/safe-4337/utils.js.map +0 -1
@@ -0,0 +1,1323 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ DUMMY_AUTHENTICATOR_DATA: () => DUMMY_AUTHENTICATOR_DATA,
34
+ DUMMY_CLIENT_DATA_FIELDS: () => DUMMY_CLIENT_DATA_FIELDS,
35
+ EthSafeOperation: () => SafeOperation_default,
36
+ GelatoRelayPack: () => GelatoRelayPack,
37
+ PimlicoFeeEstimator: () => PimlicoFeeEstimator,
38
+ RelayKitBasePack: () => RelayKitBasePack,
39
+ Safe4337Pack: () => Safe4337Pack,
40
+ addDummySignature: () => addDummySignature,
41
+ calculateSafeUserOperationHash: () => calculateSafeUserOperationHash,
42
+ encodeMultiSendCallData: () => encodeMultiSendCallData,
43
+ getEip4337BundlerProvider: () => getEip4337BundlerProvider,
44
+ getSignatureBytes: () => getSignatureBytes,
45
+ signSafeOp: () => signSafeOp,
46
+ userOperationToHexValues: () => userOperationToHexValues
47
+ });
48
+ module.exports = __toCommonJS(src_exports);
49
+
50
+ // src/packs/gelato/GelatoRelayPack.ts
51
+ var import_relay_sdk = require("@gelatonetwork/relay-sdk");
52
+ var import_protocol_kit = require("@safe-global/protocol-kit");
53
+
54
+ // src/RelayKitBasePack.ts
55
+ var RelayKitBasePack = class {
56
+ /**
57
+ * Creates a new RelayKitBasePack instance.
58
+ * The packs implemented using our SDK should extend this class and therefore provide a Safe SDK instance
59
+ * @param {Safe} protocolKit - The Safe SDK instance
60
+ */
61
+ constructor(protocolKit) {
62
+ this.protocolKit = protocolKit;
63
+ }
64
+ };
65
+
66
+ // src/constants.ts
67
+ var GELATO_NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
68
+ var GELATO_FEE_COLLECTOR = "0x3AC05161b76a35c1c28dC99Aa01BEd7B24cEA3bf";
69
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
70
+ var GELATO_GAS_EXECUTION_OVERHEAD = 15e4;
71
+ var GELATO_TRANSFER_GAS_COST = 15e3;
72
+
73
+ // src/packs/gelato/GelatoRelayPack.ts
74
+ var GelatoRelayPack = class extends RelayKitBasePack {
75
+ #gelatoRelay;
76
+ #apiKey;
77
+ constructor({ apiKey, protocolKit }) {
78
+ super(protocolKit);
79
+ this.#gelatoRelay = new import_relay_sdk.GelatoRelay();
80
+ this.#apiKey = apiKey;
81
+ }
82
+ _getFeeToken(gasToken) {
83
+ return !gasToken || gasToken === ZERO_ADDRESS ? GELATO_NATIVE_TOKEN_ADDRESS : gasToken;
84
+ }
85
+ getFeeCollector() {
86
+ return GELATO_FEE_COLLECTOR;
87
+ }
88
+ async getEstimateFee(propsOrChainId, inputGasLimit, inputGasToken) {
89
+ let chainId;
90
+ let gasLimit;
91
+ let gasToken;
92
+ if (typeof propsOrChainId === "object") {
93
+ ;
94
+ ({ chainId, gasLimit, gasToken } = propsOrChainId);
95
+ } else {
96
+ chainId = propsOrChainId;
97
+ gasLimit = inputGasLimit;
98
+ gasToken = inputGasToken;
99
+ }
100
+ const feeToken = this._getFeeToken(gasToken);
101
+ const estimation = await this.#gelatoRelay.getEstimatedFee(
102
+ chainId,
103
+ feeToken,
104
+ BigInt(gasLimit),
105
+ false
106
+ );
107
+ return estimation.toString();
108
+ }
109
+ async getTaskStatus(taskId) {
110
+ return this.#gelatoRelay.getTaskStatus(taskId);
111
+ }
112
+ /**
113
+ * Creates a payment transaction to Gelato
114
+ *
115
+ * @private
116
+ * @async
117
+ * @function
118
+ * @param {string} gas - The gas amount for the payment.
119
+ * @param {MetaTransactionOptions} options - Options for the meta transaction.
120
+ * @returns {Promise<Transaction>} Promise object representing the created payment transaction.
121
+ *
122
+ */
123
+ async createPaymentToGelato(gas, options) {
124
+ const chainId = await this.protocolKit.getChainId();
125
+ const gelatoAddress = this.getFeeCollector();
126
+ const gasToken = options.gasToken ?? ZERO_ADDRESS;
127
+ const paymentToGelato = await this.getEstimateFee({ chainId, gasLimit: gas, gasToken });
128
+ const transferToGelato = (0, import_protocol_kit.createERC20TokenTransferTransaction)(
129
+ gasToken,
130
+ gelatoAddress,
131
+ paymentToGelato
132
+ );
133
+ return transferToGelato;
134
+ }
135
+ /**
136
+ * @deprecated Use createTransaction instead
137
+ */
138
+ async createRelayedTransaction({
139
+ transactions,
140
+ onlyCalls = false,
141
+ options = {}
142
+ }) {
143
+ return this.createTransaction({ transactions, onlyCalls, options });
144
+ }
145
+ /**
146
+ * Creates a Safe transaction designed to be executed using the Gelato Relayer.
147
+ *
148
+ * @param {GelatoCreateTransactionProps} options - Options for Gelato.
149
+ * @param {MetaTransactionData[]} [options.transactions] - The transactions batch.
150
+ * @param {boolean} [options.onlyCalls=false] - If true, MultiSendCallOnly contract should be used. Remember to not use delegate calls in the batch.
151
+ * @param {MetaTransactionOptions} [options.options={}] - Gas Options for the transaction batch.
152
+ * @returns {Promise<SafeTransaction>} Returns a Promise that resolves with a SafeTransaction object.
153
+ */
154
+ async createTransaction({
155
+ transactions,
156
+ onlyCalls = false,
157
+ options = {}
158
+ }) {
159
+ const { isSponsored = false } = options;
160
+ if (isSponsored) {
161
+ const nonce = await this.protocolKit.getNonce();
162
+ const sponsoredTransaction = await this.protocolKit.createTransaction({
163
+ transactions,
164
+ onlyCalls,
165
+ options: {
166
+ nonce
167
+ }
168
+ });
169
+ return sponsoredTransaction;
170
+ }
171
+ const gasToken = options.gasToken ?? ZERO_ADDRESS;
172
+ const isGasTokenCompatible = await (0, import_protocol_kit.isGasTokenCompatibleWithHandlePayment)(
173
+ gasToken,
174
+ this.protocolKit
175
+ );
176
+ if (!isGasTokenCompatible) {
177
+ return this.createTransactionWithTransfer({ transactions, onlyCalls, options });
178
+ }
179
+ return this.createTransactionWithHandlePayment({ transactions, onlyCalls, options });
180
+ }
181
+ /**
182
+ * Creates a Safe transaction designed to be executed using the Gelato Relayer and
183
+ * uses the handlePayment function defined in the Safe contract to pay the fees
184
+ * to the Gelato relayer.
185
+ *
186
+ * @async
187
+ * @function createTransactionWithHandlePayment
188
+ * @param {GelatoCreateTransactionProps} options - Options for Gelato.
189
+ * @param {MetaTransactionData[]} [options.transactions] - The transactions batch.
190
+ * @param {boolean} [options.onlyCalls=false] - If true, MultiSendCallOnly contract should be used. Remember to not use delegate calls in the batch.
191
+ * @param {MetaTransactionOptions} [options.options={}] - Gas Options for the transaction batch.
192
+ * @returns {Promise<SafeTransaction>} Returns a promise that resolves to the created SafeTransaction.
193
+ * @private
194
+ */
195
+ async createTransactionWithHandlePayment({
196
+ transactions,
197
+ onlyCalls = false,
198
+ options = {}
199
+ }) {
200
+ const { gasLimit } = options;
201
+ const nonce = await this.protocolKit.getNonce();
202
+ const transactionToEstimateGas = await this.protocolKit.createTransaction({
203
+ transactions,
204
+ onlyCalls,
205
+ options: {
206
+ nonce
207
+ }
208
+ });
209
+ const gasPrice = "1";
210
+ const safeTxGas = await (0, import_protocol_kit.estimateSafeTxGas)(this.protocolKit, transactionToEstimateGas);
211
+ const gasToken = options.gasToken ?? ZERO_ADDRESS;
212
+ const refundReceiver = this.getFeeCollector();
213
+ const chainId = await this.protocolKit.getChainId();
214
+ if (gasLimit) {
215
+ const paymentToGelato2 = await this.getEstimateFee({ chainId, gasLimit, gasToken });
216
+ const syncTransaction2 = await this.protocolKit.createTransaction({
217
+ transactions,
218
+ onlyCalls,
219
+ options: {
220
+ baseGas: paymentToGelato2,
221
+ gasPrice,
222
+ safeTxGas,
223
+ gasToken,
224
+ refundReceiver,
225
+ nonce
226
+ }
227
+ });
228
+ return syncTransaction2;
229
+ }
230
+ const baseGas = await (0, import_protocol_kit.estimateTxBaseGas)(this.protocolKit, transactionToEstimateGas);
231
+ const safeDeploymentGasCost = await (0, import_protocol_kit.estimateSafeDeploymentGas)(this.protocolKit);
232
+ const totalGas = Number(baseGas) + // baseGas
233
+ Number(safeTxGas) + // safeTxGas
234
+ Number(safeDeploymentGasCost) + // Safe deploymet gas cost if it is required
235
+ GELATO_GAS_EXECUTION_OVERHEAD;
236
+ const paymentToGelato = await this.getEstimateFee({
237
+ chainId,
238
+ gasLimit: String(totalGas),
239
+ gasToken
240
+ });
241
+ const syncTransaction = await this.protocolKit.createTransaction({
242
+ transactions,
243
+ onlyCalls,
244
+ options: {
245
+ baseGas: paymentToGelato,
246
+ // payment to Gelato
247
+ gasPrice,
248
+ safeTxGas,
249
+ gasToken,
250
+ refundReceiver,
251
+ nonce
252
+ }
253
+ });
254
+ return syncTransaction;
255
+ }
256
+ /**
257
+ * Creates a Safe transaction designed to be executed using the Gelato Relayer and
258
+ * uses a separate ERC20 transfer to pay the fees to the Gelato relayer.
259
+ *
260
+ * @async
261
+ * @function createTransactionWithTransfer
262
+ * @param {GelatoCreateTransactionProps} options - Options for Gelato.
263
+ * @param {MetaTransactionData[]} [options.transactions] - The transactions batch.
264
+ * @param {boolean} [options.onlyCalls=false] - If true, MultiSendCallOnly contract should be used. Remember to not use delegate calls in the batch.
265
+ * @param {MetaTransactionOptions} [options.options={}] - Gas Options for the transaction batch.
266
+ * @returns {Promise<SafeTransaction>} Returns a promise that resolves to the created SafeTransaction.
267
+ * @private
268
+ */
269
+ async createTransactionWithTransfer({
270
+ transactions,
271
+ onlyCalls = false,
272
+ options = {}
273
+ }) {
274
+ const { gasLimit } = options;
275
+ const nonce = await this.protocolKit.getNonce();
276
+ const gasToken = options.gasToken ?? ZERO_ADDRESS;
277
+ if (gasLimit) {
278
+ const transferToGelato2 = await this.createPaymentToGelato(gasLimit, options);
279
+ const syncTransaction2 = await this.protocolKit.createTransaction({
280
+ transactions: [...transactions, transferToGelato2],
281
+ onlyCalls,
282
+ options: {
283
+ nonce,
284
+ gasToken
285
+ }
286
+ });
287
+ return syncTransaction2;
288
+ }
289
+ const transactionToEstimateGas = await this.protocolKit.createTransaction({
290
+ transactions,
291
+ onlyCalls,
292
+ options: {
293
+ nonce
294
+ }
295
+ });
296
+ const safeTxGas = await (0, import_protocol_kit.estimateSafeTxGas)(this.protocolKit, transactionToEstimateGas);
297
+ const baseGas = await (0, import_protocol_kit.estimateTxBaseGas)(this.protocolKit, transactionToEstimateGas);
298
+ const safeDeploymentGasCost = await (0, import_protocol_kit.estimateSafeDeploymentGas)(this.protocolKit);
299
+ const totalGas = Number(baseGas) + // baseGas
300
+ Number(safeTxGas) + // safeTxGas without Gelato payment transfer
301
+ Number(safeDeploymentGasCost) + // Safe deploymet gas cost if it is required
302
+ GELATO_TRANSFER_GAS_COST + // Gelato payment transfer
303
+ GELATO_GAS_EXECUTION_OVERHEAD;
304
+ const transferToGelato = await this.createPaymentToGelato(String(totalGas), options);
305
+ const syncTransaction = await this.protocolKit.createTransaction({
306
+ transactions: [...transactions, transferToGelato],
307
+ onlyCalls,
308
+ options: {
309
+ nonce,
310
+ gasToken
311
+ }
312
+ });
313
+ return syncTransaction;
314
+ }
315
+ async sendSponsorTransaction(target, encodedTransaction, chainId) {
316
+ if (!this.#apiKey) {
317
+ throw new Error("API key not defined");
318
+ }
319
+ const request = {
320
+ chainId,
321
+ target,
322
+ data: encodedTransaction
323
+ };
324
+ const response = await this.#gelatoRelay.sponsoredCall(request, this.#apiKey);
325
+ return response;
326
+ }
327
+ async sendSyncTransaction(target, encodedTransaction, chainId, options) {
328
+ const { gasLimit, gasToken } = options;
329
+ const feeToken = this._getFeeToken(gasToken);
330
+ const request = {
331
+ chainId,
332
+ target,
333
+ data: encodedTransaction,
334
+ feeToken,
335
+ isRelayContext: false
336
+ };
337
+ const relayRequestOptions = {
338
+ gasLimit: gasLimit ? BigInt(gasLimit) : void 0
339
+ };
340
+ const response = await this.#gelatoRelay.callWithSyncFee(request, relayRequestOptions);
341
+ return response;
342
+ }
343
+ async relayTransaction({
344
+ target,
345
+ encodedTransaction,
346
+ chainId,
347
+ options = {}
348
+ }) {
349
+ const response = options.isSponsored ? this.sendSponsorTransaction(target, encodedTransaction, chainId) : this.sendSyncTransaction(target, encodedTransaction, chainId, options);
350
+ return response;
351
+ }
352
+ /**
353
+ * @deprecated Use executeTransaction instead
354
+ */
355
+ async executeRelayTransaction(safeTransaction, options) {
356
+ return this.executeTransaction({ executable: safeTransaction, options });
357
+ }
358
+ /**
359
+ * Sends the Safe transaction to the Gelato Relayer for execution.
360
+ * If the Safe is not deployed, it creates a batch of transactions including the Safe deployment transaction.
361
+ *
362
+ * @param {GelatoExecuteTransactionProps} props - Execution props
363
+ * @param {SafeTransaction} props.executable - The Safe transaction to be executed.
364
+ * @param {MetaTransactionOptions} props.options - Options for the transaction.
365
+ * @returns {Promise<RelayResponse>} Returns a Promise that resolves with a RelayResponse object.
366
+ */
367
+ async executeTransaction({
368
+ executable: safeTransaction,
369
+ options
370
+ }) {
371
+ const isSafeDeployed = await this.protocolKit.isSafeDeployed();
372
+ const chainId = await this.protocolKit.getChainId();
373
+ const safeAddress = await this.protocolKit.getAddress();
374
+ const safeTransactionEncodedData = await this.protocolKit.getEncodedTransaction(safeTransaction);
375
+ const gasToken = options?.gasToken || safeTransaction.data.gasToken;
376
+ if (isSafeDeployed) {
377
+ const relayTransaction2 = {
378
+ target: safeAddress,
379
+ encodedTransaction: safeTransactionEncodedData,
380
+ chainId,
381
+ options: {
382
+ ...options,
383
+ gasToken
384
+ }
385
+ };
386
+ return this.relayTransaction(relayTransaction2);
387
+ }
388
+ const safeDeploymentBatch = await this.protocolKit.wrapSafeTransactionIntoDeploymentBatch(safeTransaction);
389
+ const relayTransaction = {
390
+ target: safeDeploymentBatch.to,
391
+ // multiSend Contract address
392
+ encodedTransaction: safeDeploymentBatch.data,
393
+ chainId,
394
+ options: {
395
+ ...options,
396
+ gasToken
397
+ }
398
+ };
399
+ return this.relayTransaction(relayTransaction);
400
+ }
401
+ };
402
+
403
+ // src/packs/safe-4337/Safe4337Pack.ts
404
+ var import_satisfies = __toESM(require("semver/functions/satisfies.js"));
405
+ var import_protocol_kit4 = __toESM(require("@safe-global/protocol-kit"));
406
+ var import_types_kit2 = require("@safe-global/types-kit");
407
+ var import_safe_modules_deployments = require("@safe-global/safe-modules-deployments");
408
+ var import_viem4 = require("viem");
409
+
410
+ // src/packs/safe-4337/SafeOperation.ts
411
+ var import_viem3 = require("viem");
412
+ var import_protocol_kit3 = require("@safe-global/protocol-kit");
413
+
414
+ // src/packs/safe-4337/utils.ts
415
+ var import_viem2 = require("viem");
416
+ var import_types_kit = require("@safe-global/types-kit");
417
+ var import_protocol_kit2 = require("@safe-global/protocol-kit");
418
+
419
+ // src/packs/safe-4337/constants.ts
420
+ var import_viem = require("viem");
421
+ var DEFAULT_SAFE_VERSION = "1.4.1";
422
+ var DEFAULT_SAFE_MODULES_VERSION = "0.2.0";
423
+ var EIP712_SAFE_OPERATION_TYPE = {
424
+ SafeOp: [
425
+ { type: "address", name: "safe" },
426
+ { type: "uint256", name: "nonce" },
427
+ { type: "bytes", name: "initCode" },
428
+ { type: "bytes", name: "callData" },
429
+ { type: "uint256", name: "callGasLimit" },
430
+ { type: "uint256", name: "verificationGasLimit" },
431
+ { type: "uint256", name: "preVerificationGas" },
432
+ { type: "uint256", name: "maxFeePerGas" },
433
+ { type: "uint256", name: "maxPriorityFeePerGas" },
434
+ { type: "bytes", name: "paymasterAndData" },
435
+ { type: "uint48", name: "validAfter" },
436
+ { type: "uint48", name: "validUntil" },
437
+ { type: "address", name: "entryPoint" }
438
+ ]
439
+ };
440
+ var ABI = (0, import_viem.parseAbi)([
441
+ "function enableModules(address[])",
442
+ "function multiSend(bytes memory transactions) public payable",
443
+ "function executeUserOp(address to, uint256 value, bytes data, uint8 operation)",
444
+ "function approve(address _spender, uint256 _value)",
445
+ "function configure((uint256 x, uint256 y, uint176 verifiers) signer)"
446
+ ]);
447
+ var ENTRYPOINT_ABI = [
448
+ {
449
+ inputs: [
450
+ { name: "sender", type: "address" },
451
+ { name: "key", type: "uint192" }
452
+ ],
453
+ name: "getNonce",
454
+ outputs: [{ name: "nonce", type: "uint256" }],
455
+ stateMutability: "view",
456
+ type: "function"
457
+ }
458
+ ];
459
+ var ENTRYPOINT_ADDRESS_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
460
+ var ENTRYPOINT_ADDRESS_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
461
+
462
+ // src/packs/safe-4337/utils.ts
463
+ function getEip4337BundlerProvider(bundlerUrl) {
464
+ const provider = (0, import_viem2.createPublicClient)({
465
+ transport: (0, import_viem2.http)(bundlerUrl),
466
+ rpcSchema: (0, import_viem2.rpcSchema)()
467
+ });
468
+ return provider;
469
+ }
470
+ async function signSafeOp(safeUserOperation, safeProvider, safe4337ModuleAddress) {
471
+ const signer = await safeProvider.getExternalSigner();
472
+ if (!signer) {
473
+ throw new Error("No signer found");
474
+ }
475
+ const chainId = await safeProvider.getChainId();
476
+ const signerAddress = signer.account.address;
477
+ const signature = await signer.signTypedData({
478
+ domain: {
479
+ chainId: Number(chainId),
480
+ verifyingContract: safe4337ModuleAddress
481
+ },
482
+ types: EIP712_SAFE_OPERATION_TYPE,
483
+ message: {
484
+ ...safeUserOperation,
485
+ nonce: (0, import_viem2.toHex)(safeUserOperation.nonce),
486
+ validAfter: (0, import_viem2.toHex)(safeUserOperation.validAfter),
487
+ validUntil: (0, import_viem2.toHex)(safeUserOperation.validUntil),
488
+ maxFeePerGas: (0, import_viem2.toHex)(safeUserOperation.maxFeePerGas),
489
+ maxPriorityFeePerGas: (0, import_viem2.toHex)(safeUserOperation.maxPriorityFeePerGas)
490
+ },
491
+ primaryType: "SafeOp"
492
+ });
493
+ return new import_protocol_kit2.EthSafeSignature(signerAddress, signature);
494
+ }
495
+ function encodeMultiSendCallData(transactions) {
496
+ return (0, import_viem2.encodeFunctionData)({
497
+ abi: ABI,
498
+ functionName: "multiSend",
499
+ args: [
500
+ (0, import_protocol_kit2.encodeMultiSendData)(
501
+ transactions.map((tx) => ({ ...tx, operation: tx.operation ?? import_types_kit.OperationType.Call }))
502
+ )
503
+ ]
504
+ });
505
+ }
506
+ function calculateSafeUserOperationHash(safeUserOperation, chainId, safe4337ModuleAddress) {
507
+ return (0, import_viem2.hashTypedData)({
508
+ domain: {
509
+ chainId: Number(chainId),
510
+ verifyingContract: safe4337ModuleAddress
511
+ },
512
+ types: EIP712_SAFE_OPERATION_TYPE,
513
+ primaryType: "SafeOp",
514
+ message: safeUserOperation
515
+ });
516
+ }
517
+ function userOperationToHexValues(userOperation) {
518
+ const userOperationWithHexValues = {
519
+ ...userOperation,
520
+ nonce: (0, import_viem2.toHex)(BigInt(userOperation.nonce)),
521
+ callGasLimit: (0, import_viem2.toHex)(userOperation.callGasLimit),
522
+ verificationGasLimit: (0, import_viem2.toHex)(userOperation.verificationGasLimit),
523
+ preVerificationGas: (0, import_viem2.toHex)(userOperation.preVerificationGas),
524
+ maxFeePerGas: (0, import_viem2.toHex)(userOperation.maxFeePerGas),
525
+ maxPriorityFeePerGas: (0, import_viem2.toHex)(userOperation.maxPriorityFeePerGas)
526
+ };
527
+ return userOperationWithHexValues;
528
+ }
529
+ var DUMMY_CLIENT_DATA_FIELDS = [
530
+ `"origin":"https://safe.global"`,
531
+ `"padding":"This pads the clientDataJSON so that we can leave room for additional implementation specific fields for a more accurate 'preVerificationGas' estimate."`
532
+ ].join(",");
533
+ var DUMMY_AUTHENTICATOR_DATA = new Uint8Array(37);
534
+ DUMMY_AUTHENTICATOR_DATA.fill(254);
535
+ DUMMY_AUTHENTICATOR_DATA[32] = 4;
536
+ function addDummySignature(userOperation, signer, threshold) {
537
+ const signatures = [];
538
+ for (let i = 0; i < threshold; i++) {
539
+ const isContractSignature = true;
540
+ const passkeySignature = getSignatureBytes({
541
+ authenticatorData: DUMMY_AUTHENTICATOR_DATA,
542
+ clientDataFields: DUMMY_CLIENT_DATA_FIELDS,
543
+ r: BigInt(`0x${"ec".repeat(32)}`),
544
+ s: BigInt(`0x${"d5a".repeat(21)}f`)
545
+ });
546
+ signatures.push(new import_protocol_kit2.EthSafeSignature(signer, passkeySignature, isContractSignature));
547
+ }
548
+ return {
549
+ ...userOperation,
550
+ signature: (0, import_viem2.encodePacked)(
551
+ ["uint48", "uint48", "bytes"],
552
+ [0, 0, (0, import_protocol_kit2.buildSignatureBytes)(signatures)]
553
+ )
554
+ };
555
+ }
556
+ function getSignatureBytes({
557
+ authenticatorData,
558
+ clientDataFields,
559
+ r,
560
+ s
561
+ }) {
562
+ const encodeUint256 = (x) => x.toString(16).padStart(64, "0");
563
+ const byteSize = (data) => 32 * (Math.ceil(data.length / 32) + 1);
564
+ const encodeBytes = (data) => `${encodeUint256(data.length)}${(0, import_viem2.toHex)(data).slice(2)}`.padEnd(byteSize(data) * 2, "0");
565
+ const authenticatorDataOffset = 32 * 4;
566
+ const clientDataFieldsOffset = authenticatorDataOffset + byteSize(authenticatorData);
567
+ return "0x" + encodeUint256(authenticatorDataOffset) + encodeUint256(clientDataFieldsOffset) + encodeUint256(r) + encodeUint256(s) + encodeBytes(authenticatorData) + encodeBytes(new TextEncoder().encode(clientDataFields));
568
+ }
569
+
570
+ // src/packs/safe-4337/SafeOperation.ts
571
+ var EthSafeOperation = class {
572
+ constructor(userOperation, { chainId, entryPoint, validAfter, validUntil, moduleAddress }) {
573
+ this.signatures = /* @__PURE__ */ new Map();
574
+ this.chainId = chainId;
575
+ this.moduleAddress = moduleAddress;
576
+ this.data = {
577
+ safe: userOperation.sender,
578
+ nonce: BigInt(userOperation.nonce),
579
+ initCode: userOperation.initCode,
580
+ callData: userOperation.callData,
581
+ callGasLimit: userOperation.callGasLimit,
582
+ verificationGasLimit: userOperation.verificationGasLimit,
583
+ preVerificationGas: userOperation.preVerificationGas,
584
+ maxFeePerGas: userOperation.maxFeePerGas,
585
+ maxPriorityFeePerGas: userOperation.maxPriorityFeePerGas,
586
+ paymasterAndData: userOperation.paymasterAndData,
587
+ validAfter: validAfter || 0,
588
+ validUntil: validUntil || 0,
589
+ entryPoint
590
+ };
591
+ }
592
+ getSignature(signer) {
593
+ return this.signatures.get(signer.toLowerCase());
594
+ }
595
+ addSignature(signature) {
596
+ this.signatures.set(signature.signer.toLowerCase(), signature);
597
+ }
598
+ encodedSignatures() {
599
+ return (0, import_protocol_kit3.buildSignatureBytes)(Array.from(this.signatures.values()));
600
+ }
601
+ addEstimations(estimations) {
602
+ const keys = [
603
+ "maxFeePerGas",
604
+ "maxPriorityFeePerGas",
605
+ "verificationGasLimit",
606
+ "preVerificationGas",
607
+ "callGasLimit"
608
+ ];
609
+ for (const key of keys) {
610
+ this.data[key] = BigInt(estimations[key] || this.data[key]);
611
+ }
612
+ }
613
+ toUserOperation() {
614
+ return {
615
+ sender: this.data.safe,
616
+ nonce: (0, import_viem3.toHex)(this.data.nonce),
617
+ initCode: this.data.initCode,
618
+ callData: this.data.callData,
619
+ callGasLimit: this.data.callGasLimit,
620
+ verificationGasLimit: this.data.verificationGasLimit,
621
+ preVerificationGas: this.data.preVerificationGas,
622
+ maxFeePerGas: this.data.maxFeePerGas,
623
+ maxPriorityFeePerGas: this.data.maxPriorityFeePerGas,
624
+ paymasterAndData: this.data.paymasterAndData,
625
+ signature: (0, import_viem3.encodePacked)(
626
+ ["uint48", "uint48", "bytes"],
627
+ [this.data.validAfter, this.data.validUntil, this.encodedSignatures()]
628
+ )
629
+ };
630
+ }
631
+ getHash() {
632
+ return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress);
633
+ }
634
+ };
635
+ var SafeOperation_default = EthSafeOperation;
636
+
637
+ // src/packs/safe-4337/utils/entrypoint.ts
638
+ var EQ_0_2_0 = "0.2.0";
639
+ var EQ_OR_GT_0_3_0 = ">=0.3.0";
640
+ function entryPointToSafeModules(entryPoint) {
641
+ const moduleVersionToEntryPoint = {
642
+ [ENTRYPOINT_ADDRESS_V06]: EQ_0_2_0,
643
+ [ENTRYPOINT_ADDRESS_V07]: EQ_OR_GT_0_3_0
644
+ };
645
+ return moduleVersionToEntryPoint[entryPoint];
646
+ }
647
+
648
+ // src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts
649
+ var PimlicoFeeEstimator = class {
650
+ async setupEstimation({ bundlerUrl }) {
651
+ const bundlerClient = getEip4337BundlerProvider(bundlerUrl);
652
+ const feeData = await this.#getFeeData(bundlerClient);
653
+ return feeData;
654
+ }
655
+ async adjustEstimation({ userOperation }) {
656
+ return {
657
+ callGasLimit: userOperation.callGasLimit + userOperation.callGasLimit / 2n,
658
+ // +50%
659
+ verificationGasLimit: userOperation.verificationGasLimit * 4n,
660
+ // +300%
661
+ preVerificationGas: userOperation.preVerificationGas + userOperation.preVerificationGas / 20n
662
+ // +5%
663
+ };
664
+ }
665
+ async getPaymasterEstimation({
666
+ userOperation,
667
+ paymasterUrl,
668
+ entryPoint,
669
+ sponsorshipPolicyId
670
+ }) {
671
+ const paymasterClient = getEip4337BundlerProvider(paymasterUrl);
672
+ const gasEstimate = await paymasterClient.request({
673
+ method: "pm_sponsorUserOperation" /* SPONSOR_USER_OPERATION */,
674
+ params: sponsorshipPolicyId ? [userOperationToHexValues(userOperation), entryPoint, { sponsorshipPolicyId }] : [userOperationToHexValues(userOperation), entryPoint]
675
+ });
676
+ return gasEstimate;
677
+ }
678
+ async #getFeeData(bundlerClient) {
679
+ const {
680
+ fast: { maxFeePerGas, maxPriorityFeePerGas }
681
+ } = await bundlerClient.request({
682
+ method: "pimlico_getUserOperationGasPrice"
683
+ });
684
+ return {
685
+ maxFeePerGas: BigInt(maxFeePerGas),
686
+ maxPriorityFeePerGas: BigInt(maxPriorityFeePerGas)
687
+ };
688
+ }
689
+ };
690
+
691
+ // src/packs/safe-4337/utils/getRelayKitVersion.ts
692
+ var getRelayKitVersion = () => "3.4.1";
693
+
694
+ // src/packs/safe-4337/Safe4337Pack.ts
695
+ var MAX_ERC20_AMOUNT_TO_APPROVE = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn;
696
+ var EQ_OR_GT_1_4_1 = ">=1.4.1";
697
+ var Safe4337Pack = class _Safe4337Pack extends RelayKitBasePack {
698
+ #BUNDLER_URL;
699
+ #ENTRYPOINT_ADDRESS;
700
+ #SAFE_4337_MODULE_ADDRESS = "0x";
701
+ #SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS = "0x";
702
+ #bundlerClient;
703
+ #chainId;
704
+ #paymasterOptions;
705
+ #onchainIdentifier = "";
706
+ /**
707
+ * Creates an instance of the Safe4337Pack.
708
+ *
709
+ * @param {Safe4337Options} options - The initialization parameters.
710
+ */
711
+ constructor({
712
+ protocolKit,
713
+ bundlerClient,
714
+ bundlerUrl,
715
+ chainId,
716
+ paymasterOptions,
717
+ entryPointAddress,
718
+ safe4337ModuleAddress,
719
+ safeWebAuthnSharedSignerAddress,
720
+ onchainAnalytics
721
+ }) {
722
+ super(protocolKit);
723
+ this.#BUNDLER_URL = bundlerUrl;
724
+ this.#bundlerClient = bundlerClient;
725
+ this.#chainId = chainId;
726
+ this.#paymasterOptions = paymasterOptions;
727
+ this.#ENTRYPOINT_ADDRESS = entryPointAddress;
728
+ this.#SAFE_4337_MODULE_ADDRESS = safe4337ModuleAddress;
729
+ this.#SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS = safeWebAuthnSharedSignerAddress || "0x";
730
+ if (onchainAnalytics?.project) {
731
+ const { project, platform } = onchainAnalytics;
732
+ this.#onchainIdentifier = (0, import_protocol_kit4.generateOnChainIdentifier)({
733
+ project,
734
+ platform,
735
+ tool: "relay-kit",
736
+ toolVersion: getRelayKitVersion()
737
+ });
738
+ }
739
+ }
740
+ /**
741
+ * Initializes a Safe4337Pack class.
742
+ * This method creates the protocolKit instance based on the input parameters.
743
+ * When the Safe address is provided, it will use the existing Safe.
744
+ * When the Safe address is not provided, it will use the predictedSafe feature with the provided owners and threshold.
745
+ * It will use the correct contract addresses for the fallbackHandler and the module and will add the data to enable the 4337 module.
746
+ *
747
+ * @param {Safe4337InitOptions} initOptions - The initialization parameters.
748
+ * @return {Promise<Safe4337Pack>} The Promise object that will be resolved into an instance of Safe4337Pack.
749
+ */
750
+ static async init(initOptions) {
751
+ const {
752
+ provider,
753
+ signer,
754
+ options,
755
+ bundlerUrl,
756
+ customContracts,
757
+ paymasterOptions,
758
+ onchainAnalytics
759
+ } = initOptions;
760
+ let protocolKit;
761
+ const bundlerClient = getEip4337BundlerProvider(bundlerUrl);
762
+ const chainId = await bundlerClient.request({ method: "eth_chainId" /* CHAIN_ID */ });
763
+ let addModulesLibAddress = customContracts?.addModulesLibAddress;
764
+ const network = parseInt(chainId, 16).toString();
765
+ const safeModulesVersion = initOptions.safeModulesVersion || DEFAULT_SAFE_MODULES_VERSION;
766
+ if ((0, import_satisfies.default)(safeModulesVersion, EQ_OR_GT_0_3_0)) {
767
+ throw new Error(
768
+ `Incompatibility detected: Safe modules version ${safeModulesVersion} is not supported. The SDK can use 0.2.0 only.`
769
+ );
770
+ }
771
+ if (!addModulesLibAddress) {
772
+ const addModulesDeployment = (0, import_safe_modules_deployments.getAddModulesLibDeployment)({
773
+ released: true,
774
+ version: safeModulesVersion,
775
+ network
776
+ });
777
+ addModulesLibAddress = addModulesDeployment?.networkAddresses[network];
778
+ }
779
+ let safe4337ModuleAddress = customContracts?.safe4337ModuleAddress;
780
+ if (!safe4337ModuleAddress) {
781
+ const safe4337ModuleDeployment = (0, import_safe_modules_deployments.getSafe4337ModuleDeployment)({
782
+ released: true,
783
+ version: safeModulesVersion,
784
+ network
785
+ });
786
+ safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network];
787
+ }
788
+ if (!addModulesLibAddress || !safe4337ModuleAddress) {
789
+ throw new Error(
790
+ `Safe4337Module and/or AddModulesLib not available for chain ${network} and modules version ${safeModulesVersion}`
791
+ );
792
+ }
793
+ let safeWebAuthnSharedSignerAddress = customContracts?.safeWebAuthnSharedSignerAddress;
794
+ if ("safeAddress" in options) {
795
+ protocolKit = await import_protocol_kit4.default.init({
796
+ provider,
797
+ signer,
798
+ safeAddress: options.safeAddress
799
+ });
800
+ const safeVersion = protocolKit.getContractVersion();
801
+ const isSafeVersion4337Compatible = (0, import_satisfies.default)(safeVersion, EQ_OR_GT_1_4_1);
802
+ if (!isSafeVersion4337Compatible) {
803
+ throw new Error(
804
+ `Incompatibility detected: The current Safe Account version (${safeVersion}) is not supported. EIP-4337 requires the Safe to use at least v1.4.1.`
805
+ );
806
+ }
807
+ const safeModules = await protocolKit.getModules();
808
+ const is4337ModulePresent = safeModules.some((module2) => module2 === safe4337ModuleAddress);
809
+ if (!is4337ModulePresent) {
810
+ throw new Error(
811
+ `Incompatibility detected: The EIP-4337 module is not enabled in the provided Safe Account. Enable this module (address: ${safe4337ModuleAddress}) to add compatibility.`
812
+ );
813
+ }
814
+ const safeFallbackhandler = await protocolKit.getFallbackHandler();
815
+ const is4337FallbackhandlerPresent = safeFallbackhandler === safe4337ModuleAddress;
816
+ if (!is4337FallbackhandlerPresent) {
817
+ throw new Error(
818
+ `Incompatibility detected: The EIP-4337 fallbackhandler is not attached to the Safe Account. Attach this fallbackhandler (address: ${safe4337ModuleAddress}) to ensure compatibility.`
819
+ );
820
+ }
821
+ } else {
822
+ if (!options.owners || !options.threshold) {
823
+ throw new Error("Owners and threshold are required to deploy a new Safe");
824
+ }
825
+ const safeVersion = options.safeVersion || DEFAULT_SAFE_VERSION;
826
+ const enable4337ModuleTransaction = {
827
+ to: addModulesLibAddress,
828
+ value: "0",
829
+ data: (0, import_viem4.encodeFunctionData)({
830
+ abi: ABI,
831
+ functionName: "enableModules",
832
+ args: [[safe4337ModuleAddress]]
833
+ }),
834
+ operation: import_types_kit2.OperationType.DelegateCall
835
+ // DelegateCall required for enabling the 4337 module
836
+ };
837
+ const setupTransactions = [enable4337ModuleTransaction];
838
+ const isApproveTransactionRequired = !!paymasterOptions && !paymasterOptions.isSponsored && !!paymasterOptions.paymasterTokenAddress;
839
+ if (isApproveTransactionRequired) {
840
+ const { paymasterAddress, amountToApprove = MAX_ERC20_AMOUNT_TO_APPROVE } = paymasterOptions;
841
+ const approveToPaymasterTransaction = {
842
+ to: paymasterOptions.paymasterTokenAddress,
843
+ data: (0, import_viem4.encodeFunctionData)({
844
+ abi: ABI,
845
+ functionName: "approve",
846
+ args: [paymasterAddress, amountToApprove]
847
+ }),
848
+ value: "0",
849
+ operation: import_types_kit2.OperationType.Call
850
+ // Call for approve
851
+ };
852
+ setupTransactions.push(approveToPaymasterTransaction);
853
+ }
854
+ const safeProvider = await import_protocol_kit4.SafeProvider.init({ provider, signer, safeVersion });
855
+ const isPasskeySigner = await safeProvider.isPasskeySigner();
856
+ if (isPasskeySigner) {
857
+ if (!safeWebAuthnSharedSignerAddress) {
858
+ const safeWebAuthnSharedSignerDeployment = (0, import_safe_modules_deployments.getSafeWebAuthnShareSignerDeployment)({
859
+ released: true,
860
+ version: "0.2.1",
861
+ network
862
+ });
863
+ safeWebAuthnSharedSignerAddress = safeWebAuthnSharedSignerDeployment?.networkAddresses[network];
864
+ }
865
+ if (!safeWebAuthnSharedSignerAddress) {
866
+ throw new Error(`safeWebAuthnSharedSignerAddress not available for chain ${network}`);
867
+ }
868
+ const passkeySigner = await safeProvider.getExternalSigner();
869
+ if (!options.owners.includes(safeWebAuthnSharedSignerAddress)) {
870
+ options.owners.push(safeWebAuthnSharedSignerAddress);
871
+ }
872
+ const sharedSignerTransaction = {
873
+ to: safeWebAuthnSharedSignerAddress,
874
+ value: "0",
875
+ data: passkeySigner.encodeConfigure(),
876
+ operation: import_types_kit2.OperationType.DelegateCall
877
+ // DelegateCall required into the SafeWebAuthnSharedSigner instance in order for it to set its configuration.
878
+ };
879
+ setupTransactions.push(sharedSignerTransaction);
880
+ }
881
+ let deploymentTo;
882
+ let deploymentData;
883
+ const isBatch = setupTransactions.length > 1;
884
+ if (isBatch) {
885
+ const multiSendContract = await (0, import_protocol_kit4.getMultiSendContract)({
886
+ safeProvider,
887
+ safeVersion,
888
+ deploymentType: options.deploymentType || void 0
889
+ });
890
+ const batchData = (0, import_viem4.encodeFunctionData)({
891
+ abi: ABI,
892
+ functionName: "multiSend",
893
+ args: [(0, import_protocol_kit4.encodeMultiSendData)(setupTransactions)]
894
+ });
895
+ deploymentTo = multiSendContract.getAddress();
896
+ deploymentData = batchData;
897
+ } else {
898
+ deploymentTo = enable4337ModuleTransaction.to;
899
+ deploymentData = enable4337ModuleTransaction.data;
900
+ }
901
+ protocolKit = await import_protocol_kit4.default.init({
902
+ provider,
903
+ signer,
904
+ predictedSafe: {
905
+ safeDeploymentConfig: {
906
+ safeVersion,
907
+ saltNonce: options.saltNonce || void 0,
908
+ deploymentType: options.deploymentType || void 0
909
+ },
910
+ safeAccountConfig: {
911
+ owners: options.owners,
912
+ threshold: options.threshold,
913
+ to: deploymentTo,
914
+ data: deploymentData,
915
+ fallbackHandler: safe4337ModuleAddress,
916
+ paymentToken: import_viem4.zeroAddress,
917
+ payment: 0,
918
+ paymentReceiver: import_viem4.zeroAddress
919
+ }
920
+ },
921
+ onchainAnalytics
922
+ });
923
+ }
924
+ let selectedEntryPoint;
925
+ if (customContracts?.entryPointAddress) {
926
+ const requiredSafeModulesVersion = entryPointToSafeModules(customContracts?.entryPointAddress);
927
+ if (!(0, import_satisfies.default)(safeModulesVersion, requiredSafeModulesVersion))
928
+ throw new Error(
929
+ `The selected entrypoint ${customContracts?.entryPointAddress} is not compatible with version ${safeModulesVersion} of Safe modules`
930
+ );
931
+ selectedEntryPoint = customContracts?.entryPointAddress;
932
+ } else {
933
+ const supportedEntryPoints = await bundlerClient.request({
934
+ method: "eth_supportedEntryPoints" /* SUPPORTED_ENTRY_POINTS */
935
+ });
936
+ if (!supportedEntryPoints.length) {
937
+ throw new Error("No entrypoint provided or available through the bundler");
938
+ }
939
+ selectedEntryPoint = supportedEntryPoints.find((entryPoint) => {
940
+ const requiredSafeModulesVersion = entryPointToSafeModules(entryPoint);
941
+ return (0, import_satisfies.default)(safeModulesVersion, requiredSafeModulesVersion);
942
+ });
943
+ if (!selectedEntryPoint) {
944
+ throw new Error(
945
+ `Incompatibility detected: None of the entrypoints provided by the bundler is compatible with the Safe modules version ${safeModulesVersion}`
946
+ );
947
+ }
948
+ }
949
+ return new _Safe4337Pack({
950
+ chainId: BigInt(chainId),
951
+ protocolKit,
952
+ bundlerClient,
953
+ paymasterOptions,
954
+ bundlerUrl,
955
+ entryPointAddress: selectedEntryPoint,
956
+ safe4337ModuleAddress,
957
+ safeWebAuthnSharedSignerAddress,
958
+ onchainAnalytics
959
+ });
960
+ }
961
+ /**
962
+ * Estimates gas for the SafeOperation.
963
+ *
964
+ * @param {EstimateFeeProps} props - The parameters for the gas estimation.
965
+ * @param {EthSafeOperation} props.safeOperation - The SafeOperation to estimate the gas.
966
+ * @param {IFeeEstimator} props.feeEstimator - The function to estimate the gas.
967
+ * @return {Promise<EthSafeOperation>} The Promise object that will be resolved into the gas estimation.
968
+ */
969
+ async getEstimateFee({
970
+ safeOperation,
971
+ feeEstimator = new PimlicoFeeEstimator()
972
+ }) {
973
+ const threshold = await this.protocolKit.getThreshold();
974
+ const setupEstimationData = await feeEstimator?.setupEstimation?.({
975
+ bundlerUrl: this.#BUNDLER_URL,
976
+ entryPoint: this.#ENTRYPOINT_ADDRESS,
977
+ userOperation: safeOperation.toUserOperation()
978
+ });
979
+ if (setupEstimationData) {
980
+ safeOperation.addEstimations(setupEstimationData);
981
+ }
982
+ const estimateUserOperationGas = await this.#bundlerClient.request({
983
+ method: "eth_estimateUserOperationGas" /* ESTIMATE_USER_OPERATION_GAS */,
984
+ params: [
985
+ userOperationToHexValues(
986
+ addDummySignature(
987
+ safeOperation.toUserOperation(),
988
+ this.#SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS,
989
+ threshold
990
+ )
991
+ ),
992
+ this.#ENTRYPOINT_ADDRESS
993
+ ]
994
+ });
995
+ if (estimateUserOperationGas) {
996
+ safeOperation.addEstimations({
997
+ preVerificationGas: BigInt(estimateUserOperationGas.preVerificationGas),
998
+ verificationGasLimit: BigInt(estimateUserOperationGas.verificationGasLimit),
999
+ callGasLimit: BigInt(estimateUserOperationGas.callGasLimit)
1000
+ });
1001
+ }
1002
+ const adjustEstimationData = await feeEstimator?.adjustEstimation?.({
1003
+ bundlerUrl: this.#BUNDLER_URL,
1004
+ entryPoint: this.#ENTRYPOINT_ADDRESS,
1005
+ userOperation: safeOperation.toUserOperation()
1006
+ });
1007
+ if (adjustEstimationData) {
1008
+ safeOperation.addEstimations(adjustEstimationData);
1009
+ }
1010
+ if (this.#paymasterOptions?.isSponsored) {
1011
+ if (!this.#paymasterOptions.paymasterUrl) {
1012
+ throw new Error("No paymaster url provided for a sponsored transaction");
1013
+ }
1014
+ const paymasterEstimation = await feeEstimator?.getPaymasterEstimation?.({
1015
+ userOperation: addDummySignature(
1016
+ safeOperation.toUserOperation(),
1017
+ this.#SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS,
1018
+ threshold
1019
+ ),
1020
+ paymasterUrl: this.#paymasterOptions.paymasterUrl,
1021
+ entryPoint: this.#ENTRYPOINT_ADDRESS,
1022
+ sponsorshipPolicyId: this.#paymasterOptions.sponsorshipPolicyId
1023
+ });
1024
+ safeOperation.data.paymasterAndData = paymasterEstimation?.paymasterAndData || safeOperation.data.paymasterAndData;
1025
+ if (paymasterEstimation) {
1026
+ safeOperation.addEstimations(paymasterEstimation);
1027
+ }
1028
+ }
1029
+ return safeOperation;
1030
+ }
1031
+ /**
1032
+ * Creates a relayed transaction based on the provided parameters.
1033
+ *
1034
+ * @param {MetaTransactionData[]} transactions - The transactions to batch in a SafeOperation.
1035
+ * @param options - Optional configuration options for the transaction creation.
1036
+ * @return {Promise<EthSafeOperation>} The Promise object will resolve a SafeOperation.
1037
+ */
1038
+ async createTransaction({
1039
+ transactions,
1040
+ options = {}
1041
+ }) {
1042
+ const safeAddress = await this.protocolKit.getAddress();
1043
+ const nonce = await this.#getSafeNonceFromEntrypoint(safeAddress);
1044
+ const { amountToApprove, validUntil, validAfter, feeEstimator } = options;
1045
+ if (amountToApprove) {
1046
+ const paymasterOptions = this.#paymasterOptions;
1047
+ if (!paymasterOptions.paymasterTokenAddress) {
1048
+ throw new Error("Paymaster must be initialized");
1049
+ }
1050
+ const approveToPaymasterTransaction = {
1051
+ to: paymasterOptions.paymasterTokenAddress,
1052
+ data: (0, import_viem4.encodeFunctionData)({
1053
+ abi: ABI,
1054
+ functionName: "approve",
1055
+ args: [paymasterOptions.paymasterAddress, amountToApprove]
1056
+ }),
1057
+ value: "0",
1058
+ operation: import_types_kit2.OperationType.Call
1059
+ // Call for approve
1060
+ };
1061
+ transactions.push(approveToPaymasterTransaction);
1062
+ }
1063
+ const isBatch = transactions.length > 1;
1064
+ const multiSendAddress = this.protocolKit.getMultiSendAddress();
1065
+ const callData = isBatch ? this.#encodeExecuteUserOpCallData({
1066
+ to: multiSendAddress,
1067
+ value: "0",
1068
+ data: encodeMultiSendCallData(transactions),
1069
+ operation: import_types_kit2.OperationType.DelegateCall
1070
+ }) : this.#encodeExecuteUserOpCallData(transactions[0]);
1071
+ const paymasterAndData = this.#paymasterOptions && "paymasterAddress" in this.#paymasterOptions ? this.#paymasterOptions.paymasterAddress : "0x";
1072
+ const userOperation = {
1073
+ sender: safeAddress,
1074
+ nonce,
1075
+ initCode: "0x",
1076
+ callData,
1077
+ callGasLimit: 1n,
1078
+ verificationGasLimit: 1n,
1079
+ preVerificationGas: 1n,
1080
+ maxFeePerGas: 1n,
1081
+ maxPriorityFeePerGas: 1n,
1082
+ paymasterAndData,
1083
+ signature: "0x"
1084
+ };
1085
+ if (this.#onchainIdentifier) {
1086
+ userOperation.callData += this.#onchainIdentifier;
1087
+ }
1088
+ const isSafeDeployed = await this.protocolKit.isSafeDeployed();
1089
+ if (!isSafeDeployed) {
1090
+ userOperation.initCode = await this.protocolKit.getInitCode();
1091
+ }
1092
+ const safeOperation = new SafeOperation_default(userOperation, {
1093
+ chainId: this.#chainId,
1094
+ moduleAddress: this.#SAFE_4337_MODULE_ADDRESS,
1095
+ entryPoint: this.#ENTRYPOINT_ADDRESS,
1096
+ validUntil,
1097
+ validAfter
1098
+ });
1099
+ return await this.getEstimateFee({
1100
+ safeOperation,
1101
+ feeEstimator
1102
+ });
1103
+ }
1104
+ /**
1105
+ * Converts a SafeOperationResponse to an EthSafeOperation.
1106
+ *
1107
+ * @param {SafeOperationResponse} safeOperationResponse - The SafeOperationResponse to convert to EthSafeOperation
1108
+ * @returns {EthSafeOperation} - The EthSafeOperation object
1109
+ */
1110
+ #toSafeOperation(safeOperationResponse) {
1111
+ const { validUntil, validAfter, userOperation } = safeOperationResponse;
1112
+ const paymaster = userOperation?.paymaster || "0x";
1113
+ const paymasterData = userOperation?.paymasterData || "0x";
1114
+ const safeOperation = new SafeOperation_default(
1115
+ {
1116
+ sender: userOperation?.sender || "0x",
1117
+ nonce: userOperation?.nonce?.toString() || "0",
1118
+ initCode: userOperation?.initCode || "",
1119
+ callData: userOperation?.callData || "",
1120
+ callGasLimit: BigInt(userOperation?.callGasLimit || 0n),
1121
+ verificationGasLimit: BigInt(userOperation?.verificationGasLimit || 0),
1122
+ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0),
1123
+ maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0),
1124
+ maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0),
1125
+ paymasterAndData: (0, import_viem4.concat)([paymaster, paymasterData]),
1126
+ signature: safeOperationResponse.preparedSignature || "0x"
1127
+ },
1128
+ {
1129
+ chainId: this.#chainId,
1130
+ moduleAddress: this.#SAFE_4337_MODULE_ADDRESS,
1131
+ entryPoint: userOperation?.entryPoint || this.#ENTRYPOINT_ADDRESS,
1132
+ validAfter: this.#timestamp(validAfter),
1133
+ validUntil: this.#timestamp(validUntil)
1134
+ }
1135
+ );
1136
+ if (safeOperationResponse.confirmations) {
1137
+ safeOperationResponse.confirmations.forEach((confirmation) => {
1138
+ safeOperation.addSignature(new import_protocol_kit4.EthSafeSignature(confirmation.owner, confirmation.signature));
1139
+ });
1140
+ }
1141
+ return safeOperation;
1142
+ }
1143
+ /**
1144
+ *
1145
+ * @param date An ISO string date
1146
+ * @returns The timestamp in seconds to send to the bundler
1147
+ */
1148
+ #timestamp(date) {
1149
+ return date ? new Date(date).getTime() / 1e3 : void 0;
1150
+ }
1151
+ /**
1152
+ * Signs a safe operation.
1153
+ *
1154
+ * @param {EthSafeOperation | SafeOperationResponse} safeOperation - The SafeOperation to sign. It can be:
1155
+ * - A response from the API (Tx Service)
1156
+ * - An instance of EthSafeOperation
1157
+ * @param {SigningMethod} signingMethod - The signing method to use.
1158
+ * @return {Promise<EthSafeOperation>} The Promise object will resolve to the signed SafeOperation.
1159
+ */
1160
+ async signSafeOperation(safeOperation, signingMethod = import_protocol_kit4.SigningMethod.ETH_SIGN_TYPED_DATA_V4) {
1161
+ let safeOp;
1162
+ if ((0, import_types_kit2.isSafeOperationResponse)(safeOperation)) {
1163
+ safeOp = this.#toSafeOperation(safeOperation);
1164
+ } else {
1165
+ safeOp = safeOperation;
1166
+ }
1167
+ const safeProvider = this.protocolKit.getSafeProvider();
1168
+ const signerAddress = await safeProvider.getSignerAddress();
1169
+ const isPasskeySigner = await safeProvider.isPasskeySigner();
1170
+ if (!signerAddress) {
1171
+ throw new Error("There is no signer address available to sign the SafeOperation");
1172
+ }
1173
+ const isOwner = await this.protocolKit.isOwner(signerAddress);
1174
+ const isSafeDeployed = await this.protocolKit.isSafeDeployed();
1175
+ if (!isOwner && isSafeDeployed || !isSafeDeployed && !isPasskeySigner && !isOwner) {
1176
+ throw new Error("UserOperations can only be signed by Safe owners");
1177
+ }
1178
+ let signature;
1179
+ if (isPasskeySigner) {
1180
+ const safeOpHash = safeOp.getHash();
1181
+ if (!isSafeDeployed) {
1182
+ const passkeySignature = await this.protocolKit.signHash(safeOpHash);
1183
+ signature = new import_protocol_kit4.EthSafeSignature(
1184
+ this.#SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS,
1185
+ passkeySignature.data,
1186
+ true
1187
+ // passkeys are contract signatures
1188
+ );
1189
+ } else {
1190
+ signature = await this.protocolKit.signHash(safeOpHash);
1191
+ }
1192
+ } else {
1193
+ if (signingMethod in [
1194
+ import_protocol_kit4.SigningMethod.ETH_SIGN_TYPED_DATA_V4,
1195
+ import_protocol_kit4.SigningMethod.ETH_SIGN_TYPED_DATA_V3,
1196
+ import_protocol_kit4.SigningMethod.ETH_SIGN_TYPED_DATA
1197
+ ]) {
1198
+ signature = await signSafeOp(
1199
+ safeOp.data,
1200
+ this.protocolKit.getSafeProvider(),
1201
+ this.#SAFE_4337_MODULE_ADDRESS
1202
+ );
1203
+ } else {
1204
+ const safeOpHash = safeOp.getHash();
1205
+ signature = await this.protocolKit.signHash(safeOpHash);
1206
+ }
1207
+ }
1208
+ const signedSafeOperation = new SafeOperation_default(safeOp.toUserOperation(), {
1209
+ chainId: this.#chainId,
1210
+ moduleAddress: this.#SAFE_4337_MODULE_ADDRESS,
1211
+ entryPoint: this.#ENTRYPOINT_ADDRESS,
1212
+ validUntil: safeOp.data.validUntil,
1213
+ validAfter: safeOp.data.validAfter
1214
+ });
1215
+ safeOp.signatures.forEach((signature2) => {
1216
+ signedSafeOperation.addSignature(signature2);
1217
+ });
1218
+ signedSafeOperation.addSignature(signature);
1219
+ return signedSafeOperation;
1220
+ }
1221
+ /**
1222
+ * Executes the relay transaction.
1223
+ *
1224
+ * @param {Safe4337ExecutableProps} props - The parameters for the transaction execution.
1225
+ * @param {EthSafeOperation | SafeOperationResponse} props.executable - The SafeOperation to execute. It can be:
1226
+ * - A response from the API (Tx Service)
1227
+ * - An instance of EthSafeOperation
1228
+ * @return {Promise<string>} The user operation hash.
1229
+ */
1230
+ async executeTransaction({ executable }) {
1231
+ let safeOperation;
1232
+ if ((0, import_types_kit2.isSafeOperationResponse)(executable)) {
1233
+ safeOperation = this.#toSafeOperation(executable);
1234
+ } else {
1235
+ safeOperation = executable;
1236
+ }
1237
+ const userOperation = safeOperation.toUserOperation();
1238
+ return this.#bundlerClient.request({
1239
+ method: "eth_sendUserOperation" /* SEND_USER_OPERATION */,
1240
+ params: [userOperationToHexValues(userOperation), this.#ENTRYPOINT_ADDRESS]
1241
+ });
1242
+ }
1243
+ /**
1244
+ * Return a UserOperation based on a hash (userOpHash) returned by eth_sendUserOperation
1245
+ *
1246
+ * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method
1247
+ * @returns {UserOperation} - null in case the UserOperation is not yet included in a block, or a full UserOperation, with the addition of entryPoint, blockNumber, blockHash and transactionHash
1248
+ */
1249
+ async getUserOperationByHash(userOpHash) {
1250
+ return this.#bundlerClient.request({
1251
+ method: "eth_getUserOperationByHash" /* GET_USER_OPERATION_BY_HASH */,
1252
+ params: [userOpHash]
1253
+ });
1254
+ }
1255
+ /**
1256
+ * Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation
1257
+ *
1258
+ * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method
1259
+ * @returns {UserOperationReceipt} - null in case the UserOperation is not yet included in a block, or UserOperationReceipt object
1260
+ */
1261
+ async getUserOperationReceipt(userOpHash) {
1262
+ return this.#bundlerClient.request({
1263
+ method: "eth_getUserOperationReceipt" /* GET_USER_OPERATION_RECEIPT */,
1264
+ params: [userOpHash]
1265
+ });
1266
+ }
1267
+ /**
1268
+ * Returns an array of the entryPoint addresses supported by the client.
1269
+ * The first element of the array SHOULD be the entryPoint addressed preferred by the client.
1270
+ *
1271
+ * @returns {string[]} - The supported entry points.
1272
+ */
1273
+ async getSupportedEntryPoints() {
1274
+ return this.#bundlerClient.request({
1275
+ method: "eth_supportedEntryPoints" /* SUPPORTED_ENTRY_POINTS */
1276
+ });
1277
+ }
1278
+ /**
1279
+ * Returns EIP-155 Chain ID.
1280
+ *
1281
+ * @returns {string} - The chain id.
1282
+ */
1283
+ async getChainId() {
1284
+ return this.#bundlerClient.request({ method: "eth_chainId" /* CHAIN_ID */ });
1285
+ }
1286
+ /**
1287
+ * Gets account nonce from the bundler.
1288
+ *
1289
+ * @param {string} safeAddress - Account address for which the nonce is to be fetched.
1290
+ * @returns {Promise<string>} The Promise object will resolve to the account nonce.
1291
+ */
1292
+ async #getSafeNonceFromEntrypoint(safeAddress) {
1293
+ const safeProvider = this.protocolKit.getSafeProvider();
1294
+ const newNonce = await safeProvider.readContract({
1295
+ address: this.#ENTRYPOINT_ADDRESS || "0x",
1296
+ abi: ENTRYPOINT_ABI,
1297
+ functionName: "getNonce",
1298
+ args: [safeAddress, 0n]
1299
+ });
1300
+ return newNonce.toString();
1301
+ }
1302
+ /**
1303
+ * Encode the UserOperation execution from a transaction.
1304
+ *
1305
+ * @param {MetaTransactionData} transaction - The transaction data to encode.
1306
+ * @return {string} The encoded call data string.
1307
+ */
1308
+ #encodeExecuteUserOpCallData(transaction) {
1309
+ return (0, import_viem4.encodeFunctionData)({
1310
+ abi: ABI,
1311
+ functionName: "executeUserOp",
1312
+ args: [
1313
+ transaction.to,
1314
+ BigInt(transaction.value),
1315
+ transaction.data,
1316
+ transaction.operation || import_types_kit2.OperationType.Call
1317
+ ]
1318
+ });
1319
+ }
1320
+ getOnchainIdentifier() {
1321
+ return this.#onchainIdentifier;
1322
+ }
1323
+ };