@safe-global/protocol-kit 2.0.0 → 3.0.0-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 (73) hide show
  1. package/README.md +7 -4
  2. package/dist/src/Safe.d.ts +57 -7
  3. package/dist/src/Safe.js +222 -38
  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/ethers/contracts/CreateCall/CreateCallEthersContract.js.map +1 -1
  9. package/dist/src/adapters/ethers/contracts/Safe/SafeContractEthers.js.map +1 -1
  10. package/dist/src/adapters/ethers/contracts/Safe/v1.0.0/SafeContract_V1_0_0_Ethers.js.map +1 -1
  11. package/dist/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Ethers.js.map +1 -1
  12. package/dist/src/adapters/ethers/contracts/Safe/v1.2.0/SafeContract_V1_2_0_Ethers.js.map +1 -1
  13. package/dist/src/adapters/ethers/contracts/Safe/v1.3.0/SafeContract_V1_3_0_Ethers.js.map +1 -1
  14. package/dist/src/adapters/ethers/contracts/Safe/v1.4.1/SafeContract_V1_4_1_Ethers.js.map +1 -1
  15. package/dist/src/adapters/ethers/contracts/SafeProxyFactory/SafeProxyFactoryEthersContract.js.map +1 -1
  16. package/dist/src/adapters/ethers/contracts/SignMessageLib/SignMessageLibEthersContract.js.map +1 -1
  17. package/dist/src/adapters/ethers/contracts/contractInstancesEthers.js.map +1 -1
  18. package/dist/src/adapters/web3/Web3Adapter.d.ts +2 -2
  19. package/dist/src/adapters/web3/Web3Adapter.js +6 -5
  20. package/dist/src/adapters/web3/Web3Adapter.js.map +1 -1
  21. package/dist/src/adapters/web3/contracts/CreateCall/CreateCallWeb3Contract.js.map +1 -1
  22. package/dist/src/adapters/web3/contracts/Safe/SafeContractWeb3.js.map +1 -1
  23. package/dist/src/adapters/web3/contracts/Safe/v1.0.0/SafeContract_V1_0_0_Web3.js.map +1 -1
  24. package/dist/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Web3.js.map +1 -1
  25. package/dist/src/adapters/web3/contracts/Safe/v1.2.0/SafeContract_V1_2_0_Web3.js.map +1 -1
  26. package/dist/src/adapters/web3/contracts/Safe/v1.3.0/SafeContract_V1_3_0_Web3.js.map +1 -1
  27. package/dist/src/adapters/web3/contracts/Safe/v1.4.1/SafeContract_V1_4_1_Web3.js.map +1 -1
  28. package/dist/src/adapters/web3/contracts/SafeProxyFactory/SafeProxyFactoryWeb3Contract.js.map +1 -1
  29. package/dist/src/adapters/web3/contracts/SignMessageLib/SignMessageLibWeb3Contract.js.map +1 -1
  30. package/dist/src/adapters/web3/contracts/contractInstancesWeb3.js.map +1 -1
  31. package/dist/src/contracts/safeDeploymentContracts.d.ts +2 -3
  32. package/dist/src/contracts/safeDeploymentContracts.js.map +1 -1
  33. package/dist/src/contracts/utils.d.ts +2 -1
  34. package/dist/src/contracts/utils.js +12 -9
  35. package/dist/src/contracts/utils.js.map +1 -1
  36. package/dist/src/index.d.ts +5 -3
  37. package/dist/src/index.js +17 -1
  38. package/dist/src/index.js.map +1 -1
  39. package/dist/src/managers/contractManager.js.map +1 -1
  40. package/dist/src/managers/fallbackHandlerManager.js.map +1 -1
  41. package/dist/src/managers/guardManager.js.map +1 -1
  42. package/dist/src/managers/moduleManager.js.map +1 -1
  43. package/dist/src/managers/ownerManager.js.map +1 -1
  44. package/dist/src/safeFactory/index.js +1 -0
  45. package/dist/src/safeFactory/index.js.map +1 -1
  46. package/dist/src/types/index.d.ts +8 -0
  47. package/dist/src/types/index.js +9 -0
  48. package/dist/src/types/index.js.map +1 -1
  49. package/dist/src/utils/eip-3770/config.js +21 -1
  50. package/dist/src/utils/eip-3770/config.js.map +1 -1
  51. package/dist/src/utils/eip-3770/index.js.map +1 -1
  52. package/dist/src/utils/eip-712/index.d.ts +6 -9
  53. package/dist/src/utils/eip-712/index.js +57 -18
  54. package/dist/src/utils/eip-712/index.js.map +1 -1
  55. package/dist/src/utils/erc-20/index.js.map +1 -1
  56. package/dist/src/utils/messages/SafeMessage.d.ts +10 -0
  57. package/dist/src/utils/messages/SafeMessage.js +20 -0
  58. package/dist/src/utils/messages/SafeMessage.js.map +1 -0
  59. package/dist/src/utils/safeVersions.js +1 -1
  60. package/dist/src/utils/safeVersions.js.map +1 -1
  61. package/dist/src/utils/signatures/SafeSignature.d.ts +3 -2
  62. package/dist/src/utils/signatures/SafeSignature.js +10 -2
  63. package/dist/src/utils/signatures/SafeSignature.js.map +1 -1
  64. package/dist/src/utils/signatures/utils.d.ts +11 -4
  65. package/dist/src/utils/signatures/utils.js +75 -7
  66. package/dist/src/utils/signatures/utils.js.map +1 -1
  67. package/dist/src/utils/transactions/SafeTransaction.d.ts +1 -0
  68. package/dist/src/utils/transactions/SafeTransaction.js +5 -10
  69. package/dist/src/utils/transactions/SafeTransaction.js.map +1 -1
  70. package/dist/src/utils/transactions/gas.js.map +1 -1
  71. package/dist/src/utils/transactions/utils.js.map +1 -1
  72. package/dist/tsconfig.build.tsbuildinfo +1 -1
  73. package/package.json +11 -13
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"),
@@ -142,6 +215,7 @@ class Safe {
142
215
  const chainId = await __classPrivateFieldGet(this, _Safe_ethAdapter, "f").getChainId();
143
216
  return (0, utils_1.predictSafeAddress)({
144
217
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
218
+ chainId,
145
219
  customContracts: __classPrivateFieldGet(this, _Safe_contractManager, "f").contractNetworks?.[chainId.toString()],
146
220
  ...__classPrivateFieldGet(this, _Safe_predictedSafe, "f")
147
221
  });
@@ -322,7 +396,7 @@ class Safe {
322
396
  const multiSendContract = onlyCalls
323
397
  ? __classPrivateFieldGet(this, _Safe_contractManager, "f").multiSendCallOnlyContract
324
398
  : __classPrivateFieldGet(this, _Safe_contractManager, "f").multiSendContract;
325
- const multiSendData = (0, utils_4.encodeMultiSendData)(transactions.map(utils_4.standardizeMetaTransactionData));
399
+ const multiSendData = (0, utils_3.encodeMultiSendData)(transactions.map(utils_3.standardizeMetaTransactionData));
326
400
  const multiSendTransaction = {
327
401
  ...options,
328
402
  to: await multiSendContract.getAddress(),
@@ -336,7 +410,7 @@ class Safe {
336
410
  newTransaction = { ...options, ...transactions[0] };
337
411
  }
338
412
  if (__classPrivateFieldGet(this, _Safe_predictedSafe, "f")) {
339
- return new SafeTransaction_1.default(await (0, utils_4.standardizeSafeTransactionData)({
413
+ return new SafeTransaction_1.default(await (0, utils_3.standardizeSafeTransactionData)({
340
414
  predictedSafe: __classPrivateFieldGet(this, _Safe_predictedSafe, "f"),
341
415
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
342
416
  tx: newTransaction,
@@ -346,7 +420,7 @@ class Safe {
346
420
  if (!__classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract) {
347
421
  throw new Error('Safe is not deployed');
348
422
  }
349
- return new SafeTransaction_1.default(await (0, utils_4.standardizeSafeTransactionData)({
423
+ return new SafeTransaction_1.default(await (0, utils_3.standardizeSafeTransactionData)({
350
424
  safeContract: __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract,
351
425
  ethAdapter: __classPrivateFieldGet(this, _Safe_ethAdapter, "f"),
352
426
  tx: newTransaction,
@@ -398,15 +472,13 @@ class Safe {
398
472
  * Returns the transaction hash of a Safe transaction.
399
473
  *
400
474
  * @param safeTransaction - The Safe transaction
401
- * @returns The transaction hash of the Safe transaction
475
+ * @returns The hash of the Safe transaction
402
476
  */
403
477
  async getTransactionHash(safeTransaction) {
404
- if (!__classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract) {
405
- throw new Error('Safe is not deployed');
406
- }
407
- const safeTransactionData = safeTransaction.data;
408
- const txHash = await __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract.getTransactionHash(safeTransactionData);
409
- 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);
410
482
  }
411
483
  /**
412
484
  * Signs a hash using the current signer account.
@@ -414,34 +486,109 @@ class Safe {
414
486
  * @param hash - The hash to sign
415
487
  * @returns The Safe signature
416
488
  */
417
- async signTransactionHash(hash) {
418
- 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;
419
562
  }
420
563
  /**
421
564
  * Signs a transaction according to the EIP-712 using the current signer account.
422
565
  *
423
- * @param safeTransaction - The Safe transaction to be signed
566
+ * @param eip712Data - The Safe Transaction or message hash to be signed
424
567
  * @param methodVersion - EIP-712 version. Optional
425
568
  * @returns The Safe signature
426
569
  */
427
- async signTypedData(safeTransaction, methodVersion) {
428
- const safeTransactionEIP712Args = {
570
+ async signTypedData(eip712Data, methodVersion) {
571
+ const safeEIP712Args = {
429
572
  safeAddress: await this.getAddress(),
430
573
  safeVersion: await this.getContractVersion(),
431
574
  chainId: await this.getEthAdapter().getChainId(),
432
- safeTransactionData: safeTransaction.data
575
+ data: eip712Data.data
433
576
  };
434
- 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);
435
578
  }
436
579
  /**
437
580
  * Adds the signature of the current signer to the Safe transaction object.
438
581
  *
439
582
  * @param safeTransaction - The Safe transaction to be signed
440
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
441
588
  * @returns The signed Safe transaction
442
589
  * @throws "Transactions can only be signed by Safe owners"
443
590
  */
444
- async signTransaction(safeTransaction, signingMethod = 'eth_signTypedData_v4') {
591
+ async signTransaction(safeTransaction, signingMethod = types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4, preimageSafeAddress) {
445
592
  const transaction = (0, utils_2.isSafeMultisigTransactionResponse)(safeTransaction)
446
593
  ? await this.toSafeTransactionType(safeTransaction)
447
594
  : safeTransaction;
@@ -454,23 +601,42 @@ class Safe {
454
601
  if (!addressIsOwner) {
455
602
  throw new Error('Transactions can only be signed by Safe owners');
456
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
+ }
457
610
  let signature;
458
- if (signingMethod === 'eth_signTypedData_v4') {
611
+ if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V4) {
459
612
  signature = await this.signTypedData(transaction, 'v4');
460
613
  }
461
- else if (signingMethod === 'eth_signTypedData_v3') {
614
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA_V3) {
462
615
  signature = await this.signTypedData(transaction, 'v3');
463
616
  }
464
- else if (signingMethod === 'eth_signTypedData') {
465
- signature = await this.signTypedData(transaction);
617
+ else if (signingMethod === types_1.SigningMethod.ETH_SIGN_TYPED_DATA) {
618
+ signature = await this.signTypedData(transaction, undefined);
466
619
  }
467
620
  else {
468
621
  const safeVersion = await this.getContractVersion();
622
+ const chainId = await this.getChainId();
469
623
  if (!(0, utils_2.hasSafeFeature)(utils_2.SAFE_FEATURES.ETH_SIGN, safeVersion)) {
470
624
  throw new Error('eth_sign is only supported by Safes >= v1.1.0');
471
625
  }
472
- const txHash = await this.getTransactionHash(transaction);
473
- 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);
474
640
  }
475
641
  const signedSafeTransaction = await this.copyTransaction(transaction);
476
642
  signedSafeTransaction.addSignature(signature);
@@ -791,7 +957,7 @@ class Safe {
791
957
  const txHash = await this.getTransactionHash(signedSafeTransaction);
792
958
  const ownersWhoApprovedTx = await this.getOwnersWhoApprovedTx(txHash);
793
959
  for (const owner of ownersWhoApprovedTx) {
794
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(owner));
960
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(owner));
795
961
  }
796
962
  const owners = await this.getOwners();
797
963
  const signerAddress = await __classPrivateFieldGet(this, _Safe_ethAdapter, "f").getSignerAddress();
@@ -799,7 +965,7 @@ class Safe {
799
965
  throw new Error('EthAdapter must be initialized with a signer to use this method');
800
966
  }
801
967
  if (owners.includes(signerAddress)) {
802
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(signerAddress));
968
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(signerAddress));
803
969
  }
804
970
  const isTxValid = await __classPrivateFieldGet(this, _Safe_contractManager, "f").safeContract.isValidTransaction(signedSafeTransaction, {
805
971
  from: signerAddress,
@@ -828,7 +994,7 @@ class Safe {
828
994
  const txHash = await this.getTransactionHash(signedSafeTransaction);
829
995
  const ownersWhoApprovedTx = await this.getOwnersWhoApprovedTx(txHash);
830
996
  for (const owner of ownersWhoApprovedTx) {
831
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(owner));
997
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(owner));
832
998
  }
833
999
  const owners = await this.getOwners();
834
1000
  const threshold = await this.getThreshold();
@@ -836,7 +1002,7 @@ class Safe {
836
1002
  if (threshold > signedSafeTransaction.signatures.size &&
837
1003
  signerAddress &&
838
1004
  owners.includes(signerAddress)) {
839
- signedSafeTransaction.addSignature((0, utils_3.generatePreValidatedSignature)(signerAddress));
1005
+ signedSafeTransaction.addSignature((0, utils_2.generatePreValidatedSignature)(signerAddress));
840
1006
  }
841
1007
  if (threshold > signedSafeTransaction.signatures.size) {
842
1008
  const signaturesMissing = threshold - signedSafeTransaction.signatures.size;
@@ -979,13 +1145,13 @@ class Safe {
979
1145
  safeDeploymentConfig?.saltNonce ||
980
1146
  (0, utils_1.getChainSpecificDefaultSaltNonce)(chainId);
981
1147
  const safeDeployTransactionData = {
982
- ...transactionOptions,
1148
+ ...transactionOptions, // optional transaction options like from, gasLimit, gasPrice...
983
1149
  to: await safeProxyFactoryContract.getAddress(),
984
1150
  value: '0',
985
1151
  // we use the createProxyWithNonce method to create the Safe in a deterministic address, see: https://github.com/safe-global/safe-contracts/blob/main/contracts/proxies/SafeProxyFactory.sol#L52
986
1152
  data: safeProxyFactoryContract.encode('createProxyWithNonce', [
987
1153
  await safeSingletonContract.getAddress(),
988
- initializer,
1154
+ initializer, // call to the setup method to set the threshold & owners of the new Safe
989
1155
  saltNonce
990
1156
  ])
991
1157
  };
@@ -1012,17 +1178,35 @@ class Safe {
1012
1178
  });
1013
1179
  // multiSend method with the transactions encoded
1014
1180
  const batchData = multiSendCallOnlyContract.encode('multiSend', [
1015
- (0, utils_4.encodeMultiSendData)(transactions) // encoded transactions
1181
+ (0, utils_3.encodeMultiSendData)(transactions) // encoded transactions
1016
1182
  ]);
1017
1183
  const transactionBatch = {
1018
- ...transactionOptions,
1184
+ ...transactionOptions, // optional transaction options like from, gasLimit, gasPrice...
1019
1185
  to: await multiSendCallOnlyContract.getAddress(),
1020
1186
  value: '0',
1021
1187
  data: batchData
1022
1188
  };
1023
1189
  return transactionBatch;
1024
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
+ }
1025
1209
  }
1026
- _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();
1027
1211
  exports.default = Safe;
1028
1212
  //# sourceMappingURL=Safe.js.map