@safe-global/sdk-starter-kit 1.1.4 → 2.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.
- package/dist/cjs/index.cjs +906 -0
- package/dist/esm/index.mjs +875 -0
- package/dist/src/BaseClient.d.ts +1 -0
- package/dist/src/BaseClient.d.ts.map +1 -0
- package/dist/src/SafeClient.d.ts +1 -0
- package/dist/src/SafeClient.d.ts.map +1 -0
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/extensions/index.d.ts +1 -0
- package/dist/src/extensions/index.d.ts.map +1 -0
- package/dist/src/extensions/messages/SafeMessageClient.d.ts +1 -0
- package/dist/src/extensions/messages/SafeMessageClient.d.ts.map +1 -0
- package/dist/src/extensions/messages/offChainMessages.d.ts +1 -0
- package/dist/src/extensions/messages/offChainMessages.d.ts.map +1 -0
- package/dist/src/extensions/messages/onChainMessages.d.ts +1 -0
- package/dist/src/extensions/messages/onChainMessages.d.ts.map +1 -0
- package/dist/src/extensions/safe-operations/SafeOperationClient.d.ts +1 -0
- package/dist/src/extensions/safe-operations/SafeOperationClient.d.ts.map +1 -0
- package/dist/src/extensions/safe-operations/safeOperations.d.ts +1 -0
- package/dist/src/extensions/safe-operations/safeOperations.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/types.d.ts +1 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/index.d.ts +7 -6
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/proposeTransaction.d.ts +1 -0
- package/dist/src/utils/proposeTransaction.d.ts.map +1 -0
- package/dist/src/utils/sendTransaction.d.ts +1 -0
- package/dist/src/utils/sendTransaction.d.ts.map +1 -0
- package/package.json +17 -8
- package/dist/src/BaseClient.js +0 -123
- package/dist/src/BaseClient.js.map +0 -1
- package/dist/src/SafeClient.js +0 -215
- package/dist/src/SafeClient.js.map +0 -1
- package/dist/src/constants.js +0 -37
- package/dist/src/constants.js.map +0 -1
- package/dist/src/extensions/index.js +0 -20
- package/dist/src/extensions/index.js.map +0 -1
- package/dist/src/extensions/messages/SafeMessageClient.js +0 -161
- package/dist/src/extensions/messages/SafeMessageClient.js.map +0 -1
- package/dist/src/extensions/messages/offChainMessages.js +0 -52
- package/dist/src/extensions/messages/offChainMessages.js.map +0 -1
- package/dist/src/extensions/messages/onChainMessages.js +0 -48
- package/dist/src/extensions/messages/onChainMessages.js.map +0 -1
- package/dist/src/extensions/safe-operations/SafeOperationClient.js +0 -127
- package/dist/src/extensions/safe-operations/SafeOperationClient.js.map +0 -1
- package/dist/src/extensions/safe-operations/safeOperations.js +0 -85
- package/dist/src/extensions/safe-operations/safeOperations.js.map +0 -1
- package/dist/src/index.js +0 -112
- package/dist/src/index.js.map +0 -1
- package/dist/src/types.js +0 -3
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils/index.js +0 -57
- package/dist/src/utils/index.js.map +0 -1
- package/dist/src/utils/proposeTransaction.js +0 -29
- package/dist/src/utils/proposeTransaction.js.map +0 -1
- package/dist/src/utils/sendTransaction.js +0 -28
- package/dist/src/utils/sendTransaction.js.map +0 -1
- package/dist/tsconfig.build.tsbuildinfo +0 -1
|
@@ -0,0 +1,906 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
SafeClient: () => SafeClient,
|
|
34
|
+
createSafeClient: () => createSafeClient,
|
|
35
|
+
offChainMessages: () => offChainMessages,
|
|
36
|
+
onChainMessages: () => onChainMessages,
|
|
37
|
+
safeOperations: () => safeOperations
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(src_exports);
|
|
40
|
+
var import_protocol_kit6 = __toESM(require("@safe-global/protocol-kit"));
|
|
41
|
+
var import_api_kit = __toESM(require("@safe-global/api-kit"));
|
|
42
|
+
|
|
43
|
+
// src/utils/index.ts
|
|
44
|
+
var import_protocol_kit2 = require("@safe-global/protocol-kit");
|
|
45
|
+
|
|
46
|
+
// src/constants.ts
|
|
47
|
+
var DEFAULT_DEPLOYMENT_TYPE = "canonical";
|
|
48
|
+
var TRANSACTION_EXECUTED = "The transaction has been executed, check the ethereumTxHash in the transactions property to view it on the corresponding blockchain explorer";
|
|
49
|
+
var TRANSACTION_SAVED = "The transaction was not executed on-chain yet. There are pending signatures and you need to confirm it with other Safe owners first. Use the confirm(safeTxHash) method with other signer connected to the client";
|
|
50
|
+
var OFFCHAIN_MESSAGE_SAVED = "The message was stored using the Safe Transaction Service, you need to confirm it with other Safe owners in order to make it valid. Use the confirmMessage(messageHash) method with other signer connected to the client";
|
|
51
|
+
var OFFCHAIN_MESSAGE_CONFIRMED = "The message was stored using Safe services and now is confirmed and valid";
|
|
52
|
+
var SAFE_OPERATION_SAVED = "The UserOperation was stored using the Safe Transaction Service as an SafeOperation, you need to confirm it with other Safe owners in order to make it valid. Use the confirmSafeOperation(safeOperationHash) method with other signer connected to the client";
|
|
53
|
+
var SAFE_OPERATION_SENT_TO_BUNDLER = "The SafeOperation was sent to the bundler for being processed. Check the userOperationHash in the safeOperations property to see the SafeOperation in the corresponding explorer";
|
|
54
|
+
var SAFE_DEPLOYED = "A new Safe account was deployed, check the ethereumTxHash in the safeAccountDeployment property to view it on the corresponding blockchain explorer";
|
|
55
|
+
var MESSAGES = {
|
|
56
|
+
["DEPLOYED_AND_EXECUTED" /* DEPLOYED_AND_EXECUTED */]: `${SAFE_DEPLOYED}. ${TRANSACTION_EXECUTED}`,
|
|
57
|
+
["DEPLOYED_AND_PENDING_SIGNATURES" /* DEPLOYED_AND_PENDING_SIGNATURES */]: `${SAFE_DEPLOYED}. ${TRANSACTION_SAVED}`,
|
|
58
|
+
["EXECUTED" /* EXECUTED */]: TRANSACTION_EXECUTED,
|
|
59
|
+
["PENDING_SIGNATURES" /* PENDING_SIGNATURES */]: TRANSACTION_SAVED,
|
|
60
|
+
["MESSAGE_PENDING_SIGNATURES" /* MESSAGE_PENDING_SIGNATURES */]: OFFCHAIN_MESSAGE_SAVED,
|
|
61
|
+
["MESSAGE_CONFIRMED" /* MESSAGE_CONFIRMED */]: OFFCHAIN_MESSAGE_CONFIRMED,
|
|
62
|
+
["DEPLOYED_AND_MESSAGE_PENDING_SIGNATURES" /* DEPLOYED_AND_MESSAGE_PENDING_SIGNATURES */]: `${SAFE_DEPLOYED}. ${OFFCHAIN_MESSAGE_SAVED}`,
|
|
63
|
+
["DEPLOYED_AND_MESSAGE_CONFIRMED" /* DEPLOYED_AND_MESSAGE_CONFIRMED */]: `${SAFE_DEPLOYED}. ${OFFCHAIN_MESSAGE_CONFIRMED}`,
|
|
64
|
+
["SAFE_OPERATION_EXECUTED" /* SAFE_OPERATION_EXECUTED */]: SAFE_OPERATION_SENT_TO_BUNDLER,
|
|
65
|
+
["SAFE_OPERATION_PENDING_SIGNATURES" /* SAFE_OPERATION_PENDING_SIGNATURES */]: SAFE_OPERATION_SAVED
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/utils/sendTransaction.ts
|
|
69
|
+
var import_actions = require("viem/actions");
|
|
70
|
+
var sendTransaction = async ({
|
|
71
|
+
transaction,
|
|
72
|
+
protocolKit
|
|
73
|
+
}) => {
|
|
74
|
+
const signer = await protocolKit.getSafeProvider().getExternalSigner();
|
|
75
|
+
const client = protocolKit.getSafeProvider().getExternalProvider();
|
|
76
|
+
if (!signer)
|
|
77
|
+
throw new Error("SafeProvider must be initialized with a signer to use this function");
|
|
78
|
+
const hash = await signer.sendTransaction({
|
|
79
|
+
to: transaction.to,
|
|
80
|
+
data: transaction.data,
|
|
81
|
+
value: BigInt(transaction.value),
|
|
82
|
+
account: signer.account
|
|
83
|
+
});
|
|
84
|
+
const receipt = await (0, import_actions.waitForTransactionReceipt)(client, { hash });
|
|
85
|
+
return receipt.transactionHash;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/utils/proposeTransaction.ts
|
|
89
|
+
var import_protocol_kit = require("@safe-global/protocol-kit");
|
|
90
|
+
var proposeTransaction = async ({
|
|
91
|
+
safeTransaction,
|
|
92
|
+
protocolKit,
|
|
93
|
+
apiKit
|
|
94
|
+
}) => {
|
|
95
|
+
safeTransaction = await protocolKit.signTransaction(safeTransaction);
|
|
96
|
+
const signerAddress = await protocolKit.getSafeProvider().getSignerAddress() || "0x";
|
|
97
|
+
const ethSig = safeTransaction.getSignature(signerAddress);
|
|
98
|
+
const safeTxHash = await protocolKit.getTransactionHash(safeTransaction);
|
|
99
|
+
const txOptions = {
|
|
100
|
+
safeAddress: await protocolKit.getAddress(),
|
|
101
|
+
safeTransactionData: safeTransaction.data,
|
|
102
|
+
safeTxHash,
|
|
103
|
+
senderAddress: signerAddress,
|
|
104
|
+
senderSignature: (0, import_protocol_kit.buildSignatureBytes)([ethSig])
|
|
105
|
+
};
|
|
106
|
+
await apiKit.proposeTransaction(txOptions);
|
|
107
|
+
return safeTxHash;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/utils/index.ts
|
|
111
|
+
var isValidAddress = (address) => {
|
|
112
|
+
try {
|
|
113
|
+
(0, import_protocol_kit2.validateEthereumAddress)(address);
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var isValidSafeConfig = (config) => {
|
|
120
|
+
if (!config.owners || !config.threshold) return false;
|
|
121
|
+
return true;
|
|
122
|
+
};
|
|
123
|
+
var waitSafeTxReceipt = async (txResult) => {
|
|
124
|
+
const receipt = txResult.transactionResponse ? await txResult.transactionResponse.wait() : void 0;
|
|
125
|
+
return receipt;
|
|
126
|
+
};
|
|
127
|
+
var createSafeClientResult = ({
|
|
128
|
+
status,
|
|
129
|
+
safeAddress,
|
|
130
|
+
deploymentTxHash,
|
|
131
|
+
safeTxHash,
|
|
132
|
+
txHash,
|
|
133
|
+
messageHash,
|
|
134
|
+
userOperationHash,
|
|
135
|
+
safeOperationHash
|
|
136
|
+
}) => {
|
|
137
|
+
return {
|
|
138
|
+
safeAddress,
|
|
139
|
+
description: MESSAGES[status],
|
|
140
|
+
status,
|
|
141
|
+
transactions: txHash || safeTxHash ? { ethereumTxHash: txHash, safeTxHash } : void 0,
|
|
142
|
+
messages: messageHash ? { messageHash } : void 0,
|
|
143
|
+
safeOperations: userOperationHash || safeOperationHash ? { userOperationHash, safeOperationHash } : void 0,
|
|
144
|
+
safeAccountDeployment: deploymentTxHash ? { ethereumTxHash: deploymentTxHash } : void 0
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/BaseClient.ts
|
|
149
|
+
var BaseClient = class {
|
|
150
|
+
constructor(protocolKit, apiKit) {
|
|
151
|
+
this.protocolKit = protocolKit;
|
|
152
|
+
this.apiKit = apiKit;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Returns the Safe address.
|
|
156
|
+
*
|
|
157
|
+
* @returns {string} The Safe address
|
|
158
|
+
*/
|
|
159
|
+
async getAddress() {
|
|
160
|
+
return this.protocolKit.getAddress();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Checks if the current Safe is deployed.
|
|
164
|
+
*
|
|
165
|
+
* @returns {boolean} if the Safe contract is deployed
|
|
166
|
+
*/
|
|
167
|
+
async isDeployed() {
|
|
168
|
+
return this.protocolKit.isSafeDeployed();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Checks if a specific address is an owner of the current Safe.
|
|
172
|
+
*
|
|
173
|
+
* @param {string} ownerAddress - The account address
|
|
174
|
+
* @returns {boolean} TRUE if the account is an owner
|
|
175
|
+
*/
|
|
176
|
+
async isOwner(ownerAddress) {
|
|
177
|
+
return this.protocolKit.isOwner(ownerAddress);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns the list of Safe owner accounts.
|
|
181
|
+
*
|
|
182
|
+
* @returns The list of owners
|
|
183
|
+
*/
|
|
184
|
+
async getOwners() {
|
|
185
|
+
return this.protocolKit.getOwners();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Returns the Safe threshold.
|
|
189
|
+
*
|
|
190
|
+
* @returns {number} The Safe threshold
|
|
191
|
+
*/
|
|
192
|
+
async getThreshold() {
|
|
193
|
+
return this.protocolKit.getThreshold();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Returns the Safe nonce.
|
|
197
|
+
*
|
|
198
|
+
* @returns {number} The Safe nonce
|
|
199
|
+
*/
|
|
200
|
+
async getNonce() {
|
|
201
|
+
return this.protocolKit.getNonce();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns a list of owners who have approved a specific Safe transaction.
|
|
205
|
+
*
|
|
206
|
+
* @param {string} txHash - The Safe transaction hash
|
|
207
|
+
* @returns {string[]} The list of owners
|
|
208
|
+
*/
|
|
209
|
+
async getOwnersWhoApprovedTransaction(txHash) {
|
|
210
|
+
return this.protocolKit.getOwnersWhoApprovedTx(txHash);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Encodes the data for adding a new owner to the Safe.
|
|
214
|
+
*
|
|
215
|
+
* @param {AddOwnerTxParams | AddPasskeyOwnerTxParams} addOwnerParams - The parameters for adding a new owner
|
|
216
|
+
* @returns {TransactionBase} The encoded data
|
|
217
|
+
*/
|
|
218
|
+
async createAddOwnerTransaction(addOwnerParams) {
|
|
219
|
+
const addOwnerTransaction = await this.protocolKit.createAddOwnerTx(addOwnerParams);
|
|
220
|
+
return this.#buildTransaction(addOwnerTransaction);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Encodes the data for removing an owner from the Safe.
|
|
224
|
+
*
|
|
225
|
+
* @param {RemoveOwnerTxParams | RemovePasskeyOwnerTxParams} removeOwnerParams - The parameters for removing an owner
|
|
226
|
+
* @returns {TransactionBase} The encoded data
|
|
227
|
+
*/
|
|
228
|
+
async createRemoveOwnerTransaction(removeOwnerParams) {
|
|
229
|
+
const removeOwnerTransaction = await this.protocolKit.createRemoveOwnerTx(removeOwnerParams);
|
|
230
|
+
return this.#buildTransaction(removeOwnerTransaction);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Encodes the data for swapping an owner in the Safe.
|
|
234
|
+
*
|
|
235
|
+
* @param {SwapOwnerTxParams} swapParams - The parameters for swapping an owner
|
|
236
|
+
* @returns {TransactionBase} The encoded data
|
|
237
|
+
*/
|
|
238
|
+
async createSwapOwnerTransaction(swapParams) {
|
|
239
|
+
const swapOwnerTransaction = await this.protocolKit.createSwapOwnerTx(swapParams);
|
|
240
|
+
return this.#buildTransaction(swapOwnerTransaction);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Encodes the data for changing the Safe threshold.
|
|
244
|
+
*
|
|
245
|
+
* @param {ChangeThresholdTxParams} changeThresholdParams - The parameters for changing the Safe threshold
|
|
246
|
+
* @returns {TransactionBase} The encoded data
|
|
247
|
+
*/
|
|
248
|
+
async createChangeThresholdTransaction(changeThresholdParams) {
|
|
249
|
+
const changeThresholdTransaction = await this.protocolKit.createChangeThresholdTx(
|
|
250
|
+
changeThresholdParams.threshold
|
|
251
|
+
);
|
|
252
|
+
return this.#buildTransaction(changeThresholdTransaction);
|
|
253
|
+
}
|
|
254
|
+
async #buildTransaction(safeTransaction) {
|
|
255
|
+
return {
|
|
256
|
+
to: safeTransaction.data.to,
|
|
257
|
+
value: safeTransaction.data.value,
|
|
258
|
+
data: safeTransaction.data.data
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// src/SafeClient.ts
|
|
264
|
+
var SafeClient = class extends BaseClient {
|
|
265
|
+
constructor(protocolKit, apiKit) {
|
|
266
|
+
super(protocolKit, apiKit);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Sends transactions through the Safe protocol.
|
|
270
|
+
* You can send an array to transactions { to, value, data} that we will convert to a transaction batch
|
|
271
|
+
*
|
|
272
|
+
* @param {SendTransactionProps} props The SendTransactionProps object.
|
|
273
|
+
* @param {TransactionBase[]} props.transactions An array of transactions to be sent.
|
|
274
|
+
* @param {string} props.transactions[].to The recipient address of the transaction.
|
|
275
|
+
* @param {string} props.transactions[].value The value of the transaction.
|
|
276
|
+
* @param {string} props.transactions[].data The data of the transaction.
|
|
277
|
+
* @param {string} props.from The sender address of the transaction.
|
|
278
|
+
* @param {number | string} props.gasLimit The gas limit of the transaction.
|
|
279
|
+
* @param {number | string} props.gasPrice The gas price of the transaction.
|
|
280
|
+
* @param {number | string} props.maxFeePerGas The max fee per gas of the transaction.
|
|
281
|
+
* @param {number | string} props.maxPriorityFeePerGas The max priority fee per gas of the transaction.
|
|
282
|
+
* @param {number} props.nonce The nonce of the transaction.
|
|
283
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves to the result of the transaction.
|
|
284
|
+
*/
|
|
285
|
+
async send({
|
|
286
|
+
transactions,
|
|
287
|
+
...transactionOptions
|
|
288
|
+
}) {
|
|
289
|
+
const isSafeDeployed = await this.protocolKit.isSafeDeployed();
|
|
290
|
+
const isMultisigSafe = await this.protocolKit.getThreshold() > 1;
|
|
291
|
+
const safeTransaction = await this.protocolKit.createTransaction({ transactions });
|
|
292
|
+
if (isSafeDeployed) {
|
|
293
|
+
if (isMultisigSafe) {
|
|
294
|
+
return this.#proposeTransaction({ safeTransaction });
|
|
295
|
+
} else {
|
|
296
|
+
return this.#executeTransaction({ safeTransaction, ...transactionOptions });
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
if (isMultisigSafe) {
|
|
300
|
+
return this.#deployAndProposeTransaction({ safeTransaction, ...transactionOptions });
|
|
301
|
+
} else {
|
|
302
|
+
return this.#deployAndExecuteTransaction({ safeTransaction, ...transactionOptions });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Confirms a transaction by its safe transaction hash.
|
|
308
|
+
*
|
|
309
|
+
* @param {ConfirmTransactionProps} props The ConfirmTransactionProps object.
|
|
310
|
+
* @param {string} props.safeTxHash The hash of the safe transaction to confirm.
|
|
311
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves to the result of the confirmed transaction.
|
|
312
|
+
* @throws {Error} If the transaction confirmation fails.
|
|
313
|
+
*/
|
|
314
|
+
async confirm({ safeTxHash }) {
|
|
315
|
+
let transactionResponse = await this.apiKit.getTransaction(safeTxHash);
|
|
316
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
317
|
+
const signedTransaction = await this.protocolKit.signTransaction(transactionResponse);
|
|
318
|
+
await this.apiKit.confirmTransaction(safeTxHash, signedTransaction.encodedSignatures());
|
|
319
|
+
transactionResponse = await this.apiKit.getTransaction(safeTxHash);
|
|
320
|
+
if (transactionResponse.confirmations && transactionResponse.confirmationsRequired === transactionResponse.confirmations.length) {
|
|
321
|
+
const executedTransactionResponse = await this.protocolKit.executeTransaction(transactionResponse);
|
|
322
|
+
await waitSafeTxReceipt(executedTransactionResponse);
|
|
323
|
+
return createSafeClientResult({
|
|
324
|
+
status: "EXECUTED" /* EXECUTED */,
|
|
325
|
+
safeAddress,
|
|
326
|
+
txHash: executedTransactionResponse.hash,
|
|
327
|
+
safeTxHash
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return createSafeClientResult({
|
|
331
|
+
status: "PENDING_SIGNATURES" /* PENDING_SIGNATURES */,
|
|
332
|
+
safeAddress,
|
|
333
|
+
safeTxHash
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Retrieves the pending transactions for the current safe address.
|
|
338
|
+
*
|
|
339
|
+
* @async
|
|
340
|
+
* @returns {Promise<SafeMultisigTransactionListResponse>} A promise that resolves to an array of pending transactions.
|
|
341
|
+
* @throws {Error} If there is an issue retrieving the safe address or pending transactions.
|
|
342
|
+
*/
|
|
343
|
+
async getPendingTransactions() {
|
|
344
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
345
|
+
return this.apiKit.getPendingTransactions(safeAddress);
|
|
346
|
+
}
|
|
347
|
+
extend(extendFunc) {
|
|
348
|
+
const result = extendFunc(this);
|
|
349
|
+
if (result instanceof Promise) {
|
|
350
|
+
return result.then((extensions) => Object.assign(this, extensions));
|
|
351
|
+
} else {
|
|
352
|
+
return Object.assign(this, result);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Deploys and executes a transaction in one step.
|
|
357
|
+
*
|
|
358
|
+
* @param {SafeTransaction} safeTransaction The safe transaction to be executed
|
|
359
|
+
* @param {TransactionOptions} options Optional transaction options
|
|
360
|
+
* @returns A promise that resolves to the result of the transaction
|
|
361
|
+
*/
|
|
362
|
+
async #deployAndExecuteTransaction({
|
|
363
|
+
safeTransaction,
|
|
364
|
+
...transactionOptions
|
|
365
|
+
}) {
|
|
366
|
+
safeTransaction = await this.protocolKit.signTransaction(safeTransaction);
|
|
367
|
+
const transactionBatchWithDeployment = await this.protocolKit.wrapSafeTransactionIntoDeploymentBatch(
|
|
368
|
+
safeTransaction,
|
|
369
|
+
transactionOptions
|
|
370
|
+
);
|
|
371
|
+
const hash = await sendTransaction({
|
|
372
|
+
transaction: transactionBatchWithDeployment,
|
|
373
|
+
protocolKit: this.protocolKit
|
|
374
|
+
});
|
|
375
|
+
await this.#reconnectSafe();
|
|
376
|
+
return createSafeClientResult({
|
|
377
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
378
|
+
status: "DEPLOYED_AND_EXECUTED" /* DEPLOYED_AND_EXECUTED */,
|
|
379
|
+
deploymentTxHash: hash,
|
|
380
|
+
txHash: hash
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Deploys and proposes a transaction in one step.
|
|
385
|
+
*
|
|
386
|
+
* @param {SafeTransaction} safeTransaction The safe transaction to be proposed
|
|
387
|
+
* @param {TransactionOptions} transactionOptions Optional transaction options
|
|
388
|
+
* @returns A promise that resolves to the result of the transaction
|
|
389
|
+
*/
|
|
390
|
+
async #deployAndProposeTransaction({
|
|
391
|
+
safeTransaction,
|
|
392
|
+
...transactionOptions
|
|
393
|
+
}) {
|
|
394
|
+
const safeDeploymentTransaction = await this.protocolKit.createSafeDeploymentTransaction();
|
|
395
|
+
const hash = await sendTransaction({
|
|
396
|
+
transaction: { ...safeDeploymentTransaction, ...transactionOptions },
|
|
397
|
+
protocolKit: this.protocolKit
|
|
398
|
+
});
|
|
399
|
+
await this.#reconnectSafe();
|
|
400
|
+
safeTransaction = await this.protocolKit.signTransaction(safeTransaction);
|
|
401
|
+
const safeTxHash = await proposeTransaction({
|
|
402
|
+
safeTransaction,
|
|
403
|
+
protocolKit: this.protocolKit,
|
|
404
|
+
apiKit: this.apiKit
|
|
405
|
+
});
|
|
406
|
+
return createSafeClientResult({
|
|
407
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
408
|
+
status: "DEPLOYED_AND_PENDING_SIGNATURES" /* DEPLOYED_AND_PENDING_SIGNATURES */,
|
|
409
|
+
deploymentTxHash: hash,
|
|
410
|
+
safeTxHash
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Executes a transaction.
|
|
415
|
+
*
|
|
416
|
+
* @param {SafeTransaction} safeTransaction The safe transaction to be executed
|
|
417
|
+
* @param {TransactionOptions} transactionOptions Optional transaction options
|
|
418
|
+
* @returns A promise that resolves to the result of the transaction
|
|
419
|
+
*/
|
|
420
|
+
async #executeTransaction({
|
|
421
|
+
safeTransaction,
|
|
422
|
+
...transactionOptions
|
|
423
|
+
}) {
|
|
424
|
+
safeTransaction = await this.protocolKit.signTransaction(safeTransaction);
|
|
425
|
+
const { hash } = await this.protocolKit.executeTransaction(safeTransaction, transactionOptions);
|
|
426
|
+
return createSafeClientResult({
|
|
427
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
428
|
+
status: "EXECUTED" /* EXECUTED */,
|
|
429
|
+
txHash: hash
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Proposes a transaction to the Safe.
|
|
434
|
+
* @param { SafeTransaction } safeTransaction The safe transaction to propose
|
|
435
|
+
* @returns The SafeClientResult
|
|
436
|
+
*/
|
|
437
|
+
async #proposeTransaction({ safeTransaction }) {
|
|
438
|
+
const safeTxHash = await proposeTransaction({
|
|
439
|
+
safeTransaction,
|
|
440
|
+
protocolKit: this.protocolKit,
|
|
441
|
+
apiKit: this.apiKit
|
|
442
|
+
});
|
|
443
|
+
return createSafeClientResult({
|
|
444
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
445
|
+
status: "PENDING_SIGNATURES" /* PENDING_SIGNATURES */,
|
|
446
|
+
safeTxHash
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async #reconnectSafe() {
|
|
450
|
+
this.protocolKit = await this.protocolKit.connect({
|
|
451
|
+
provider: this.protocolKit.getSafeProvider().provider,
|
|
452
|
+
signer: this.protocolKit.getSafeProvider().signer,
|
|
453
|
+
safeAddress: await this.protocolKit.getAddress()
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// src/extensions/messages/onChainMessages.ts
|
|
459
|
+
var import_protocol_kit3 = require("@safe-global/protocol-kit");
|
|
460
|
+
var import_types_kit = require("@safe-global/types-kit");
|
|
461
|
+
function onChainMessages() {
|
|
462
|
+
return (client) => ({
|
|
463
|
+
/**
|
|
464
|
+
* Creates and sends a message as a regular transaction using the SignMessageLib contract
|
|
465
|
+
* The message can be a string or an EIP712TypedData object
|
|
466
|
+
* As this method creates a new transaction you can confirm it using the safeTxHash and the confirm() method and
|
|
467
|
+
* retrieve the pending transactions using the getPendingTransactions() method from the general client
|
|
468
|
+
* @param {SendOnChainMessageProps} props The message properties
|
|
469
|
+
* @returns {Promise<SafeClientResult>} A SafeClientResult. You can get the safeTxHash to confirm from the transaction property
|
|
470
|
+
*/
|
|
471
|
+
async sendOnChainMessage(props) {
|
|
472
|
+
const { message, ...transactionOptions } = props;
|
|
473
|
+
const signMessageLibContract = await (0, import_protocol_kit3.getSignMessageLibContract)({
|
|
474
|
+
safeProvider: client.protocolKit.getSafeProvider(),
|
|
475
|
+
safeVersion: client.protocolKit.getContractVersion()
|
|
476
|
+
});
|
|
477
|
+
const transaction = {
|
|
478
|
+
to: signMessageLibContract.getAddress(),
|
|
479
|
+
value: "0",
|
|
480
|
+
data: signMessageLibContract.encode("signMessage", [(0, import_protocol_kit3.hashSafeMessage)(message)]),
|
|
481
|
+
operation: import_types_kit.OperationType.DelegateCall
|
|
482
|
+
};
|
|
483
|
+
return client.send({ transactions: [transaction], ...transactionOptions });
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/extensions/messages/SafeMessageClient.ts
|
|
489
|
+
var import_protocol_kit4 = require("@safe-global/protocol-kit");
|
|
490
|
+
var SafeMessageClient = class {
|
|
491
|
+
/**
|
|
492
|
+
* @constructor
|
|
493
|
+
* @param {Safe} protocolKit A Safe instance
|
|
494
|
+
* @param {SafeApiKit} apiKit A SafeApiKit instance
|
|
495
|
+
*/
|
|
496
|
+
constructor(protocolKit, apiKit) {
|
|
497
|
+
this.protocolKit = protocolKit;
|
|
498
|
+
this.apiKit = apiKit;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Send off-chain messages using the Transaction service
|
|
502
|
+
*
|
|
503
|
+
* @param {SendOffChainMessageProps} props The message properties
|
|
504
|
+
* @param {string | EIP712TypedData} props.message The message to be sent. Can be a raw string or an EIP712TypedData object
|
|
505
|
+
* @returns {Promise<SafeClientResult>} A SafeClientResult. You can get the messageHash to confirmMessage() afterwards from the messages property
|
|
506
|
+
*/
|
|
507
|
+
async sendMessage({ message }) {
|
|
508
|
+
const isSafeDeployed = await this.protocolKit.isSafeDeployed();
|
|
509
|
+
const safeMessage = this.protocolKit.createMessage(message);
|
|
510
|
+
if (isSafeDeployed) {
|
|
511
|
+
return this.#addMessage({ safeMessage });
|
|
512
|
+
} else {
|
|
513
|
+
return this.#deployAndAddMessage({ safeMessage });
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Confirms an off-chain message using the Transaction service
|
|
518
|
+
*
|
|
519
|
+
* @param {ConfirmOffChainMessageProps} props The confirmation properties
|
|
520
|
+
* @param {string} props.messageHash The messageHash. Returned from the sendMessage() method inside the SafeClientResult messages property
|
|
521
|
+
* @returns {Promise<SafeClientResult>} A SafeClientResult with the result of the confirmation
|
|
522
|
+
*/
|
|
523
|
+
async confirmMessage({ messageHash }) {
|
|
524
|
+
let messageResponse = await this.apiKit.getMessage(messageHash);
|
|
525
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
526
|
+
const threshold = await this.protocolKit.getThreshold();
|
|
527
|
+
let safeMessage = this.protocolKit.createMessage(messageResponse.message);
|
|
528
|
+
safeMessage = await this.protocolKit.signMessage(safeMessage);
|
|
529
|
+
await this.apiKit.addMessageSignature(messageHash, safeMessage.encodedSignatures());
|
|
530
|
+
messageResponse = await this.apiKit.getMessage(messageHash);
|
|
531
|
+
return createSafeClientResult({
|
|
532
|
+
status: messageResponse.confirmations.length === threshold ? "MESSAGE_CONFIRMED" /* MESSAGE_CONFIRMED */ : "MESSAGE_PENDING_SIGNATURES" /* MESSAGE_PENDING_SIGNATURES */,
|
|
533
|
+
safeAddress,
|
|
534
|
+
messageHash
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Get the list of pending off-chain messages. This messages can be confirmed using the confirmMessage() method
|
|
539
|
+
*
|
|
540
|
+
* @param {ListOptions} options The pagination options
|
|
541
|
+
* @returns {Promise<SafeMessageListResponse>} A list of pending messages
|
|
542
|
+
*/
|
|
543
|
+
async getPendingMessages(options) {
|
|
544
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
545
|
+
return this.apiKit.getMessages(safeAddress, options);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Deploys a new Safe account based on the provided config and adds a message using the Transaction service
|
|
549
|
+
* - If the Safe threshold > 1, we need to deploy the Safe account first and afterwards add the message
|
|
550
|
+
* The message should be confirmed with other owners using the confirmMessage() method until the threshold is reached in order to be valid
|
|
551
|
+
* - If the threshold = 1, we can deploy the Safe account and add the message in one step. The message will be valid immediately
|
|
552
|
+
*
|
|
553
|
+
* @param {SafeTransaction} safeMessage The safe message
|
|
554
|
+
* @returns {Promise<SafeClientResult>} The SafeClientResult
|
|
555
|
+
*/
|
|
556
|
+
async #deployAndAddMessage({
|
|
557
|
+
safeMessage
|
|
558
|
+
}) {
|
|
559
|
+
let deploymentTxHash;
|
|
560
|
+
const threshold = await this.protocolKit.getThreshold();
|
|
561
|
+
const safeDeploymentTransaction = await this.protocolKit.createSafeDeploymentTransaction();
|
|
562
|
+
try {
|
|
563
|
+
deploymentTxHash = await sendTransaction({
|
|
564
|
+
transaction: safeDeploymentTransaction,
|
|
565
|
+
protocolKit: this.protocolKit
|
|
566
|
+
});
|
|
567
|
+
await this.#updateProtocolKitWithDeployedSafe();
|
|
568
|
+
} catch (error) {
|
|
569
|
+
throw new Error("Could not deploy the Safe account");
|
|
570
|
+
}
|
|
571
|
+
try {
|
|
572
|
+
const { messages } = await this.#addMessage({ safeMessage });
|
|
573
|
+
const messageResponse = await this.apiKit.getMessage(messages?.messageHash || "0x");
|
|
574
|
+
return createSafeClientResult({
|
|
575
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
576
|
+
status: messageResponse.confirmations.length === threshold ? "DEPLOYED_AND_MESSAGE_CONFIRMED" /* DEPLOYED_AND_MESSAGE_CONFIRMED */ : "DEPLOYED_AND_MESSAGE_PENDING_SIGNATURES" /* DEPLOYED_AND_MESSAGE_PENDING_SIGNATURES */,
|
|
577
|
+
deploymentTxHash,
|
|
578
|
+
messageHash: messages?.messageHash
|
|
579
|
+
});
|
|
580
|
+
} catch (error) {
|
|
581
|
+
throw new Error("Could not add a new off-chain message to the Safe account");
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Add a new off-chain message using the Transaction service
|
|
586
|
+
* - If the threshold > 1, remember to confirmMessage() after sendMessage()
|
|
587
|
+
* - If the threshold = 1, then the message is confirmed and valid immediately
|
|
588
|
+
*
|
|
589
|
+
* @param {SafeMessage} safeMessage The message
|
|
590
|
+
* @returns {Promise<SafeClientResult>} The SafeClientResult
|
|
591
|
+
*/
|
|
592
|
+
async #addMessage({ safeMessage }) {
|
|
593
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
594
|
+
const threshold = await this.protocolKit.getThreshold();
|
|
595
|
+
const signedMessage = await this.protocolKit.signMessage(safeMessage);
|
|
596
|
+
const messageHash = await this.protocolKit.getSafeMessageHash((0, import_protocol_kit4.hashSafeMessage)(safeMessage.data));
|
|
597
|
+
try {
|
|
598
|
+
await this.apiKit.addMessage(safeAddress, {
|
|
599
|
+
message: safeMessage.data,
|
|
600
|
+
signature: signedMessage.encodedSignatures()
|
|
601
|
+
});
|
|
602
|
+
} catch (error) {
|
|
603
|
+
throw new Error("Could not add a new off-chain message to the Safe account");
|
|
604
|
+
}
|
|
605
|
+
const message = await this.apiKit.getMessage(messageHash);
|
|
606
|
+
return createSafeClientResult({
|
|
607
|
+
safeAddress: await this.protocolKit.getAddress(),
|
|
608
|
+
status: message.confirmations.length === threshold ? "MESSAGE_CONFIRMED" /* MESSAGE_CONFIRMED */ : "MESSAGE_PENDING_SIGNATURES" /* MESSAGE_PENDING_SIGNATURES */,
|
|
609
|
+
messageHash
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* This method updates the Safe instance with the deployed Safe account
|
|
614
|
+
*/
|
|
615
|
+
async #updateProtocolKitWithDeployedSafe() {
|
|
616
|
+
this.protocolKit = await this.protocolKit.connect({
|
|
617
|
+
provider: this.protocolKit.getSafeProvider().provider,
|
|
618
|
+
signer: this.protocolKit.getSafeProvider().signer,
|
|
619
|
+
safeAddress: await this.protocolKit.getAddress()
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// src/extensions/messages/offChainMessages.ts
|
|
625
|
+
function offChainMessages() {
|
|
626
|
+
return (client) => {
|
|
627
|
+
const safeMessageClient = new SafeMessageClient(client.protocolKit, client.apiKit);
|
|
628
|
+
return {
|
|
629
|
+
/**
|
|
630
|
+
* Creates an off-chain message using the Transaction service
|
|
631
|
+
*
|
|
632
|
+
* @param {SendOffChainMessageProps} props The message properties
|
|
633
|
+
* @returns {Promise<SafeClientResult>} A SafeClientResult. You can get the messageHash to confirmMessage() afterwards from the messages property */
|
|
634
|
+
async sendOffChainMessage(props) {
|
|
635
|
+
return safeMessageClient.sendMessage(props);
|
|
636
|
+
},
|
|
637
|
+
/**
|
|
638
|
+
* Confirms an off-chain message using the Transaction service
|
|
639
|
+
*
|
|
640
|
+
* @param {ConfirmOffChainMessageProps} props The confirmation properties
|
|
641
|
+
* @returns {Promise<SafeClientResult>} A SafeClientResult with the result of the confirmation
|
|
642
|
+
*/
|
|
643
|
+
async confirmOffChainMessage(props) {
|
|
644
|
+
return safeMessageClient.confirmMessage(props);
|
|
645
|
+
},
|
|
646
|
+
/**
|
|
647
|
+
* Get the list of pending off-chain messages. This messages can be confirmed using the confirmMessage() method
|
|
648
|
+
*
|
|
649
|
+
* @param {ListOptions} options The pagination options
|
|
650
|
+
* @returns {Promise<SafeMessageListResponse>} A list of pending messages
|
|
651
|
+
*/
|
|
652
|
+
async getPendingOffChainMessages(options) {
|
|
653
|
+
return safeMessageClient.getPendingMessages(options);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/extensions/safe-operations/safeOperations.ts
|
|
660
|
+
var import_relay_kit = require("@safe-global/relay-kit");
|
|
661
|
+
|
|
662
|
+
// src/extensions/safe-operations/SafeOperationClient.ts
|
|
663
|
+
var import_protocol_kit5 = require("@safe-global/protocol-kit");
|
|
664
|
+
var SafeOperationClient = class {
|
|
665
|
+
constructor(safe4337Pack, apiKit) {
|
|
666
|
+
this.protocolKit = safe4337Pack.protocolKit;
|
|
667
|
+
this.apiKit = apiKit;
|
|
668
|
+
this.safe4337Pack = safe4337Pack;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Send SafeOperations from a group of transactions.
|
|
672
|
+
* This method will convert your transactions in a batch and:
|
|
673
|
+
* - If the threshold > 1 it will save for later the SafeOperation using the Transaction service
|
|
674
|
+
* You must confirmSafeOperation() with other owners
|
|
675
|
+
* - If the threshold = 1 the SafeOperation can be submitted to the bundler so it will execute it immediately
|
|
676
|
+
*
|
|
677
|
+
* @param {Safe4337CreateTransactionProps} props The Safe4337CreateTransactionProps object
|
|
678
|
+
* @param {SafeTransaction[]} props.transactions An array of transactions to be batched
|
|
679
|
+
* @param {TransactionOptions} [props.amountToApprove] The amount to approve for the SafeOperation
|
|
680
|
+
* @param {TransactionOptions} [props.validUntil] The validUntil timestamp for the SafeOperation
|
|
681
|
+
* @param {TransactionOptions} [props.validAfter] The validAfter timestamp for the SafeOperation
|
|
682
|
+
* @param {TransactionOptions} [props.feeEstimator] The feeEstimator to calculate the fees
|
|
683
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves with the status of the SafeOperation
|
|
684
|
+
*/
|
|
685
|
+
async sendSafeOperation({
|
|
686
|
+
transactions,
|
|
687
|
+
...sendSafeOperationOptions
|
|
688
|
+
}) {
|
|
689
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
690
|
+
const isMultisigSafe = await this.protocolKit.getThreshold() > 1;
|
|
691
|
+
let safeOperation = await this.safe4337Pack.createTransaction({
|
|
692
|
+
transactions,
|
|
693
|
+
options: sendSafeOperationOptions
|
|
694
|
+
});
|
|
695
|
+
safeOperation = await this.safe4337Pack.signSafeOperation(safeOperation);
|
|
696
|
+
if (isMultisigSafe) {
|
|
697
|
+
await this.apiKit.addSafeOperation(safeOperation);
|
|
698
|
+
const safeOperationHash = safeOperation.getHash();
|
|
699
|
+
return createSafeClientResult({
|
|
700
|
+
safeAddress,
|
|
701
|
+
status: "SAFE_OPERATION_PENDING_SIGNATURES" /* SAFE_OPERATION_PENDING_SIGNATURES */,
|
|
702
|
+
safeOperationHash
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
const userOperationHash = await this.safe4337Pack.executeTransaction({
|
|
706
|
+
executable: safeOperation
|
|
707
|
+
});
|
|
708
|
+
await this.#waitForOperationToFinish({ userOperationHash });
|
|
709
|
+
return createSafeClientResult({
|
|
710
|
+
safeAddress,
|
|
711
|
+
status: "SAFE_OPERATION_EXECUTED" /* SAFE_OPERATION_EXECUTED */,
|
|
712
|
+
userOperationHash,
|
|
713
|
+
safeOperationHash: safeOperation.getHash()
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Confirms the stored safeOperation
|
|
718
|
+
*
|
|
719
|
+
* @param {ConfirmSafeOperationProps} props The confirmation properties
|
|
720
|
+
* @param {string} props.safeOperationHash The hash of the safe operation to confirm.
|
|
721
|
+
* The safeOperationHash can be extracted from the SafeClientResult of the sendSafeOperation method under the safeOperations property
|
|
722
|
+
* You must confirmSafeOperation() with the other owners and once the threshold is reached the SafeOperation will be sent to the bundler
|
|
723
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves to the result of the safeOperation.
|
|
724
|
+
*/
|
|
725
|
+
async confirmSafeOperation({
|
|
726
|
+
safeOperationHash
|
|
727
|
+
}) {
|
|
728
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
729
|
+
const threshold = await this.protocolKit.getThreshold();
|
|
730
|
+
await this.apiKit.confirmSafeOperation(
|
|
731
|
+
safeOperationHash,
|
|
732
|
+
(0, import_protocol_kit5.buildSignatureBytes)([await this.protocolKit.signHash(safeOperationHash)])
|
|
733
|
+
);
|
|
734
|
+
const confirmedSafeOperation = await this.apiKit.getSafeOperation(safeOperationHash);
|
|
735
|
+
if (confirmedSafeOperation?.confirmations?.length === threshold) {
|
|
736
|
+
const userOperationHash = await this.safe4337Pack.executeTransaction({
|
|
737
|
+
executable: confirmedSafeOperation
|
|
738
|
+
});
|
|
739
|
+
await this.#waitForOperationToFinish({ userOperationHash });
|
|
740
|
+
return createSafeClientResult({
|
|
741
|
+
status: "SAFE_OPERATION_EXECUTED" /* SAFE_OPERATION_EXECUTED */,
|
|
742
|
+
safeAddress,
|
|
743
|
+
userOperationHash,
|
|
744
|
+
safeOperationHash
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
return createSafeClientResult({
|
|
748
|
+
status: "SAFE_OPERATION_PENDING_SIGNATURES" /* SAFE_OPERATION_PENDING_SIGNATURES */,
|
|
749
|
+
safeAddress,
|
|
750
|
+
safeOperationHash
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Retrieves the pending Safe operations for the current Safe account
|
|
755
|
+
*
|
|
756
|
+
* @async
|
|
757
|
+
* @param {ListOptions} options The pagination options
|
|
758
|
+
* @returns {Promise<GetSafeOperationListResponse>} A promise that resolves to an array of pending Safe operations.
|
|
759
|
+
* @throws {Error} If there is an issue retrieving the safe address or pending Safe operations.
|
|
760
|
+
*/
|
|
761
|
+
async getPendingSafeOperations(options) {
|
|
762
|
+
const safeAddress = await this.protocolKit.getAddress();
|
|
763
|
+
return this.apiKit.getPendingSafeOperations({ safeAddress, ...options });
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Helper method to wait for the operation to finish
|
|
767
|
+
* @param userOperationHash The userOperationHash to wait for. This comes from the bundler and can be obtained from the
|
|
768
|
+
* SafeClientResult method under the safeOperations property
|
|
769
|
+
*/
|
|
770
|
+
async #waitForOperationToFinish({
|
|
771
|
+
userOperationHash
|
|
772
|
+
}) {
|
|
773
|
+
let userOperationReceipt = null;
|
|
774
|
+
while (!userOperationReceipt) {
|
|
775
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
776
|
+
userOperationReceipt = await this.safe4337Pack.getUserOperationReceipt(userOperationHash);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// src/extensions/safe-operations/safeOperations.ts
|
|
782
|
+
function safeOperations({ bundlerUrl }, paymasterOptions) {
|
|
783
|
+
return async (client) => {
|
|
784
|
+
const { provider, signer } = client.protocolKit.getSafeProvider();
|
|
785
|
+
const isSafeDeployed = await client.protocolKit.isSafeDeployed();
|
|
786
|
+
let options;
|
|
787
|
+
if (isSafeDeployed) {
|
|
788
|
+
const safeAddress = await client.protocolKit.getAddress();
|
|
789
|
+
options = {
|
|
790
|
+
safeAddress
|
|
791
|
+
};
|
|
792
|
+
} else {
|
|
793
|
+
const { safeDeploymentConfig, safeAccountConfig } = client.protocolKit.getPredictedSafe();
|
|
794
|
+
options = {
|
|
795
|
+
owners: safeAccountConfig.owners,
|
|
796
|
+
threshold: safeAccountConfig.threshold,
|
|
797
|
+
...safeDeploymentConfig
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
const safe4337Pack = await import_relay_kit.Safe4337Pack.init({
|
|
801
|
+
provider,
|
|
802
|
+
signer,
|
|
803
|
+
bundlerUrl,
|
|
804
|
+
options,
|
|
805
|
+
paymasterOptions
|
|
806
|
+
});
|
|
807
|
+
client.protocolKit = safe4337Pack.protocolKit;
|
|
808
|
+
const safeOperationClient = new SafeOperationClient(safe4337Pack, client.apiKit);
|
|
809
|
+
return {
|
|
810
|
+
/**
|
|
811
|
+
* Send SafeOperations from a group of transactions.
|
|
812
|
+
* This method will convert your transactions in a batch and:
|
|
813
|
+
* - If the threshold > 1 it will save for later the SafeOperation using the Transaction service
|
|
814
|
+
* You must confirmSafeOperation() with other owners
|
|
815
|
+
* - If the threshold = 1 the SafeOperation can be submitted to the bundler so it will execute it immediately
|
|
816
|
+
*
|
|
817
|
+
* @param {Safe4337CreateTransactionProps} props The Safe4337CreateTransactionProps object
|
|
818
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves with the status of the SafeOperation
|
|
819
|
+
*/
|
|
820
|
+
async sendSafeOperation(props) {
|
|
821
|
+
return safeOperationClient.sendSafeOperation(props);
|
|
822
|
+
},
|
|
823
|
+
/**
|
|
824
|
+
* Confirms the stored safeOperation
|
|
825
|
+
*
|
|
826
|
+
* @param {ConfirmSafeOperationProps} props The ConfirmSafeOperationProps object
|
|
827
|
+
* @returns {Promise<SafeClientResult>} A promise that resolves to the result of the safeOperation.
|
|
828
|
+
*/
|
|
829
|
+
async confirmSafeOperation(props) {
|
|
830
|
+
return safeOperationClient.confirmSafeOperation(props);
|
|
831
|
+
},
|
|
832
|
+
/**
|
|
833
|
+
* Retrieves the pending Safe operations for the current Safe account
|
|
834
|
+
*
|
|
835
|
+
* @async
|
|
836
|
+
* @param {ListOptions} options The pagination options
|
|
837
|
+
* @returns {Promise<GetSafeOperationListResponse>} A promise that resolves to an array of pending Safe operations.
|
|
838
|
+
* @throws {Error} If there is an issue retrieving the safe address or pending Safe operations.
|
|
839
|
+
*/
|
|
840
|
+
async getPendingSafeOperations(options2) {
|
|
841
|
+
return safeOperationClient.getPendingSafeOperations(options2);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// src/index.ts
|
|
848
|
+
async function createSafeClient(config) {
|
|
849
|
+
const protocolKit = await getProtocolKitInstance(config);
|
|
850
|
+
const apiKit = await getApiKitInstance(protocolKit, config);
|
|
851
|
+
if (!protocolKit || !apiKit) throw new Error("Failed to create a kit instances");
|
|
852
|
+
return new SafeClient(protocolKit, apiKit);
|
|
853
|
+
}
|
|
854
|
+
async function getProtocolKitInstance(config) {
|
|
855
|
+
if (config.safeAddress && isValidAddress(config.safeAddress)) {
|
|
856
|
+
return import_protocol_kit6.default.init({
|
|
857
|
+
provider: config.provider,
|
|
858
|
+
signer: config.signer,
|
|
859
|
+
safeAddress: config.safeAddress
|
|
860
|
+
});
|
|
861
|
+
} else if (config.safeOptions && isValidSafeConfig(config.safeOptions)) {
|
|
862
|
+
let protocolKit;
|
|
863
|
+
const initConfig = {
|
|
864
|
+
provider: config.provider,
|
|
865
|
+
signer: config.signer,
|
|
866
|
+
predictedSafe: {
|
|
867
|
+
safeAccountConfig: {
|
|
868
|
+
owners: config.safeOptions.owners,
|
|
869
|
+
threshold: config.safeOptions.threshold
|
|
870
|
+
},
|
|
871
|
+
safeDeploymentConfig: {
|
|
872
|
+
saltNonce: config.safeOptions.saltNonce,
|
|
873
|
+
deploymentType: DEFAULT_DEPLOYMENT_TYPE
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
try {
|
|
878
|
+
protocolKit = await import_protocol_kit6.default.init(initConfig);
|
|
879
|
+
} catch (error) {
|
|
880
|
+
const isDeploymentTypeUnresolvedError = error instanceof Error && error.message && error.message.startsWith("Invalid") && error.message.includes("contract address");
|
|
881
|
+
if (isDeploymentTypeUnresolvedError && initConfig.predictedSafe.safeDeploymentConfig?.deploymentType) {
|
|
882
|
+
delete initConfig.predictedSafe.safeDeploymentConfig.deploymentType;
|
|
883
|
+
protocolKit = await import_protocol_kit6.default.init(initConfig);
|
|
884
|
+
} else {
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const isSafeDeployed = await protocolKit.isSafeDeployed();
|
|
889
|
+
if (isSafeDeployed) {
|
|
890
|
+
return import_protocol_kit6.default.init({
|
|
891
|
+
provider: config.provider,
|
|
892
|
+
signer: config.signer,
|
|
893
|
+
safeAddress: await protocolKit.getAddress()
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
return protocolKit;
|
|
897
|
+
} else {
|
|
898
|
+
throw new Error(
|
|
899
|
+
"Invalid configuration: either a valid safeAddress or valid safeOptions must be provided."
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
async function getApiKitInstance(protocolKit, config) {
|
|
904
|
+
const chainId = await protocolKit.getChainId();
|
|
905
|
+
return new import_api_kit.default({ chainId, txServiceUrl: config.txServiceUrl });
|
|
906
|
+
}
|