@safe-global/protocol-kit 2.0.1-alpha.0 → 3.0.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 (35) hide show
  1. package/README.md +7 -4
  2. package/dist/src/Safe.d.ts +57 -7
  3. package/dist/src/Safe.js +218 -35
  4. package/dist/src/Safe.js.map +1 -1
  5. package/dist/src/adapters/ethers/EthersAdapter.d.ts +2 -2
  6. package/dist/src/adapters/ethers/EthersAdapter.js +5 -3
  7. package/dist/src/adapters/ethers/EthersAdapter.js.map +1 -1
  8. package/dist/src/adapters/web3/Web3Adapter.d.ts +2 -2
  9. package/dist/src/adapters/web3/Web3Adapter.js +6 -5
  10. package/dist/src/adapters/web3/Web3Adapter.js.map +1 -1
  11. package/dist/src/index.d.ts +5 -3
  12. package/dist/src/index.js +17 -1
  13. package/dist/src/index.js.map +1 -1
  14. package/dist/src/types/index.d.ts +8 -0
  15. package/dist/src/types/index.js +9 -0
  16. package/dist/src/types/index.js.map +1 -1
  17. package/dist/src/utils/eip-3770/config.js +14 -1
  18. package/dist/src/utils/eip-3770/config.js.map +1 -1
  19. package/dist/src/utils/eip-712/index.d.ts +6 -9
  20. package/dist/src/utils/eip-712/index.js +57 -18
  21. package/dist/src/utils/eip-712/index.js.map +1 -1
  22. package/dist/src/utils/messages/SafeMessage.d.ts +10 -0
  23. package/dist/src/utils/messages/SafeMessage.js +20 -0
  24. package/dist/src/utils/messages/SafeMessage.js.map +1 -0
  25. package/dist/src/utils/signatures/SafeSignature.d.ts +3 -2
  26. package/dist/src/utils/signatures/SafeSignature.js +10 -2
  27. package/dist/src/utils/signatures/SafeSignature.js.map +1 -1
  28. package/dist/src/utils/signatures/utils.d.ts +11 -4
  29. package/dist/src/utils/signatures/utils.js +75 -7
  30. package/dist/src/utils/signatures/utils.js.map +1 -1
  31. package/dist/src/utils/transactions/SafeTransaction.d.ts +1 -0
  32. package/dist/src/utils/transactions/SafeTransaction.js +5 -10
  33. package/dist/src/utils/transactions/SafeTransaction.js.map +1 -1
  34. package/dist/tsconfig.build.tsbuildinfo +1 -1
  35. package/package.json +3 -5
package/README.md CHANGED
@@ -627,7 +627,7 @@ const safeTransaction = await safeSdk.createTransaction({ transactions })
627
627
  const txHash = await safeSdk.getTransactionHash(safeTransaction)
628
628
  ```
629
629
 
630
- ### signTransactionHash
630
+ ### signHash
631
631
 
632
632
  Signs a hash using the current owner account.
633
633
 
@@ -639,7 +639,7 @@ const transactions: MetaTransactionData[] = [
639
639
  ]
640
640
  const safeTransaction = await safeSdk.createTransaction({ transactions })
641
641
  const txHash = await safeSdk.getTransactionHash(safeTransaction)
642
- const signature = await safeSdk.signTransactionHash(txHash)
642
+ const signature = await safeSdk.signHash(txHash)
643
643
  ```
644
644
 
645
645
  ### signTypedData
@@ -673,11 +673,14 @@ const signedSafeTransaction = await safeSdk.signTransaction(safeTransaction)
673
673
  Optionally, an additional parameter can be passed to specify a different way of signing:
674
674
 
675
675
  ```js
676
- const signedSafeTransaction = await safeSdk.signTransaction(safeTransaction, 'eth_signTypedData')
676
+ const signedSafeTransaction = await safeSdk.signTransaction(
677
+ safeTransaction,
678
+ SigningMethod.ETH_SIGN_TYPED_DATA
679
+ )
677
680
  ```
678
681
 
679
682
  ```js
680
- const signedSafeTransaction = await safeSdk.signTransaction(safeTransaction, 'eth_sign') // default option.
683
+ const signedSafeTransaction = await safeSdk.signTransaction(safeTransaction, SigningMethod.ETH_SIGN) // default option.
681
684
  ```
682
685
 
683
686
  ### approveTransactionHash
@@ -1,7 +1,8 @@
1
- import { EthAdapter, SafeMultisigTransactionResponse, SafeSignature, SafeTransaction, SafeVersion, TransactionOptions, TransactionResult, MetaTransactionData, Transaction } from '@safe-global/safe-core-sdk-types';
1
+ import { EthAdapter, SafeMultisigTransactionResponse, SafeSignature, SafeTransaction, SafeVersion, TransactionOptions, TransactionResult, MetaTransactionData, Transaction, EIP712TypedData } from '@safe-global/safe-core-sdk-types';
2
2
  import ContractManager from './managers/contractManager';
3
- import { AddOwnerTxParams, ConnectSafeConfig, CreateTransactionProps, RemoveOwnerTxParams, SafeConfig, SwapOwnerTxParams } from './types';
3
+ import { AddOwnerTxParams, ConnectSafeConfig, CreateTransactionProps, RemoveOwnerTxParams, SafeConfig, SigningMethodType, SwapOwnerTxParams } from './types';
4
4
  import { SafeTransactionOptionalProps } from './utils/transactions/types';
5
+ import SafeMessage from './utils/messages/SafeMessage';
5
6
  declare class Safe {
6
7
  #private;
7
8
  /**
@@ -163,7 +164,7 @@ declare class Safe {
163
164
  * Returns the transaction hash of a Safe transaction.
164
165
  *
165
166
  * @param safeTransaction - The Safe transaction
166
- * @returns The transaction hash of the Safe transaction
167
+ * @returns The hash of the Safe transaction
167
168
  */
168
169
  getTransactionHash(safeTransaction: SafeTransaction): Promise<string>;
169
170
  /**
@@ -172,24 +173,47 @@ declare class Safe {
172
173
  * @param hash - The hash to sign
173
174
  * @returns The Safe signature
174
175
  */
175
- signTransactionHash(hash: string): Promise<SafeSignature>;
176
+ signHash(hash: string): Promise<SafeSignature>;
177
+ /**
178
+ * Returns a Safe message ready to be signed by the owners.
179
+ *
180
+ * @param message - The message
181
+ * @returns The Safe message
182
+ */
183
+ createMessage(message: string | EIP712TypedData): SafeMessage;
184
+ /**
185
+ * Returns the Safe message with a new signature
186
+ *
187
+ * @param message The message to be signed
188
+ * @param signingMethod The signature type
189
+ * @param preimageSafeAddress If the preimage is required, the address of the Safe that will be used to calculate the preimage.
190
+ * This field is mandatory for 1.4.1 contract versions Because the safe uses the old EIP-1271 interface which uses `bytes` instead of `bytes32` for the message
191
+ * we need to use the pre-image of the message to calculate the message hash
192
+ * https://github.com/safe-global/safe-contracts/blob/192c7dc67290940fcbc75165522bb86a37187069/test/core/Safe.Signatures.spec.ts#L229-L233
193
+ * @returns The signed Safe message
194
+ */
195
+ signMessage(message: SafeMessage, signingMethod?: SigningMethodType, preimageSafeAddress?: string): Promise<SafeMessage>;
176
196
  /**
177
197
  * Signs a transaction according to the EIP-712 using the current signer account.
178
198
  *
179
- * @param safeTransaction - The Safe transaction to be signed
199
+ * @param eip712Data - The Safe Transaction or message hash to be signed
180
200
  * @param methodVersion - EIP-712 version. Optional
181
201
  * @returns The Safe signature
182
202
  */
183
- signTypedData(safeTransaction: SafeTransaction, methodVersion?: 'v3' | 'v4'): Promise<SafeSignature>;
203
+ signTypedData(eip712Data: SafeTransaction | SafeMessage, methodVersion?: 'v3' | 'v4'): Promise<SafeSignature>;
184
204
  /**
185
205
  * Adds the signature of the current signer to the Safe transaction object.
186
206
  *
187
207
  * @param safeTransaction - The Safe transaction to be signed
188
208
  * @param signingMethod - Method followed to sign a transaction. Optional. Default value is "eth_sign"
209
+ * @param preimageSafeAddress - If the preimage is required, the address of the Safe that will be used to calculate the preimage
210
+ * This field is mandatory for 1.3.0 and 1.4.1 contract versions Because the safe uses the old EIP-1271 interface which uses `bytes` instead of `bytes32` for the message
211
+ * we need to use the pre-image of the message to calculate the message hash
212
+ * https://github.com/safe-global/safe-contracts/blob/192c7dc67290940fcbc75165522bb86a37187069/test/core/Safe.Signatures.spec.ts#L229-L233
189
213
  * @returns The signed Safe transaction
190
214
  * @throws "Transactions can only be signed by Safe owners"
191
215
  */
192
- signTransaction(safeTransaction: SafeTransaction | SafeMultisigTransactionResponse, signingMethod?: 'eth_sign' | 'eth_signTypedData' | 'eth_signTypedData_v3' | 'eth_signTypedData_v4'): Promise<SafeTransaction>;
216
+ signTransaction(safeTransaction: SafeTransaction | SafeMultisigTransactionResponse, signingMethod?: SigningMethodType, preimageSafeAddress?: string): Promise<SafeTransaction>;
193
217
  /**
194
218
  * Approves on-chain a hash using the current signer account.
195
219
  *
@@ -389,5 +413,31 @@ declare class Safe {
389
413
  *
390
414
  */
391
415
  createTransactionBatch(transactions: MetaTransactionData[], transactionOptions?: TransactionOptions): Promise<Transaction>;
416
+ /**
417
+ * Get the fallback handler contract
418
+ *
419
+ * @returns The fallback Handler contract
420
+ */
421
+ private getFallbackHandlerContract;
422
+ /**
423
+ * Call the CompatibilityFallbackHandler getMessageHash method
424
+ *
425
+ * @param messageHash The hash of the message
426
+ * @returns Returns the Safe message hash to be signed
427
+ * @link https://github.com/safe-global/safe-contracts/blob/8ffae95faa815acf86ec8b50021ebe9f96abde10/contracts/handler/CompatibilityFallbackHandler.sol#L26-L28
428
+ */
429
+ getSafeMessageHash: (messageHash: string) => Promise<string>;
430
+ /**
431
+ * Call the CompatibilityFallbackHandler isValidSignature method
432
+ *
433
+ * @param messageHash The hash of the message
434
+ * @param signature The signature to be validated or '0x'. You can send as signature one of the following:
435
+ * 1) An array of SafeSignature. In this case the signatures are concatenated for validation (buildSignatureBytes())
436
+ * 2) The concatenated signatures as string
437
+ * 3) '0x' if you want to validate an onchain message (Approved hash)
438
+ * @returns A boolean indicating if the signature is valid
439
+ * @link https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol
440
+ */
441
+ isValidSignature: (messageHash: string, signature?: SafeSignature[] | string) => Promise<boolean>;
392
442
  }
393
443
  export default Safe;
package/dist/src/Safe.js CHANGED
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _Safe_predictedSafe, _Safe_ethAdapter, _Safe_contractManager, _Safe_ownerManager, _Safe_moduleManager, _Safe_guardManager, _Safe_fallbackHandlerManager;
16
+ var _Safe_predictedSafe, _Safe_ethAdapter, _Safe_contractManager, _Safe_ownerManager, _Safe_moduleManager, _Safe_guardManager, _Safe_fallbackHandlerManager, _Safe_MAGIC_VALUE, _Safe_MAGIC_VALUE_BYTES;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const safe_core_sdk_types_1 = require("@safe-global/safe-core-sdk-types");
19
19
  const utils_1 = require("./contracts/utils");
@@ -23,12 +23,16 @@ const fallbackHandlerManager_1 = __importDefault(require("./managers/fallbackHan
23
23
  const guardManager_1 = __importDefault(require("./managers/guardManager"));
24
24
  const moduleManager_1 = __importDefault(require("./managers/moduleManager"));
25
25
  const ownerManager_1 = __importDefault(require("./managers/ownerManager"));
26
+ const types_1 = require("./types");
26
27
  const utils_2 = require("./utils");
27
- const utils_3 = require("./utils/signatures/utils");
28
28
  const SafeTransaction_1 = __importDefault(require("./utils/transactions/SafeTransaction"));
29
- const utils_4 = require("./utils/transactions/utils");
30
- const types_1 = require("./utils/types");
29
+ const utils_3 = require("./utils/transactions/utils");
30
+ const types_2 = require("./utils/types");
31
31
  const safeDeploymentContracts_1 = require("./contracts/safeDeploymentContracts");
32
+ const SafeMessage_1 = __importDefault(require("./utils/messages/SafeMessage"));
33
+ const satisfies_1 = __importDefault(require("semver/functions/satisfies"));
34
+ const EQ_OR_GT_1_4_1 = '>=1.4.1';
35
+ const EQ_OR_GT_1_3_0 = '>=1.3.0';
32
36
  class Safe {
33
37
  constructor() {
34
38
  _Safe_predictedSafe.set(this, void 0);
@@ -38,6 +42,75 @@ class Safe {
38
42
  _Safe_moduleManager.set(this, void 0);
39
43
  _Safe_guardManager.set(this, void 0);
40
44
  _Safe_fallbackHandlerManager.set(this, void 0);
45
+ _Safe_MAGIC_VALUE.set(this, '0x1626ba7e');
46
+ _Safe_MAGIC_VALUE_BYTES.set(this, '0x20c13b0b'
47
+ /**
48
+ * Creates an instance of the Safe Core SDK.
49
+ * @param config - Ethers Safe configuration
50
+ * @returns The Safe Core SDK instance
51
+ * @throws "The SDK must be initialized with a safeAddress or a predictedSafe"
52
+ * @throws "SafeProxy contract is not deployed on the current network"
53
+ * @throws "MultiSend contract is not deployed on the current network"
54
+ * @throws "MultiSendCallOnly contract is not deployed on the current network"
55
+ */
56
+ );
57
+ /**
58
+ * Call the CompatibilityFallbackHandler getMessageHash method
59
+ *
60
+ * @param messageHash The hash of the message
61
+ * @returns Returns the Safe message hash to be signed
62
+ * @link https://github.com/safe-global/safe-contracts/blob/8ffae95faa815acf86ec8b50021ebe9f96abde10/contracts/handler/CompatibilityFallbackHandler.sol#L26-L28
63
+ */
64
+ this.getSafeMessageHash = async (messageHash) => {
65
+ const safeAddress = await this.getAddress();
66
+ const safeVersion = await this.getContractVersion();
67
+ const chainId = await this.getChainId();
68
+ return (0, utils_2.calculateSafeMessageHash)(safeAddress, messageHash, safeVersion, chainId);
69
+ };
70
+ /**
71
+ * Call the CompatibilityFallbackHandler isValidSignature method
72
+ *
73
+ * @param messageHash The hash of the message
74
+ * @param signature The signature to be validated or '0x'. You can send as signature one of the following:
75
+ * 1) An array of SafeSignature. In this case the signatures are concatenated for validation (buildSignatureBytes())
76
+ * 2) The concatenated signatures as string
77
+ * 3) '0x' if you want to validate an onchain message (Approved hash)
78
+ * @returns A boolean indicating if the signature is valid
79
+ * @link https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol
80
+ */
81
+ this.isValidSignature = async (messageHash, signature = '0x') => {
82
+ const safeAddress = await this.getAddress();
83
+ const fallbackHandler = await this.getFallbackHandlerContract();
84
+ const signatureToCheck = signature && Array.isArray(signature) ? (0, utils_2.buildSignatureBytes)(signature) : signature;
85
+ const data = fallbackHandler.encode('isValidSignature(bytes32,bytes)', [
86
+ messageHash,
87
+ signatureToCheck
88
+ ]);
89
+ const bytesData = fallbackHandler.encode('isValidSignature(bytes,bytes)', [
90
+ messageHash,
91
+ signatureToCheck
92
+ ]);
93
+ try {
94
+ const isValidSignatureResponse = await Promise.all([
95
+ __classPrivateFieldGet(this, _Safe_ethAdapter, "f").call({
96
+ from: safeAddress,
97
+ to: safeAddress,
98
+ data: data
99
+ }),
100
+ __classPrivateFieldGet(this, _Safe_ethAdapter, "f").call({
101
+ from: safeAddress,
102
+ to: safeAddress,
103
+ data: bytesData
104
+ })
105
+ ]);
106
+ return (!!isValidSignatureResponse.length &&
107
+ (isValidSignatureResponse[0].slice(0, 10).toLowerCase() === __classPrivateFieldGet(this, _Safe_MAGIC_VALUE, "f") ||
108
+ isValidSignatureResponse[1].slice(0, 10).toLowerCase() === __classPrivateFieldGet(this, _Safe_MAGIC_VALUE_BYTES, "f")));
109
+ }
110
+ catch (error) {
111
+ return false;
112
+ }
113
+ };
41
114
  }
42
115
  /**
43
116
  * Creates an instance of the Safe Core SDK.
@@ -64,7 +137,7 @@ class Safe {
64
137
  async init(config) {
65
138
  const { ethAdapter, isL1SafeSingleton, contractNetworks } = config;
66
139
  __classPrivateFieldSet(this, _Safe_ethAdapter, ethAdapter, "f");
67
- if ((0, types_1.isSafeConfigWithPredictedSafe)(config)) {
140
+ if ((0, types_2.isSafeConfigWithPredictedSafe)(config)) {
68
141
  __classPrivateFieldSet(this, _Safe_predictedSafe, config.predictedSafe, "f");
69
142
  __classPrivateFieldSet(this, _Safe_contractManager, await contractManager_1.default.create({
70
143
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
@@ -323,7 +396,7 @@ class Safe {
323
396
  const multiSendContract = onlyCalls
324
397
  ? __classPrivateFieldGet(this, _Safe_contractManager, "f").multiSendCallOnlyContract
325
398
  : __classPrivateFieldGet(this, _Safe_contractManager, "f").multiSendContract;
326
- const multiSendData = (0, utils_4.encodeMultiSendData)(transactions.map(utils_4.standardizeMetaTransactionData));
399
+ const multiSendData = (0, utils_3.encodeMultiSendData)(transactions.map(utils_3.standardizeMetaTransactionData));
327
400
  const multiSendTransaction = {
328
401
  ...options,
329
402
  to: await multiSendContract.getAddress(),
@@ -337,7 +410,7 @@ class Safe {
337
410
  newTransaction = { ...options, ...transactions[0] };
338
411
  }
339
412
  if (__classPrivateFieldGet(this, _Safe_predictedSafe, "f")) {
340
- return new SafeTransaction_1.default(await (0, utils_4.standardizeSafeTransactionData)({
413
+ return new SafeTransaction_1.default(await (0, utils_3.standardizeSafeTransactionData)({
341
414
  predictedSafe: __classPrivateFieldGet(this, _Safe_predictedSafe, "f"),
342
415
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
343
416
  tx: newTransaction,
@@ -347,7 +420,7 @@ class Safe {
347
420
  if (!__classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract) {
348
421
  throw new Error('Safe is not deployed');
349
422
  }
350
- return new SafeTransaction_1.default(await (0, utils_4.standardizeSafeTransactionData)({
423
+ return new SafeTransaction_1.default(await (0, utils_3.standardizeSafeTransactionData)({
351
424
  safeContract: __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract,
352
425
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
353
426
  tx: newTransaction,
@@ -399,15 +472,13 @@ class Safe {
399
472
  * Returns the transaction hash of a Safe transaction.
400
473
  *
401
474
  * @param safeTransaction - The Safe transaction
402
- * @returns The transaction hash of the Safe transaction
475
+ * @returns The hash of the Safe transaction
403
476
  */
404
477
  async getTransactionHash(safeTransaction) {
405
- if (!__classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract) {
406
- throw new Error('Safe is not deployed');
407
- }
408
- const safeTransactionData = safeTransaction.data;
409
- const txHash = await __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract.getTransactionHash(safeTransactionData);
410
- return txHash;
478
+ const safeAddress = await this.getAddress();
479
+ const safeVersion = await this.getContractVersion();
480
+ const chainId = await this.getChainId();
481
+ return (0, utils_2.calculateSafeTransactionHash)(safeAddress, safeTransaction.data, safeVersion, chainId);
411
482
  }
412
483
  /**
413
484
  * Signs a hash using the current signer account.
@@ -415,34 +486,109 @@ class Safe {
415
486
  * @param hash - The hash to sign
416
487
  * @returns The Safe signature
417
488
  */
418
- async signTransactionHash(hash) {
419
- return (0, utils_3.generateSignature)(__classPrivateFieldGet(this, _Safe_ethAdapter, "f"), hash);
489
+ async signHash(hash) {
490
+ const signature = await (0, utils_2.generateSignature)(__classPrivateFieldGet(this, _Safe_ethAdapter, "f"), hash);
491
+ return signature;
492
+ }
493
+ /**
494
+ * Returns a Safe message ready to be signed by the owners.
495
+ *
496
+ * @param message - The message
497
+ * @returns The Safe message
498
+ */
499
+ createMessage(message) {
500
+ return new SafeMessage_1.default(message);
501
+ }
502
+ /**
503
+ * Returns the Safe message with a new signature
504
+ *
505
+ * @param message The message to be signed
506
+ * @param signingMethod The signature type
507
+ * @param preimageSafeAddress If the preimage is required, the address of the Safe that will be used to calculate the preimage.
508
+ * This field is mandatory for 1.4.1 contract versions Because the safe uses the old EIP-1271 interface which uses `bytes` instead of `bytes32` for the message
509
+ * we need to use the pre-image of the message to calculate the message hash
510
+ * https://github.com/safe-global/safe-contracts/blob/192c7dc67290940fcbc75165522bb86a37187069/test/core/Safe.Signatures.spec.ts#L229-L233
511
+ * @returns The signed Safe message
512
+ */
513
+ async signMessage(message, signingMethod = types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4, preimageSafeAddress) {
514
+ const owners = await this.getOwners();
515
+ const signerAddress = await __classPrivateFieldGet(this, _Safe_ethAdapter, "f").getSignerAddress();
516
+ if (!signerAddress) {
517
+ throw new Error('EthAdapter must be initialized with a signer to use this method');
518
+ }
519
+ const addressIsOwner = owners.some((owner) => signerAddress && (0, utils_2.sameString)(owner, signerAddress));
520
+ if (!addressIsOwner) {
521
+ throw new Error('Messages can only be signed by Safe owners');
522
+ }
523
+ const safeVersion = await this.getContractVersion();
524
+ if (signingMethod === types_1.SigningMethod.SAFE_SIGNATURE &&
525
+ (0, satisfies_1.default)(safeVersion, EQ_OR_GT_1_4_1) &&
526
+ !preimageSafeAddress) {
527
+ throw new Error('The parent Safe account address is mandatory for contract signatures');
528
+ }
529
+ let signature;
530
+ if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4) {
531
+ signature = await this.signTypedData(message, 'v4');
532
+ }
533
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V3) {
534
+ signature = await this.signTypedData(message, 'v3');
535
+ }
536
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA) {
537
+ signature = await this.signTypedData(message, undefined);
538
+ }
539
+ else {
540
+ const chainId = await this.getChainId();
541
+ if (!(0, utils_2.hasSafeFeature)(utils_2.SAFE_FEATURES.ETH_SIGN, safeVersion)) {
542
+ throw new Error('eth_sign is only supported by Safes >= v1.1.0');
543
+ }
544
+ let safeMessageHash;
545
+ if (signingMethod === types_1.SigningMethod.SAFE_SIGNATURE &&
546
+ preimageSafeAddress &&
547
+ (0, satisfies_1.default)(safeVersion, EQ_OR_GT_1_4_1)) {
548
+ const messageHashData = (0, utils_2.preimageSafeMessageHash)(preimageSafeAddress, (0, utils_2.hashSafeMessage)(message.data), safeVersion, chainId);
549
+ safeMessageHash = await this.getSafeMessageHash(messageHashData);
550
+ }
551
+ else {
552
+ safeMessageHash = await this.getSafeMessageHash((0, utils_2.hashSafeMessage)(message.data));
553
+ }
554
+ signature = await this.signHash(safeMessageHash);
555
+ }
556
+ const signedSafeMessage = this.createMessage(message.data);
557
+ message.signatures.forEach((signature) => {
558
+ signedSafeMessage.addSignature(signature);
559
+ });
560
+ signedSafeMessage.addSignature(signature);
561
+ return signedSafeMessage;
420
562
  }
421
563
  /**
422
564
  * Signs a transaction according to the EIP-712 using the current signer account.
423
565
  *
424
- * @param safeTransaction - The Safe transaction to be signed
566
+ * @param eip712Data - The Safe Transaction or message hash to be signed
425
567
  * @param methodVersion - EIP-712 version. Optional
426
568
  * @returns The Safe signature
427
569
  */
428
- async signTypedData(safeTransaction, methodVersion) {
429
- const safeTransactionEIP712Args = {
570
+ async signTypedData(eip712Data, methodVersion) {
571
+ const safeEIP712Args = {
430
572
  safeAddress: await this.getAddress(),
431
573
  safeVersion: await this.getContractVersion(),
432
574
  chainId: await this.getEthAdapter().getChainId(),
433
- safeTransactionData: safeTransaction.data
575
+ data: eip712Data.data
434
576
  };
435
- return (0, utils_3.generateEIP712Signature)(__classPrivateFieldGet(this, _Safe_ethAdapter, "f"), safeTransactionEIP712Args, methodVersion);
577
+ return (0, utils_2.generateEIP712Signature)(__classPrivateFieldGet(this, _Safe_ethAdapter, "f"), safeEIP712Args, methodVersion);
436
578
  }
437
579
  /**
438
580
  * Adds the signature of the current signer to the Safe transaction object.
439
581
  *
440
582
  * @param safeTransaction - The Safe transaction to be signed
441
583
  * @param signingMethod - Method followed to sign a transaction. Optional. Default value is "eth_sign"
584
+ * @param preimageSafeAddress - If the preimage is required, the address of the Safe that will be used to calculate the preimage
585
+ * This field is mandatory for 1.3.0 and 1.4.1 contract versions Because the safe uses the old EIP-1271 interface which uses `bytes` instead of `bytes32` for the message
586
+ * we need to use the pre-image of the message to calculate the message hash
587
+ * https://github.com/safe-global/safe-contracts/blob/192c7dc67290940fcbc75165522bb86a37187069/test/core/Safe.Signatures.spec.ts#L229-L233
442
588
  * @returns The signed Safe transaction
443
589
  * @throws "Transactions can only be signed by Safe owners"
444
590
  */
445
- async signTransaction(safeTransaction, signingMethod = 'eth_signTypedData_v4') {
591
+ async signTransaction(safeTransaction, signingMethod = types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4, preimageSafeAddress) {
446
592
  const transaction = (0, utils_2.isSafeMultisigTransactionResponse)(safeTransaction)
447
593
  ? await this.toSafeTransactionType(safeTransaction)
448
594
  : safeTransaction;
@@ -455,23 +601,42 @@ class Safe {
455
601
  if (!addressIsOwner) {
456
602
  throw new Error('Transactions can only be signed by Safe owners');
457
603
  }
604
+ const safeVersion = await this.getContractVersion();
605
+ if (signingMethod === types_1.SigningMethod.SAFE_SIGNATURE &&
606
+ (0, satisfies_1.default)(safeVersion, EQ_OR_GT_1_3_0) &&
607
+ !preimageSafeAddress) {
608
+ throw new Error('The parent Safe account address is mandatory for contract signatures');
609
+ }
458
610
  let signature;
459
- if (signingMethod === 'eth_signTypedData_v4') {
611
+ if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4) {
460
612
  signature = await this.signTypedData(transaction, 'v4');
461
613
  }
462
- else if (signingMethod === 'eth_signTypedData_v3') {
614
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V3) {
463
615
  signature = await this.signTypedData(transaction, 'v3');
464
616
  }
465
- else if (signingMethod === 'eth_signTypedData') {
466
- signature = await this.signTypedData(transaction);
617
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA) {
618
+ signature = await this.signTypedData(transaction, undefined);
467
619
  }
468
620
  else {
469
621
  const safeVersion = await this.getContractVersion();
622
+ const chainId = await this.getChainId();
470
623
  if (!(0, utils_2.hasSafeFeature)(utils_2.SAFE_FEATURES.ETH_SIGN, safeVersion)) {
471
624
  throw new Error('eth_sign is only supported by Safes >= v1.1.0');
472
625
  }
473
- const txHash = await this.getTransactionHash(transaction);
474
- signature = await this.signTransactionHash(txHash);
626
+ let txHash;
627
+ // IMPORTANT: because the safe uses the old EIP-1271 interface which uses `bytes` instead of `bytes32` for the message
628
+ // we need to use the pre-image of the transaction hash to calculate the message hash
629
+ // https://github.com/safe-global/safe-contracts/blob/192c7dc67290940fcbc75165522bb86a37187069/test/core/Safe.Signatures.spec.ts#L229-L233
630
+ if (signingMethod === types_1.SigningMethod.SAFE_SIGNATURE &&
631
+ (0, satisfies_1.default)(safeVersion, EQ_OR_GT_1_3_0) &&
632
+ preimageSafeAddress) {
633
+ const txHashData = (0, utils_2.preimageSafeTransactionHash)(preimageSafeAddress, safeTransaction.data, safeVersion, chainId);
634
+ txHash = await this.getSafeMessageHash(txHashData);
635
+ }
636
+ else {
637
+ txHash = await this.getTransactionHash(transaction);
638
+ }
639
+ signature = await this.signHash(txHash);
475
640
  }
476
641
  const signedSafeTransaction = await this.copyTransaction(transaction);
477
642
  signedSafeTransaction.addSignature(signature);
@@ -792,7 +957,7 @@ class Safe {
792
957
  const txHash = await this.getTransactionHash(signedSafeTransaction);
793
958
  const ownersWhoApprovedTx = await this.getOwnersWhoApprovedTx(txHash);
794
959
  for (const owner of ownersWhoApprovedTx) {
795
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(owner));
960
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(owner));
796
961
  }
797
962
  const owners = await this.getOwners();
798
963
  const signerAddress = await __classPrivateFieldGet(this, _Safe_ethAdapter, "f").getSignerAddress();
@@ -800,7 +965,7 @@ class Safe {
800
965
  throw new Error('EthAdapter must be initialized with a signer to use this method');
801
966
  }
802
967
  if (owners.includes(signerAddress)) {
803
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(signerAddress));
968
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(signerAddress));
804
969
  }
805
970
  const isTxValid = await __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract.isValidTransaction(signedSafeTransaction, {
806
971
  from: signerAddress,
@@ -829,7 +994,7 @@ class Safe {
829
994
  const txHash = await this.getTransactionHash(signedSafeTransaction);
830
995
  const ownersWhoApprovedTx = await this.getOwnersWhoApprovedTx(txHash);
831
996
  for (const owner of ownersWhoApprovedTx) {
832
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(owner));
997
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(owner));
833
998
  }
834
999
  const owners = await this.getOwners();
835
1000
  const threshold = await this.getThreshold();
@@ -837,7 +1002,7 @@ class Safe {
837
1002
  if (threshold > signedSafeTransaction.signatures.size &&
838
1003
  signerAddress &&
839
1004
  owners.includes(signerAddress)) {
840
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(signerAddress));
1005
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(signerAddress));
841
1006
  }
842
1007
  if (threshold > signedSafeTransaction.signatures.size) {
843
1008
  const signaturesMissing = threshold - signedSafeTransaction.signatures.size;
@@ -1013,7 +1178,7 @@ class Safe {
1013
1178
  });
1014
1179
  // multiSend method with the transactions encoded
1015
1180
  const batchData = multiSendCallOnlyContract.encode('multiSend', [
1016
- (0, utils_4.encodeMultiSendData)(transactions) // encoded transactions
1181
+ (0, utils_3.encodeMultiSendData)(transactions) // encoded transactions
1017
1182
  ]);
1018
1183
  const transactionBatch = {
1019
1184
  ...transactionOptions, // optional transaction options like from, gasLimit, gasPrice...
@@ -1023,7 +1188,25 @@ class Safe {
1023
1188
  };
1024
1189
  return transactionBatch;
1025
1190
  }
1191
+ /**
1192
+ * Get the fallback handler contract
1193
+ *
1194
+ * @returns The fallback Handler contract
1195
+ */
1196
+ async getFallbackHandlerContract() {
1197
+ if (!__classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract) {
1198
+ throw new Error('Safe is not deployed');
1199
+ }
1200
+ const safeVersion = (await __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract.getVersion()) ?? config_1.DEFAULT_SAFE_VERSION;
1201
+ const chainId = await __classPrivateFieldGet(this, _Safe_ethAdapter, "f").getChainId();
1202
+ const compatibilityFallbackHandlerContract = await (0, safeDeploymentContracts_1.getCompatibilityFallbackHandlerContract)({
1203
+ ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
1204
+ safeVersion,
1205
+ customContracts: __classPrivateFieldGet(this, _Safe_contractManager, "f").contractNetworks?.[chainId.toString()]
1206
+ });
1207
+ return compatibilityFallbackHandlerContract;
1208
+ }
1026
1209
  }
1027
- _Safe_predictedSafe = new WeakMap(), _Safe_ethAdapter = new WeakMap(), _Safe_contractManager = new WeakMap(), _Safe_ownerManager = new WeakMap(), _Safe_moduleManager = new WeakMap(), _Safe_guardManager = new WeakMap(), _Safe_fallbackHandlerManager = new WeakMap();
1210
+ _Safe_predictedSafe = new WeakMap(), _Safe_ethAdapter = new WeakMap(), _Safe_contractManager = new WeakMap(), _Safe_ownerManager = new WeakMap(), _Safe_moduleManager = new WeakMap(), _Safe_guardManager = new WeakMap(), _Safe_fallbackHandlerManager = new WeakMap(), _Safe_MAGIC_VALUE = new WeakMap(), _Safe_MAGIC_VALUE_BYTES = new WeakMap();
1028
1211
  exports.default = Safe;
1029
1212
  //# sourceMappingURL=Safe.js.map