@safe-global/relay-kit 3.0.1 → 3.1.0-alpha.1

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 (29) hide show
  1. package/dist/src/packs/safe-4337/Safe4337Pack.d.ts +11 -5
  2. package/dist/src/packs/safe-4337/Safe4337Pack.js +184 -108
  3. package/dist/src/packs/safe-4337/Safe4337Pack.js.map +1 -1
  4. package/dist/src/packs/safe-4337/Safe4337Pack.test.js +218 -29
  5. package/dist/src/packs/safe-4337/Safe4337Pack.test.js.map +1 -1
  6. package/dist/src/packs/safe-4337/SafeOperation.d.ts +3 -1
  7. package/dist/src/packs/safe-4337/SafeOperation.js +2 -1
  8. package/dist/src/packs/safe-4337/SafeOperation.js.map +1 -1
  9. package/dist/src/packs/safe-4337/SafeOperation.test.js +5 -0
  10. package/dist/src/packs/safe-4337/SafeOperation.test.js.map +1 -1
  11. package/dist/src/packs/safe-4337/constants.d.ts +2 -0
  12. package/dist/src/packs/safe-4337/constants.js +5 -2
  13. package/dist/src/packs/safe-4337/constants.js.map +1 -1
  14. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.js +2 -2
  15. package/dist/src/packs/safe-4337/estimators/PimlicoFeeEstimator.js.map +1 -1
  16. package/dist/src/packs/safe-4337/testing-utils/fixtures.d.ts +36 -0
  17. package/dist/src/packs/safe-4337/testing-utils/fixtures.js +41 -5
  18. package/dist/src/packs/safe-4337/testing-utils/fixtures.js.map +1 -1
  19. package/dist/src/packs/safe-4337/testing-utils/helpers.js +0 -1
  20. package/dist/src/packs/safe-4337/testing-utils/helpers.js.map +1 -1
  21. package/dist/src/packs/safe-4337/types.d.ts +2 -4
  22. package/dist/src/packs/safe-4337/utils/entrypoint.d.ts +4 -0
  23. package/dist/src/packs/safe-4337/utils/entrypoint.js +23 -0
  24. package/dist/src/packs/safe-4337/utils/entrypoint.js.map +1 -0
  25. package/dist/src/packs/safe-4337/utils.d.ts +61 -5
  26. package/dist/src/packs/safe-4337/utils.js +131 -9
  27. package/dist/src/packs/safe-4337/utils.js.map +1 -1
  28. package/dist/tsconfig.build.tsbuildinfo +1 -1
  29. package/package.json +4 -4
@@ -1,5 +1,6 @@
1
1
  import { SigningMethod } from '@safe-global/protocol-kit';
2
2
  import { RelayKitBasePack } from '../../RelayKitBasePack';
3
+ import { SafeOperationResponse } from '@safe-global/safe-core-sdk-types';
3
4
  import EthSafeOperation from './SafeOperation';
4
5
  import { EstimateFeeProps, Safe4337CreateTransactionProps, Safe4337ExecutableProps, Safe4337InitOptions, Safe4337Options, UserOperationReceipt, UserOperationWithPayload } from './types';
5
6
  /**
@@ -25,7 +26,7 @@ export declare class Safe4337Pack extends RelayKitBasePack<{
25
26
  *
26
27
  * @param {Safe4337Options} options - The initialization parameters.
27
28
  */
28
- constructor({ protocolKit, bundlerClient, publicClient, bundlerUrl, paymasterOptions, entryPointAddress, safe4337ModuleAddress }: Safe4337Options);
29
+ constructor({ protocolKit, bundlerClient, bundlerUrl, paymasterOptions, entryPointAddress, safe4337ModuleAddress }: Safe4337Options);
29
30
  /**
30
31
  * Initializes a Safe4337Pack class.
31
32
  * This method creates the protocolKit instance based on the input parameters.
@@ -57,18 +58,23 @@ export declare class Safe4337Pack extends RelayKitBasePack<{
57
58
  /**
58
59
  * Signs a safe operation.
59
60
  *
60
- * @param {EthSafeOperation} safeOperation - The SafeOperation to sign.
61
+ * @param {EthSafeOperation | SafeOperationResponse} safeOperation - The SafeOperation to sign. It can be:
62
+ * - A response from the API (Tx Service)
63
+ * - An instance of EthSafeOperation
61
64
  * @param {SigningMethod} signingMethod - The signing method to use.
62
65
  * @return {Promise<EthSafeOperation>} The Promise object will resolve to the signed SafeOperation.
63
66
  */
64
- signSafeOperation(safeOperation: EthSafeOperation, signingMethod?: SigningMethod): Promise<EthSafeOperation>;
67
+ signSafeOperation(safeOperation: EthSafeOperation | SafeOperationResponse, signingMethod?: SigningMethod): Promise<EthSafeOperation>;
65
68
  /**
66
69
  * Executes the relay transaction.
67
70
  *
68
- * @param {EthSafeOperation} safeOperation - The SafeOperation to execute.
71
+ * @param {Safe4337ExecutableProps} props - The parameters for the transaction execution.
72
+ * @param {EthSafeOperation | SafeOperationResponse} props.executable - The SafeOperation to execute. It can be:
73
+ * - A response from the API (Tx Service)
74
+ * - An instance of EthSafeOperation
69
75
  * @return {Promise<string>} The user operation hash.
70
76
  */
71
- executeTransaction({ executable: safeOperation }: Safe4337ExecutableProps): Promise<string>;
77
+ executeTransaction({ executable }: Safe4337ExecutableProps): Promise<string>;
72
78
  /**
73
79
  * Return a UserOperation based on a hash (userOpHash) returned by eth_sendUserOperation
74
80
  *
@@ -36,7 +36,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
36
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
- var _Safe4337Pack_instances, _Safe4337Pack_BUNDLER_URL, _Safe4337Pack_ENTRYPOINT_ADDRESS, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, _Safe4337Pack_bundlerClient, _Safe4337Pack_publicClient, _Safe4337Pack_paymasterOptions, _Safe4337Pack_getSafeUserOperationHash, _Safe4337Pack_sendUserOperation, _Safe4337Pack_signTypedData, _Safe4337Pack_getAccountNonce, _Safe4337Pack_encodeExecuteUserOpCallData, _Safe4337Pack_encodeMultiSendCallData;
39
+ var _Safe4337Pack_instances, _Safe4337Pack_BUNDLER_URL, _Safe4337Pack_ENTRYPOINT_ADDRESS, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, _Safe4337Pack_bundlerClient, _Safe4337Pack_paymasterOptions, _Safe4337Pack_toSafeOperation, _Safe4337Pack_getSafeNonceFromEntrypoint, _Safe4337Pack_encodeExecuteUserOpCallData;
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.Safe4337Pack = void 0;
42
42
  const ethers_1 = require("ethers");
@@ -48,8 +48,20 @@ const safe_modules_deployments_1 = require("@safe-global/safe-modules-deployment
48
48
  const SafeOperation_1 = __importDefault(require("./SafeOperation"));
49
49
  const constants_1 = require("./constants");
50
50
  const utils_1 = require("./utils");
51
+ const entrypoint_1 = require("./utils/entrypoint");
51
52
  const PimlicoFeeEstimator_1 = require("./estimators/PimlicoFeeEstimator");
52
53
  const MAX_ERC20_AMOUNT_TO_APPROVE = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn;
54
+ const EQ_OR_GT_1_4_1 = '>=1.4.1';
55
+ /**
56
+ Some of the contracts used in the PoC app are still experimental, and not included in
57
+ the production deployment packages, thus we need to hardcode their addresses here.
58
+ Deployment commit: https://github.com/safe-global/safe-modules/commit/3853f34f31837e0a0aee47a4452564278f8c62ba
59
+ */
60
+ // FIXME: use the production deployment packages instead of a hardcoded address
61
+ const SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS = '0x608Cf2e3412c6BDA14E6D8A0a7D27c4240FeD6F1';
62
+ // FIXME: use the production deployment packages instead of a hardcoded address
63
+ // Sepolia only
64
+ const P256_VERIFIER_ADDRESS = '0xcA89CBa4813D5B40AeC6E57A30d0Eeb500d6531b'; // FCLP256Verifier
53
65
  /**
54
66
  * Safe4337Pack class that extends RelayKitBasePack.
55
67
  * This class provides an implementation of the ERC-4337 that enables Safe accounts to wrk with UserOperations.
@@ -65,18 +77,16 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
65
77
  *
66
78
  * @param {Safe4337Options} options - The initialization parameters.
67
79
  */
68
- constructor({ protocolKit, bundlerClient, publicClient, bundlerUrl, paymasterOptions, entryPointAddress, safe4337ModuleAddress }) {
80
+ constructor({ protocolKit, bundlerClient, bundlerUrl, paymasterOptions, entryPointAddress, safe4337ModuleAddress }) {
69
81
  super(protocolKit);
70
82
  _Safe4337Pack_instances.add(this);
71
83
  _Safe4337Pack_BUNDLER_URL.set(this, void 0);
72
84
  _Safe4337Pack_ENTRYPOINT_ADDRESS.set(this, void 0);
73
85
  _Safe4337Pack_SAFE_4337_MODULE_ADDRESS.set(this, '0x');
74
86
  _Safe4337Pack_bundlerClient.set(this, void 0);
75
- _Safe4337Pack_publicClient.set(this, void 0);
76
87
  _Safe4337Pack_paymasterOptions.set(this, void 0);
77
88
  __classPrivateFieldSet(this, _Safe4337Pack_BUNDLER_URL, bundlerUrl, "f");
78
89
  __classPrivateFieldSet(this, _Safe4337Pack_bundlerClient, bundlerClient, "f");
79
- __classPrivateFieldSet(this, _Safe4337Pack_publicClient, publicClient, "f");
80
90
  __classPrivateFieldSet(this, _Safe4337Pack_paymasterOptions, paymasterOptions, "f");
81
91
  __classPrivateFieldSet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, entryPointAddress, "f");
82
92
  __classPrivateFieldSet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, safe4337ModuleAddress, "f");
@@ -92,17 +102,20 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
92
102
  * @return {Promise<Safe4337Pack>} The Promise object that will be resolved into an instance of Safe4337Pack.
93
103
  */
94
104
  static async init(initOptions) {
95
- const { provider, signer, options, bundlerUrl, rpcUrl, customContracts, paymasterOptions } = initOptions;
105
+ const { provider, signer, options, bundlerUrl, customContracts, paymasterOptions } = initOptions;
96
106
  let protocolKit;
97
107
  const bundlerClient = (0, utils_1.getEip4337BundlerProvider)(bundlerUrl);
98
- const publicClient = (0, utils_1.getEip1193Provider)(rpcUrl);
99
108
  const chainId = await bundlerClient.send(constants_1.RPC_4337_CALLS.CHAIN_ID, []);
100
109
  let addModulesLibAddress = customContracts?.addModulesLibAddress;
101
110
  const network = parseInt(chainId, 16).toString();
111
+ const safeModulesVersion = initOptions.safeModulesVersion || constants_1.DEFAULT_SAFE_MODULES_VERSION;
112
+ if ((0, satisfies_1.default)(safeModulesVersion, entrypoint_1.EQ_OR_GT_0_3_0)) {
113
+ throw new Error(`Incompatibility detected: Safe modules version ${safeModulesVersion} is not supported. The SDK can use 0.2.0 only.`);
114
+ }
102
115
  if (!addModulesLibAddress) {
103
116
  const addModulesDeployment = (0, safe_modules_deployments_1.getAddModulesLibDeployment)({
104
117
  released: true,
105
- version: initOptions.safeModulesVersion || constants_1.DEFAULT_SAFE_MODULES_VERSION,
118
+ version: safeModulesVersion,
106
119
  network
107
120
  });
108
121
  addModulesLibAddress = addModulesDeployment?.networkAddresses[network];
@@ -111,13 +124,13 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
111
124
  if (!safe4337ModuleAddress) {
112
125
  const safe4337ModuleDeployment = (0, safe_modules_deployments_1.getSafe4337ModuleDeployment)({
113
126
  released: true,
114
- version: initOptions.safeModulesVersion || constants_1.DEFAULT_SAFE_MODULES_VERSION,
127
+ version: safeModulesVersion,
115
128
  network
116
129
  });
117
130
  safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network];
118
131
  }
119
132
  if (!addModulesLibAddress || !safe4337ModuleAddress) {
120
- throw new Error(`Safe4337Module and/or AddModulesLib not available for chain ${network} and modules version ${constants_1.DEFAULT_SAFE_MODULES_VERSION}`);
133
+ throw new Error(`Safe4337Module and/or AddModulesLib not available for chain ${network} and modules version ${safeModulesVersion}`);
121
134
  }
122
135
  // Existing Safe
123
136
  if ('safeAddress' in options) {
@@ -127,7 +140,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
127
140
  safeAddress: options.safeAddress
128
141
  });
129
142
  const safeVersion = await protocolKit.getContractVersion();
130
- const isSafeVersion4337Compatible = (0, satisfies_1.default)(safeVersion, '>=1.4.1');
143
+ const isSafeVersion4337Compatible = (0, satisfies_1.default)(safeVersion, EQ_OR_GT_1_4_1);
131
144
  if (!isSafeVersion4337Compatible) {
132
145
  throw new Error(`Incompatibility detected: The current Safe Account version (${safeVersion}) is not supported. EIP-4337 requires the Safe to use at least v1.4.1.`);
133
146
  }
@@ -147,41 +160,74 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
147
160
  if (!options.owners || !options.threshold) {
148
161
  throw new Error('Owners and threshold are required to deploy a new Safe');
149
162
  }
150
- let deploymentTo = addModulesLibAddress;
151
- let deploymentData = constants_1.INTERFACES.encodeFunctionData('enableModules', [[safe4337ModuleAddress]]);
163
+ const safeVersion = options.safeVersion || constants_1.DEFAULT_SAFE_VERSION;
164
+ // we need to create a batch to setup the 4337 Safe Account
165
+ // first setup transaction: Enable 4337 module
166
+ const enable4337ModuleTransaction = {
167
+ to: addModulesLibAddress,
168
+ value: '0',
169
+ data: constants_1.INTERFACES.encodeFunctionData('enableModules', [[safe4337ModuleAddress]]),
170
+ operation: safe_core_sdk_types_1.OperationType.DelegateCall // DelegateCall required for enabling the 4337 module
171
+ };
172
+ const setupTransactions = [enable4337ModuleTransaction];
152
173
  const { isSponsored, paymasterTokenAddress } = paymasterOptions || {};
153
174
  const isApproveTransactionRequired = !!paymasterOptions && !isSponsored && !!paymasterTokenAddress;
154
175
  if (isApproveTransactionRequired) {
155
176
  const { paymasterAddress, amountToApprove = MAX_ERC20_AMOUNT_TO_APPROVE } = paymasterOptions;
156
- const enable4337ModulesTransaction = {
157
- to: addModulesLibAddress,
158
- value: '0',
159
- data: constants_1.INTERFACES.encodeFunctionData('enableModules', [[safe4337ModuleAddress]]),
160
- operation: safe_core_sdk_types_1.OperationType.DelegateCall // DelegateCall required for enabling the 4337 module
161
- };
177
+ // second transaction: approve ERC-20 paymaster token
162
178
  const approveToPaymasterTransaction = {
163
179
  to: paymasterTokenAddress,
164
180
  data: constants_1.INTERFACES.encodeFunctionData('approve', [paymasterAddress, amountToApprove]),
165
181
  value: '0',
166
182
  operation: safe_core_sdk_types_1.OperationType.Call // Call for approve
167
183
  };
168
- const setupBatch = [enable4337ModulesTransaction, approveToPaymasterTransaction];
169
- const batchData = constants_1.INTERFACES.encodeFunctionData('multiSend', [
170
- (0, protocol_kit_1.encodeMultiSendData)(setupBatch)
171
- ]);
184
+ setupTransactions.push(approveToPaymasterTransaction);
185
+ }
186
+ const safeProvider = await protocol_kit_1.SafeProvider.init(provider, signer, safeVersion);
187
+ // third transaction: passkey support via shared signer SafeWebAuthnSharedSigner
188
+ // see: https://github.com/safe-global/safe-modules/blob/main/modules/passkey/contracts/4337/experimental/README.md
189
+ const isPasskeySigner = await safeProvider.isPasskeySigner();
190
+ if (isPasskeySigner) {
191
+ const passkeySigner = (await safeProvider.getExternalSigner());
192
+ if (!options.owners.includes(SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS)) {
193
+ options.owners.push(SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS);
194
+ }
195
+ const passkeyOwnerConfiguration = {
196
+ ...passkeySigner.coordinates,
197
+ verifiers: P256_VERIFIER_ADDRESS
198
+ };
199
+ const sharedSignerTransaction = {
200
+ to: SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS,
201
+ value: '0',
202
+ data: constants_1.INTERFACES.encodeFunctionData('configure', [passkeyOwnerConfiguration]),
203
+ operation: safe_core_sdk_types_1.OperationType.DelegateCall // DelegateCall required into the SafeWebAuthnSharedSigner instance in order for it to set its configuration.
204
+ };
205
+ setupTransactions.push(sharedSignerTransaction);
206
+ }
207
+ let deploymentTo;
208
+ let deploymentData;
209
+ const isBatch = setupTransactions.length > 1;
210
+ if (isBatch) {
172
211
  const multiSendContract = await (0, protocol_kit_1.getMultiSendContract)({
173
- safeProvider: new protocol_kit_1.SafeProvider({ provider, signer }),
174
- safeVersion: options.safeVersion || constants_1.DEFAULT_SAFE_VERSION
212
+ safeProvider,
213
+ safeVersion
175
214
  });
215
+ const batchData = constants_1.INTERFACES.encodeFunctionData('multiSend', [
216
+ (0, protocol_kit_1.encodeMultiSendData)(setupTransactions)
217
+ ]);
176
218
  deploymentTo = await multiSendContract.getAddress();
177
219
  deploymentData = batchData;
178
220
  }
221
+ else {
222
+ deploymentTo = enable4337ModuleTransaction.to;
223
+ deploymentData = enable4337ModuleTransaction.data;
224
+ }
179
225
  protocolKit = await protocol_kit_1.default.init({
180
226
  provider,
181
227
  signer,
182
228
  predictedSafe: {
183
229
  safeDeploymentConfig: {
184
- safeVersion: options.safeVersion || constants_1.DEFAULT_SAFE_VERSION,
230
+ safeVersion,
185
231
  saltNonce: options.saltNonce || undefined
186
232
  },
187
233
  safeAccountConfig: {
@@ -197,20 +243,32 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
197
243
  }
198
244
  });
199
245
  }
200
- let supportedEntryPoints;
201
- if (!customContracts?.entryPointAddress) {
202
- supportedEntryPoints = await bundlerClient.send(constants_1.RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []);
246
+ let selectedEntryPoint;
247
+ if (customContracts?.entryPointAddress) {
248
+ const requiredSafeModulesVersion = (0, entrypoint_1.entryPointToSafeModules)(customContracts?.entryPointAddress);
249
+ if (!(0, satisfies_1.default)(safeModulesVersion, requiredSafeModulesVersion))
250
+ throw new Error(`The selected entrypoint ${customContracts?.entryPointAddress} is not compatible with version ${safeModulesVersion} of Safe modules`);
251
+ selectedEntryPoint = customContracts?.entryPointAddress;
252
+ }
253
+ else {
254
+ const supportedEntryPoints = await bundlerClient.send(constants_1.RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []);
203
255
  if (!supportedEntryPoints.length) {
204
256
  throw new Error('No entrypoint provided or available through the bundler');
205
257
  }
258
+ selectedEntryPoint = supportedEntryPoints.find((entryPoint) => {
259
+ const requiredSafeModulesVersion = (0, entrypoint_1.entryPointToSafeModules)(entryPoint);
260
+ return (0, satisfies_1.default)(safeModulesVersion, requiredSafeModulesVersion);
261
+ });
262
+ if (!selectedEntryPoint) {
263
+ throw new Error(`Incompatibility detected: None of the entrypoints provided by the bundler is compatible with the Safe modules version ${safeModulesVersion}`);
264
+ }
206
265
  }
207
266
  return new Safe4337Pack({
208
267
  protocolKit,
209
268
  bundlerClient,
210
- publicClient,
211
269
  paymasterOptions,
212
270
  bundlerUrl,
213
- entryPointAddress: customContracts?.entryPointAddress || supportedEntryPoints[0],
271
+ entryPointAddress: selectedEntryPoint,
214
272
  safe4337ModuleAddress
215
273
  });
216
274
  }
@@ -223,6 +281,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
223
281
  * @return {Promise<EthSafeOperation>} The Promise object that will be resolved into the gas estimation.
224
282
  */
225
283
  async getEstimateFee({ safeOperation, feeEstimator = new PimlicoFeeEstimator_1.PimlicoFeeEstimator() }) {
284
+ const threshold = await this.protocolKit.getThreshold();
226
285
  const setupEstimationData = await feeEstimator?.setupEstimation?.({
227
286
  bundlerUrl: __classPrivateFieldGet(this, _Safe4337Pack_BUNDLER_URL, "f"),
228
287
  entryPoint: __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f"),
@@ -231,7 +290,10 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
231
290
  if (setupEstimationData) {
232
291
  safeOperation.addEstimations(setupEstimationData);
233
292
  }
234
- const estimateUserOperationGas = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, [(0, utils_1.userOperationToHexValues)(safeOperation.toUserOperation()), __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f")]);
293
+ const estimateUserOperationGas = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, [
294
+ (0, utils_1.userOperationToHexValues)((0, utils_1.addDummySignature)(safeOperation.toUserOperation(), SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS, threshold)),
295
+ __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f")
296
+ ]);
235
297
  if (estimateUserOperationGas) {
236
298
  safeOperation.addEstimations({
237
299
  preVerificationGas: BigInt(estimateUserOperationGas.preVerificationGas),
@@ -252,7 +314,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
252
314
  throw new Error('No paymaster url provided for a sponsored transaction');
253
315
  }
254
316
  const paymasterEstimation = await feeEstimator?.getPaymasterEstimation?.({
255
- userOperation: safeOperation.toUserOperation(),
317
+ userOperation: (0, utils_1.addDummySignature)(safeOperation.toUserOperation(), SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS, threshold),
256
318
  paymasterUrl: __classPrivateFieldGet(this, _Safe4337Pack_paymasterOptions, "f").paymasterUrl,
257
319
  entryPoint: __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f"),
258
320
  sponsorshipPolicyId: __classPrivateFieldGet(this, _Safe4337Pack_paymasterOptions, "f").sponsorshipPolicyId
@@ -274,7 +336,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
274
336
  */
275
337
  async createTransaction({ transactions, options = {} }) {
276
338
  const safeAddress = await this.protocolKit.getAddress();
277
- const nonce = await __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_getAccountNonce).call(this, safeAddress);
339
+ const nonce = await __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_getSafeNonceFromEntrypoint).call(this, safeAddress);
278
340
  const { amountToApprove, validUntil, validAfter, feeEstimator } = options;
279
341
  if (amountToApprove) {
280
342
  if (!__classPrivateFieldGet(this, _Safe4337Pack_paymasterOptions, "f") || !__classPrivateFieldGet(this, _Safe4337Pack_paymasterOptions, "f").paymasterTokenAddress) {
@@ -296,7 +358,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
296
358
  ? __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_encodeExecuteUserOpCallData).call(this, {
297
359
  to: multiSendAddress,
298
360
  value: '0',
299
- data: __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_encodeMultiSendCallData).call(this, transactions),
361
+ data: (0, utils_1.encodeMultiSendCallData)(transactions),
300
362
  operation: safe_core_sdk_types_1.OperationType.DelegateCall
301
363
  })
302
364
  : __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_encodeExecuteUserOpCallData).call(this, transactions[0]);
@@ -319,6 +381,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
319
381
  userOperation.initCode = await this.protocolKit.getInitCode();
320
382
  }
321
383
  const safeOperation = new SafeOperation_1.default(userOperation, {
384
+ moduleAddress: __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"),
322
385
  entryPoint: __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f"),
323
386
  validUntil,
324
387
  validAfter
@@ -331,37 +394,60 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
331
394
  /**
332
395
  * Signs a safe operation.
333
396
  *
334
- * @param {EthSafeOperation} safeOperation - The SafeOperation to sign.
397
+ * @param {EthSafeOperation | SafeOperationResponse} safeOperation - The SafeOperation to sign. It can be:
398
+ * - A response from the API (Tx Service)
399
+ * - An instance of EthSafeOperation
335
400
  * @param {SigningMethod} signingMethod - The signing method to use.
336
401
  * @return {Promise<EthSafeOperation>} The Promise object will resolve to the signed SafeOperation.
337
402
  */
338
403
  async signSafeOperation(safeOperation, signingMethod = protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4) {
404
+ let safeOp;
405
+ if ((0, safe_core_sdk_types_1.isSafeOperationResponse)(safeOperation)) {
406
+ safeOp = __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_toSafeOperation).call(this, safeOperation);
407
+ }
408
+ else {
409
+ safeOp = safeOperation;
410
+ }
339
411
  const owners = await this.protocolKit.getOwners();
340
- const signerAddress = await this.protocolKit.getSafeProvider().getSignerAddress();
412
+ const safeProvider = this.protocolKit.getSafeProvider();
413
+ const signerAddress = await safeProvider.getSignerAddress();
414
+ const chainId = await safeProvider.getChainId();
415
+ const isPasskeySigner = await safeProvider.isPasskeySigner();
341
416
  if (!signerAddress) {
342
417
  throw new Error('There is no signer address available to sign the SafeOperation');
343
418
  }
344
419
  const addressIsOwner = owners.some((owner) => signerAddress && owner.toLowerCase() === signerAddress.toLowerCase());
345
- if (!addressIsOwner) {
420
+ if (!addressIsOwner && !isPasskeySigner) {
346
421
  throw new Error('UserOperations can only be signed by Safe owners');
347
422
  }
348
423
  let signature;
349
- if (signingMethod === protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4 ||
350
- signingMethod === protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA_V3 ||
351
- signingMethod === protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA) {
352
- signature = await __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_signTypedData).call(this, safeOperation.data);
424
+ if (isPasskeySigner) {
425
+ const safeOpHash = (0, utils_1.calculateSafeUserOperationHash)(safeOp.data, chainId, __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"));
426
+ const passkeySignature = await this.protocolKit.signHash(safeOpHash);
427
+ // SafeWebAuthnSharedSigner signature
428
+ signature = new protocol_kit_1.EthSafeSignature(SAFE_WEBAUTHN_SHARED_SIGNER_ADDRESS, passkeySignature.data, true);
353
429
  }
354
430
  else {
355
- const chainId = await this.protocolKit.getSafeProvider().getChainId();
356
- const safeOpHash = __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_getSafeUserOperationHash).call(this, safeOperation.data, chainId);
357
- signature = await this.protocolKit.signHash(safeOpHash);
431
+ if (signingMethod in
432
+ [
433
+ protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4,
434
+ protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA_V3,
435
+ protocol_kit_1.SigningMethod.ETH_SIGN_TYPED_DATA
436
+ ]) {
437
+ signature = await (0, utils_1.signSafeOp)(safeOp.data, this.protocolKit.getSafeProvider(), __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"));
438
+ }
439
+ else {
440
+ const safeOpHash = (0, utils_1.calculateSafeUserOperationHash)(safeOp.data, chainId, __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"));
441
+ signature = await this.protocolKit.signHash(safeOpHash);
442
+ }
358
443
  }
359
- const signedSafeOperation = new SafeOperation_1.default(safeOperation.toUserOperation(), {
444
+ const signedSafeOperation = new SafeOperation_1.default(safeOp.toUserOperation(), {
445
+ moduleAddress: __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"),
360
446
  entryPoint: __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f"),
361
- validUntil: safeOperation.data.validUntil,
362
- validAfter: safeOperation.data.validAfter
447
+ validUntil: safeOp.data.validUntil,
448
+ validAfter: safeOp.data.validAfter
363
449
  });
364
- signedSafeOperation.signatures.forEach((signature) => {
450
+ safeOp.signatures.forEach((signature) => {
365
451
  signedSafeOperation.addSignature(signature);
366
452
  });
367
453
  signedSafeOperation.addSignature(signature);
@@ -370,12 +456,25 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
370
456
  /**
371
457
  * Executes the relay transaction.
372
458
  *
373
- * @param {EthSafeOperation} safeOperation - The SafeOperation to execute.
459
+ * @param {Safe4337ExecutableProps} props - The parameters for the transaction execution.
460
+ * @param {EthSafeOperation | SafeOperationResponse} props.executable - The SafeOperation to execute. It can be:
461
+ * - A response from the API (Tx Service)
462
+ * - An instance of EthSafeOperation
374
463
  * @return {Promise<string>} The user operation hash.
375
464
  */
376
- async executeTransaction({ executable: safeOperation }) {
465
+ async executeTransaction({ executable }) {
466
+ let safeOperation;
467
+ if ((0, safe_core_sdk_types_1.isSafeOperationResponse)(executable)) {
468
+ safeOperation = __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_toSafeOperation).call(this, executable);
469
+ }
470
+ else {
471
+ safeOperation = executable;
472
+ }
377
473
  const userOperation = safeOperation.toUserOperation();
378
- return __classPrivateFieldGet(this, _Safe4337Pack_instances, "m", _Safe4337Pack_sendUserOperation).call(this, userOperation);
474
+ return __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.SEND_USER_OPERATION, [
475
+ (0, utils_1.userOperationToHexValues)(userOperation),
476
+ __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f")
477
+ ]);
379
478
  }
380
479
  /**
381
480
  * Return a UserOperation based on a hash (userOpHash) returned by eth_sendUserOperation
@@ -384,8 +483,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
384
483
  * @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
385
484
  */
386
485
  async getUserOperationByHash(userOpHash) {
387
- const userOperation = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH, [userOpHash]);
388
- return userOperation;
486
+ return __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH, [userOpHash]);
389
487
  }
390
488
  /**
391
489
  * Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation
@@ -394,8 +492,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
394
492
  * @returns {UserOperationReceipt} - null in case the UserOperation is not yet included in a block, or UserOperationReceipt object
395
493
  */
396
494
  async getUserOperationReceipt(userOpHash) {
397
- const userOperationReceipt = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT, [userOpHash]);
398
- return userOperationReceipt;
495
+ return __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT, [userOpHash]);
399
496
  }
400
497
  /**
401
498
  * Returns an array of the entryPoint addresses supported by the client.
@@ -404,8 +501,7 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
404
501
  * @returns {string[]} - The supported entry points.
405
502
  */
406
503
  async getSupportedEntryPoints() {
407
- const supportedEntryPoints = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []);
408
- return supportedEntryPoints;
504
+ return __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []);
409
505
  }
410
506
  /**
411
507
  * Returns EIP-155 Chain ID.
@@ -413,60 +509,44 @@ class Safe4337Pack extends RelayKitBasePack_1.RelayKitBasePack {
413
509
  * @returns {string} - The chain id.
414
510
  */
415
511
  async getChainId() {
416
- const chainId = await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.CHAIN_ID, []);
417
- return chainId;
512
+ return __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.CHAIN_ID, []);
418
513
  }
419
514
  }
420
515
  exports.Safe4337Pack = Safe4337Pack;
421
- _Safe4337Pack_BUNDLER_URL = new WeakMap(), _Safe4337Pack_ENTRYPOINT_ADDRESS = new WeakMap(), _Safe4337Pack_SAFE_4337_MODULE_ADDRESS = new WeakMap(), _Safe4337Pack_bundlerClient = new WeakMap(), _Safe4337Pack_publicClient = new WeakMap(), _Safe4337Pack_paymasterOptions = new WeakMap(), _Safe4337Pack_instances = new WeakSet(), _Safe4337Pack_getSafeUserOperationHash = function _Safe4337Pack_getSafeUserOperationHash(safeUserOperation, chainId) {
422
- return ethers_1.ethers.TypedDataEncoder.hash({
423
- chainId,
424
- verifyingContract: __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f")
425
- }, constants_1.EIP712_SAFE_OPERATION_TYPE, safeUserOperation);
426
- }, _Safe4337Pack_sendUserOperation =
427
- /**
428
- * Send the UserOperation to the bundler.
429
- *
430
- * @param {UserOperation} userOpWithSignature - The signed UserOperation to send to the bundler.
431
- * @return {Promise<string>} The hash.
432
- */
433
- async function _Safe4337Pack_sendUserOperation(userOpWithSignature) {
434
- return await __classPrivateFieldGet(this, _Safe4337Pack_bundlerClient, "f").send(constants_1.RPC_4337_CALLS.SEND_USER_OPERATION, [
435
- (0, utils_1.userOperationToHexValues)(userOpWithSignature),
436
- __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f")
437
- ]);
438
- }, _Safe4337Pack_signTypedData =
439
- /**
440
- * Signs typed data.
441
- *
442
- * @param {SafeUserOperation} safeUserOperation - Safe user operation to sign.
443
- * @return {Promise<SafeSignature>} The SafeSignature object containing the data and the signatures.
444
- */
445
- async function _Safe4337Pack_signTypedData(safeUserOperation) {
446
- const safeProvider = this.protocolKit.getSafeProvider();
447
- const signer = (await safeProvider.getExternalSigner());
448
- const chainId = await safeProvider.getChainId();
449
- const signerAddress = await signer.getAddress();
450
- const signature = await signer.signTypedData({
451
- chainId,
452
- verifyingContract: __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f")
453
- }, constants_1.EIP712_SAFE_OPERATION_TYPE, {
454
- ...safeUserOperation,
455
- nonce: ethers_1.ethers.toBeHex(safeUserOperation.nonce),
456
- validAfter: ethers_1.ethers.toBeHex(safeUserOperation.validAfter),
457
- validUntil: ethers_1.ethers.toBeHex(safeUserOperation.validUntil),
458
- maxFeePerGas: ethers_1.ethers.toBeHex(safeUserOperation.maxFeePerGas),
459
- maxPriorityFeePerGas: ethers_1.ethers.toBeHex(safeUserOperation.maxPriorityFeePerGas)
516
+ _Safe4337Pack_BUNDLER_URL = new WeakMap(), _Safe4337Pack_ENTRYPOINT_ADDRESS = new WeakMap(), _Safe4337Pack_SAFE_4337_MODULE_ADDRESS = new WeakMap(), _Safe4337Pack_bundlerClient = new WeakMap(), _Safe4337Pack_paymasterOptions = new WeakMap(), _Safe4337Pack_instances = new WeakSet(), _Safe4337Pack_toSafeOperation = function _Safe4337Pack_toSafeOperation(safeOperationResponse) {
517
+ const { validUntil, validAfter, userOperation } = safeOperationResponse;
518
+ const safeOperation = new SafeOperation_1.default({
519
+ sender: userOperation?.sender || '0x',
520
+ nonce: userOperation?.nonce?.toString() || '0',
521
+ initCode: userOperation?.initCode || '',
522
+ callData: userOperation?.callData || '',
523
+ callGasLimit: BigInt(userOperation?.callGasLimit || 0n),
524
+ verificationGasLimit: BigInt(userOperation?.verificationGasLimit || 0),
525
+ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0),
526
+ maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0),
527
+ maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0),
528
+ paymasterAndData: userOperation?.paymasterData || '0x',
529
+ signature: userOperation?.signature || '0x'
530
+ }, {
531
+ moduleAddress: __classPrivateFieldGet(this, _Safe4337Pack_SAFE_4337_MODULE_ADDRESS, "f"),
532
+ entryPoint: userOperation?.entryPoint || __classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f"),
533
+ validAfter: validAfter ? new Date(validAfter).getTime() : undefined,
534
+ validUntil: validUntil ? new Date(validUntil).getTime() : undefined
460
535
  });
461
- return new protocol_kit_1.EthSafeSignature(signerAddress, signature);
462
- }, _Safe4337Pack_getAccountNonce =
536
+ if (safeOperationResponse.confirmations) {
537
+ safeOperationResponse.confirmations.forEach((confirmation) => {
538
+ safeOperation.addSignature(new protocol_kit_1.EthSafeSignature(confirmation.owner, confirmation.signature));
539
+ });
540
+ }
541
+ return safeOperation;
542
+ }, _Safe4337Pack_getSafeNonceFromEntrypoint =
463
543
  /**
464
544
  * Gets account nonce from the bundler.
465
545
  *
466
- * @param {string} sender - Account address for which the nonce is to be fetched.
546
+ * @param {string} safeAddress - Account address for which the nonce is to be fetched.
467
547
  * @returns {Promise<string>} The Promise object will resolve to the account nonce.
468
548
  */
469
- async function _Safe4337Pack_getAccountNonce(sender) {
549
+ async function _Safe4337Pack_getSafeNonceFromEntrypoint(safeAddress) {
470
550
  const abi = [
471
551
  {
472
552
  inputs: [
@@ -479,8 +559,8 @@ async function _Safe4337Pack_getAccountNonce(sender) {
479
559
  type: 'function'
480
560
  }
481
561
  ];
482
- const contract = new ethers_1.ethers.Contract(__classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f") || '0x', abi, __classPrivateFieldGet(this, _Safe4337Pack_publicClient, "f"));
483
- const newNonce = await contract.getNonce(sender, BigInt(0));
562
+ const contract = new ethers_1.ethers.Contract(__classPrivateFieldGet(this, _Safe4337Pack_ENTRYPOINT_ADDRESS, "f") || '0x', abi, this.protocolKit.getSafeProvider().getExternalProvider());
563
+ const newNonce = await contract.getNonce(safeAddress, BigInt(0));
484
564
  return newNonce.toString();
485
565
  }, _Safe4337Pack_encodeExecuteUserOpCallData = function _Safe4337Pack_encodeExecuteUserOpCallData(transaction) {
486
566
  return constants_1.INTERFACES.encodeFunctionData('executeUserOp', [
@@ -489,9 +569,5 @@ async function _Safe4337Pack_getAccountNonce(sender) {
489
569
  transaction.data,
490
570
  transaction.operation || safe_core_sdk_types_1.OperationType.Call
491
571
  ]);
492
- }, _Safe4337Pack_encodeMultiSendCallData = function _Safe4337Pack_encodeMultiSendCallData(transactions) {
493
- return constants_1.INTERFACES.encodeFunctionData('multiSend', [
494
- (0, protocol_kit_1.encodeMultiSendData)(transactions.map((tx) => ({ ...tx, operation: tx.operation ?? safe_core_sdk_types_1.OperationType.Call })))
495
- ]);
496
572
  };
497
573
  //# sourceMappingURL=Safe4337Pack.js.map