@skalenetwork/upgrade-tools 1.0.0-version.2 → 2.0.0-develop.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 (41) hide show
  1. package/README.md +66 -11
  2. package/dist/hardhat.config.js +1 -1
  3. package/dist/src/deploy.d.ts +0 -1
  4. package/dist/src/deploy.js +4 -6
  5. package/dist/src/gnosis-safe.d.ts +1 -1
  6. package/dist/src/gnosis-safe.js +118 -42
  7. package/dist/src/index.d.ts +2 -2
  8. package/dist/src/index.js +2 -2
  9. package/dist/src/submitters/auto-submitter.d.ts +11 -0
  10. package/dist/src/submitters/auto-submitter.js +176 -0
  11. package/dist/src/submitters/eoa-submitter.d.ts +5 -0
  12. package/dist/src/submitters/eoa-submitter.js +34 -0
  13. package/dist/src/submitters/index.d.ts +6 -0
  14. package/dist/src/submitters/index.js +22 -0
  15. package/dist/src/submitters/safe-ima-legacy-marionette-submitter.d.ts +6 -0
  16. package/dist/src/submitters/safe-ima-legacy-marionette-submitter.js +71 -0
  17. package/dist/src/submitters/safe-ima-marionette-submitter.d.ts +7 -0
  18. package/dist/src/submitters/safe-ima-marionette-submitter.js +80 -0
  19. package/dist/src/submitters/safe-submitter.d.ts +8 -0
  20. package/dist/src/submitters/safe-submitter.js +44 -0
  21. package/dist/src/submitters/safe-to-ima-submitter.d.ts +9 -0
  22. package/dist/src/submitters/safe-to-ima-submitter.js +39 -0
  23. package/dist/src/submitters/submitter.d.ts +5 -0
  24. package/dist/src/submitters/submitter.js +21 -0
  25. package/dist/src/submitters/types/marionette.d.ts +13 -0
  26. package/dist/src/submitters/types/marionette.js +4 -0
  27. package/dist/src/types/SkaleABIFile.d.ts +3 -0
  28. package/dist/src/{types.js → types/SkaleABIFile.js} +0 -0
  29. package/dist/src/{types.d.ts → types/SkaleManifestData.d.ts} +0 -3
  30. package/dist/src/types/SkaleManifestData.js +2 -0
  31. package/dist/src/upgrader.d.ts +19 -0
  32. package/dist/src/upgrader.js +140 -0
  33. package/dist/typechain-types/factories/AdminUpgradeabilityProxy__factory.d.ts +1 -1
  34. package/dist/typechain-types/factories/AdminUpgradeabilityProxy__factory.js +1 -1
  35. package/dist/typechain-types/factories/ProxyAdmin__factory.d.ts +1 -1
  36. package/dist/typechain-types/factories/ProxyAdmin__factory.js +1 -1
  37. package/dist/typechain-types/factories/SafeMock__factory.d.ts +1 -1
  38. package/dist/typechain-types/factories/SafeMock__factory.js +1 -1
  39. package/package.json +1 -1
  40. package/dist/src/upgrade.d.ts +0 -7
  41. package/dist/src/upgrade.js +0 -203
package/README.md CHANGED
@@ -4,19 +4,74 @@ Scripts to support upgrades of smart contracts. The package contains common used
4
4
 
5
5
  ## Upgrade scripts
6
6
 
7
- To write upgrade script import `upgrade` function.
7
+ To write an upgrade script extend `Upgrader` class.
8
8
 
9
9
  ```typescript
10
- import { upgrade } from "@skalenetwork/upgrade-tools"
10
+ import { Upgrader } from "@skalenetwork/upgrade-tools";
11
+
12
+ class ExampleContractUpgrader extends Upgrader {
13
+
14
+ getDeployedVersion = async () => {
15
+ return await (await this.getExampleContract()).version();
16
+ };
17
+
18
+ setVersion = async (newVersion: string) => {
19
+ const exampleContract = await this.getExampleContract();
20
+ const setVersionTransaction = {
21
+ to: exampleContract.address,
22
+ data: exampleContract.interface.encodeFunctionData("setVersion", [newVersion])
23
+ };
24
+ this.transactions.push(setVersionTransaction);
25
+ }
26
+
27
+ async getExampleContract() {
28
+ return await ethers.getContractAt("ExampleContract", this.abi["example_contract_address"] as string);
29
+ }
30
+ }
31
+
32
+ async function main() {
33
+ const abi = JSON.parse(await fs.readFile(process.env.ABI, "utf-8")) as SkaleABIFile;
34
+
35
+ const upgrader = new ExampleContractUpgrader(
36
+ "ExampleContract",
37
+ "1.0.0",
38
+ abi,
39
+ ["ExampleContract"]
40
+ );
41
+
42
+ await upgrader.upgrade();
43
+ }
44
+
45
+ if (require.main === module) {
46
+ main()
47
+ .then(() => process.exit(0))
48
+ .catch(error => {
49
+ console.error(error);
50
+ process.exit(1);
51
+ });
52
+ }
53
+ ```
54
+
55
+ ### Abstract functions
56
+
57
+ The `Upgrader` has 2 abstract functions. It's mandatory to override them:
58
+
59
+ ```typescript
60
+ abstract getDeployedVersion: () => Promise<string | undefined>
61
+ abstract setVersion: (newVersion: string) => Promise<void>
11
62
  ```
12
63
 
13
- Then call it with parameters below:
64
+ - `getDeployedVersion` returns string representing a deployed version of the contract
65
+ - `setVersion` creates a transaction to set a new version of the contract
66
+
67
+ ### Protected functions
68
+
69
+ There are functions that may be overridden to customize an upgrade process
70
+
71
+ ```typescript
72
+ deployNewContracts = () => { return Promise.resolve() };
73
+ initialize = () => { return Promise.resolve() };
74
+ ```
14
75
 
15
- - `projectName` - project name
16
- - `targetVersion` - version of smart contracts that can be upgraded by the script
17
- - `getDeployedVersion` - a function to request current version from smart contracts
18
- - `setVersion` - function that sets version to smart contracts
19
- - `safeMockAccessRequirements` - list of smart contracts that requires ownership changing for successful upgrade (when EOA + SafeMock are used during upgrade)
20
- - `contractNamesToUpgrade` - list of smart contracts to upgrade
21
- - `deployNewContracts` - optional - a function that deploys new smart contracts
22
- - `initialize` - optional - a function that setup smart contracts after upgrade
76
+ - `deployNewContracts` is called before proxies upgrade and is used to deploy new instances
77
+ - `initialize` is called after proxies upgrade and is used to send initializing transactions
@@ -18,7 +18,7 @@ const config = {
18
18
  ]
19
19
  },
20
20
  typechain: {
21
- externalArtifacts: ['node_modules/@openzeppelin/upgrades-core/artifacts/*.json']
21
+ externalArtifacts: ['node_modules/@openzeppelin/upgrades-core/artifacts/[!b]*.json']
22
22
  }
23
23
  };
24
24
  exports.default = config;
@@ -1,5 +1,4 @@
1
1
  export declare function deployLibraries(libraryNames: string[]): Promise<Map<string, string>>;
2
2
  export declare function getLinkedContractFactory(contractName: string, libraries: Map<string, string>): Promise<import("ethers").ContractFactory>;
3
- export declare function getContractKeyInAbiFile(contract: string): string;
4
3
  export declare function getManifestFile(): Promise<string>;
5
4
  export declare function getContractFactory(contract: string): Promise<import("ethers").ContractFactory>;
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getContractFactory = exports.getManifestFile = exports.getContractKeyInAbiFile = exports.getLinkedContractFactory = exports.deployLibraries = void 0;
12
+ exports.getContractFactory = exports.getManifestFile = exports.getLinkedContractFactory = exports.deployLibraries = void 0;
13
13
  const upgrades_core_1 = require("@openzeppelin/upgrades-core");
14
14
  const hardhat_1 = require("hardhat");
15
15
  const fs_1 = require("fs");
@@ -58,10 +58,6 @@ function getLinkedContractFactory(contractName, libraries) {
58
58
  });
59
59
  }
60
60
  exports.getLinkedContractFactory = getLinkedContractFactory;
61
- function getContractKeyInAbiFile(contract) {
62
- return contract.replace(/([a-zA-Z])(?=[A-Z])/g, '$1_').toLowerCase();
63
- }
64
- exports.getContractKeyInAbiFile = getContractKeyInAbiFile;
65
61
  function getManifestFile() {
66
62
  return __awaiter(this, void 0, void 0, function* () {
67
63
  return (yield upgrades_core_1.Manifest.forNetwork(hardhat_1.ethers.provider)).file;
@@ -90,7 +86,9 @@ function getContractFactory(contract) {
90
86
  Object.assign(libraryArtifacts, manifest.libraries);
91
87
  }
92
88
  finally {
93
- Object.assign(manifest, { libraries: libraryArtifacts });
89
+ if (manifest !== undefined) {
90
+ Object.assign(manifest, { libraries: libraryArtifacts });
91
+ }
94
92
  yield fs_1.promises.writeFile(yield getManifestFile(), JSON.stringify(manifest, null, 4));
95
93
  }
96
94
  return yield getLinkedContractFactory(contract, libraries);
@@ -20,6 +20,6 @@ interface SafeMultisigTransaction {
20
20
  }
21
21
  export declare function getSafeTransactionUrl(chainId: number): string;
22
22
  export declare function getSafeRelayUrl(chainId: number): string;
23
- export declare function createMultiSendTransaction(ethers: Ethers, safeAddress: string, privateKey: string, transactions: string[], isSafeMock?: boolean): Promise<SafeMultisigTransaction>;
23
+ export declare function createMultiSendTransaction(ethers: Ethers, safeAddress: string, privateKey: string, transactions: string[], chainId: number, nonce?: number): Promise<SafeMultisigTransaction>;
24
24
  export declare function sendSafeTransaction(safe: string, chainId: number, safeTx: SafeMultisigTransaction): Promise<void>;
25
25
  export {};
@@ -44,44 +44,33 @@ var Network;
44
44
  (function (Network) {
45
45
  Network[Network["MAINNET"] = 1] = "MAINNET";
46
46
  Network[Network["RINKEBY"] = 4] = "RINKEBY";
47
+ Network[Network["GOERLI"] = 5] = "GOERLI";
47
48
  Network[Network["GANACHE"] = 1337] = "GANACHE";
48
49
  Network[Network["HARDHAT"] = 31337] = "HARDHAT";
49
50
  })(Network || (Network = {}));
51
+ // constants
50
52
  const ADDRESSES = {
51
53
  multiSend: {
52
54
  [Network.MAINNET]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD",
53
55
  [Network.RINKEBY]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD",
56
+ [Network.GOERLI]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD",
54
57
  },
55
58
  };
56
59
  const URLS = {
57
60
  safe_transaction: {
58
61
  [Network.MAINNET]: "https://safe-transaction.mainnet.gnosis.io",
59
62
  [Network.RINKEBY]: "https://safe-transaction.rinkeby.gnosis.io",
63
+ [Network.GOERLI]: "https://safe-transaction.goerli.gnosis.io",
60
64
  },
61
65
  safe_relay: {
62
66
  [Network.MAINNET]: "https://safe-relay.mainnet.gnosis.io",
63
67
  [Network.RINKEBY]: "https://safe-relay.rinkeby.gnosis.io",
68
+ [Network.GOERLI]: "https://safe-relay.goerli.gnosis.io",
64
69
  }
65
70
  };
66
- function getMultiSendAddress(chainId) {
67
- if (chainId === Network.MAINNET) {
68
- return ADDRESSES.multiSend[chainId];
69
- }
70
- else if (chainId === Network.RINKEBY) {
71
- return ADDRESSES.multiSend[chainId];
72
- }
73
- else if ([Network.GANACHE, Network.HARDHAT].includes(chainId)) {
74
- return ethers_1.ethers.constants.AddressZero;
75
- }
76
- else {
77
- throw Error(`Can't get multiSend contract at network with chainId = ${chainId}`);
78
- }
79
- }
71
+ // public functions
80
72
  function getSafeTransactionUrl(chainId) {
81
- if (chainId === Network.MAINNET) {
82
- return URLS.safe_transaction[chainId];
83
- }
84
- else if (chainId === 4) {
73
+ if (Object.keys(URLS.safe_transaction).includes(chainId.toString())) {
85
74
  return URLS.safe_transaction[chainId];
86
75
  }
87
76
  else {
@@ -90,10 +79,7 @@ function getSafeTransactionUrl(chainId) {
90
79
  }
91
80
  exports.getSafeTransactionUrl = getSafeTransactionUrl;
92
81
  function getSafeRelayUrl(chainId) {
93
- if (chainId === 1) {
94
- return URLS.safe_relay[chainId];
95
- }
96
- else if (chainId === 4) {
82
+ if (Object.keys(URLS.safe_relay).includes(chainId.toString())) {
97
83
  return URLS.safe_relay[chainId];
98
84
  }
99
85
  else {
@@ -101,29 +87,34 @@ function getSafeRelayUrl(chainId) {
101
87
  }
102
88
  }
103
89
  exports.getSafeRelayUrl = getSafeRelayUrl;
104
- function concatTransactions(transactions) {
105
- return "0x" + transactions.map((transaction) => {
106
- if (transaction.startsWith("0x")) {
107
- return transaction.slice(2);
108
- }
109
- else {
110
- return transaction;
111
- }
112
- }).join("");
113
- }
114
- function createMultiSendTransaction(ethers, safeAddress, privateKey, transactions, isSafeMock = false) {
90
+ function createMultiSendTransaction(ethers, safeAddress, privateKey, transactions, chainId, nonce) {
115
91
  return __awaiter(this, void 0, void 0, function* () {
116
- const chainId = (yield ethers.provider.getNetwork()).chainId;
117
92
  const multiSendAddress = getMultiSendAddress(chainId);
118
93
  const multiSendAbi = [{ "constant": false, "inputs": [{ "internalType": "bytes", "name": "transactions", "type": "bytes" }], "name": "multiSend", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }];
119
94
  const multiSend = new ethers.Contract(multiSendAddress, new ethers.utils.Interface(multiSendAbi), ethers.provider);
120
- const safeAbi = [{ "constant": true, "inputs": [{ "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "enum Enum.Operation", "name": "operation", "type": "uint8" }, { "internalType": "uint256", "name": "safeTxGas", "type": "uint256" }, { "internalType": "uint256", "name": "baseGas", "type": "uint256" }, { "internalType": "uint256", "name": "gasPrice", "type": "uint256" }, { "internalType": "address", "name": "gasToken", "type": "address" }, { "internalType": "address", "name": "refundReceiver", "type": "address" }, { "internalType": "uint256", "name": "_nonce", "type": "uint256" }], "name": "getTransactionHash", "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], "payable": false, "stateMutability": "view", "type": "function" }];
121
- const safe = new ethers.Contract(safeAddress, new ethers.utils.Interface(safeAbi), ethers.provider);
122
- let nonce = 0;
123
- if (!isSafeMock) {
95
+ let nonceValue = 0;
96
+ if (nonce === undefined) {
124
97
  try {
125
- const nonceResponse = yield axios_1.default.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/`);
126
- nonce = nonceResponse.data.nonce;
98
+ if (process.env.NONCE) {
99
+ // NONCE variable is set
100
+ if (isNaN(Number.parseInt(process.env.NONCE))) {
101
+ // NONCE variable is not a number
102
+ if (process.env.NONCE.toLowerCase() === "pending") {
103
+ nonceValue = yield getSafeNonceWithPending(chainId, safeAddress);
104
+ }
105
+ else {
106
+ nonceValue = yield getSafeNonce(chainId, safeAddress);
107
+ }
108
+ }
109
+ else {
110
+ // NONCE variable is a number
111
+ nonceValue = Number.parseInt(process.env.NONCE);
112
+ }
113
+ }
114
+ else {
115
+ // NONCE variable is not set
116
+ nonceValue = yield getSafeNonce(chainId, safeAddress);
117
+ }
127
118
  }
128
119
  catch (e) {
129
120
  if (!(e instanceof Error) || !e.toString().startsWith("Error: Can't get safe-transaction url")) {
@@ -131,6 +122,10 @@ function createMultiSendTransaction(ethers, safeAddress, privateKey, transaction
131
122
  }
132
123
  }
133
124
  }
125
+ else {
126
+ nonceValue = nonce;
127
+ }
128
+ console.log("Will send tx to Gnosis with nonce", nonceValue);
134
129
  const tx = {
135
130
  "safe": safeAddress,
136
131
  "to": multiSend.address,
@@ -142,9 +137,9 @@ function createMultiSendTransaction(ethers, safeAddress, privateKey, transaction
142
137
  "baseGas": 0,
143
138
  "gasPrice": 0,
144
139
  "refundReceiver": ethers.constants.AddressZero,
145
- "nonce": nonce, // Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce
140
+ "nonce": nonceValue, // Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce
146
141
  };
147
- const digestHex = yield safe.getTransactionHash(tx.to, tx.value, tx.data, tx.operation, tx.safeTxGas, tx.baseGas, tx.gasPrice, tx.gasToken, tx.refundReceiver, tx.nonce);
142
+ const digestHex = getTransactionHash(tx.to, tx.value, tx.data, tx.operation, tx.safeTxGas, tx.baseGas, tx.gasPrice, tx.gasToken, tx.refundReceiver, tx.nonce, safeAddress, chainId);
148
143
  const privateKeyBuffer = ethUtil.toBuffer(privateKey);
149
144
  const { r, s, v } = ethUtil.ecsign(ethUtil.toBuffer(digestHex), privateKeyBuffer);
150
145
  const signature = ethUtil.toRpcSig(v, r, s).toString();
@@ -187,3 +182,84 @@ function sendSafeTransaction(safe, chainId, safeTx) {
187
182
  });
188
183
  }
189
184
  exports.sendSafeTransaction = sendSafeTransaction;
185
+ // private functions
186
+ function getMultiSendAddress(chainId) {
187
+ if ([Network.GANACHE, Network.HARDHAT].includes(chainId)) {
188
+ return ethers_1.ethers.constants.AddressZero;
189
+ }
190
+ else if (Object.keys(ADDRESSES.multiSend).includes(chainId.toString())) {
191
+ return ADDRESSES.multiSend[chainId];
192
+ }
193
+ else {
194
+ throw Error(`Can't get multiSend contract at network with chainId = ${chainId}`);
195
+ }
196
+ }
197
+ function concatTransactions(transactions) {
198
+ return "0x" + transactions.map((transaction) => {
199
+ if (transaction.startsWith("0x")) {
200
+ return transaction.slice(2);
201
+ }
202
+ else {
203
+ return transaction;
204
+ }
205
+ }).join("");
206
+ }
207
+ function getSafeNonce(chainId, safeAddress) {
208
+ return __awaiter(this, void 0, void 0, function* () {
209
+ const safeInfo = yield axios_1.default.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/`);
210
+ return safeInfo.data.nonce;
211
+ });
212
+ }
213
+ function getSafeNonceWithPending(chainId, safeAddress) {
214
+ return __awaiter(this, void 0, void 0, function* () {
215
+ const allTransactions = yield axios_1.default.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/all-transactions/?executed=false&queued=true&trusted=true`);
216
+ if (allTransactions.data.results.length > 0) {
217
+ return allTransactions.data.results[0].nonce + 1;
218
+ }
219
+ else {
220
+ return 0;
221
+ }
222
+ });
223
+ }
224
+ function getDomainSeparator(safeAddress, chainId) {
225
+ const DOMAIN_SEPARATOR_TYPEHASH = "0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218";
226
+ return ethers_1.ethers.utils.solidityKeccak256(["bytes"], [
227
+ ethers_1.ethers.utils.defaultAbiCoder.encode(["bytes32", "uint256", "address"], [DOMAIN_SEPARATOR_TYPEHASH, chainId, safeAddress])
228
+ ]);
229
+ }
230
+ function encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId) {
231
+ const dataHash = ethers_1.ethers.utils.solidityKeccak256(["bytes"], [data]);
232
+ const SAFE_TX_TYPEHASH = "0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8";
233
+ const encoded = ethers_1.ethers.utils.defaultAbiCoder.encode([
234
+ "bytes32",
235
+ "address",
236
+ "uint256",
237
+ "bytes32",
238
+ "uint256",
239
+ "uint256",
240
+ "uint256",
241
+ "uint256",
242
+ "address",
243
+ "address",
244
+ "uint256"
245
+ ], [
246
+ SAFE_TX_TYPEHASH,
247
+ to,
248
+ value,
249
+ dataHash,
250
+ operation,
251
+ safeTxGas,
252
+ baseGas,
253
+ gasPrice,
254
+ gasToken,
255
+ refundReceiver,
256
+ _nonce
257
+ ]);
258
+ const encodedHash = ethers_1.ethers.utils.solidityKeccak256(["bytes"], [encoded]);
259
+ return ethers_1.ethers.utils.solidityPack(["bytes1", "bytes1", "bytes32", "bytes32"], ["0x19", "0x01", getDomainSeparator(safeAddress, chainId), encodedHash]);
260
+ }
261
+ function getTransactionHash(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId) {
262
+ return ethers_1.ethers.utils.solidityKeccak256(["bytes"], [
263
+ encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId)
264
+ ]);
265
+ }
@@ -2,7 +2,7 @@ export * from "./abi";
2
2
  export * from "./deploy";
3
3
  export * from "./gnosis-safe";
4
4
  export * from "./multiSend";
5
- export * from "./upgrade";
6
- export * from "./types";
5
+ export * from "./submitters";
7
6
  export * from "./verification";
8
7
  export * from "./version";
8
+ export * from "./upgrader";
package/dist/src/index.js CHANGED
@@ -18,7 +18,7 @@ __exportStar(require("./abi"), exports);
18
18
  __exportStar(require("./deploy"), exports);
19
19
  __exportStar(require("./gnosis-safe"), exports);
20
20
  __exportStar(require("./multiSend"), exports);
21
- __exportStar(require("./upgrade"), exports);
22
- __exportStar(require("./types"), exports);
21
+ __exportStar(require("./submitters"), exports);
23
22
  __exportStar(require("./verification"), exports);
24
23
  __exportStar(require("./version"), exports);
24
+ __exportStar(require("./upgrader"), exports);
@@ -0,0 +1,11 @@
1
+ import { UnsignedTransaction } from "ethers";
2
+ import { Submitter } from "./submitter";
3
+ import { SkaleABIFile } from "../types/SkaleABIFile";
4
+ export declare class AutoSubmitter extends Submitter {
5
+ submit(transactions: UnsignedTransaction[]): Promise<void>;
6
+ _getImaAbi(): Promise<SkaleABIFile>;
7
+ _getSafeAddress(): string;
8
+ _getSchainHash(): string;
9
+ _getMainnetChainId(): number;
10
+ _versionFunctionExists(): Promise<boolean>;
11
+ }
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.AutoSubmitter = void 0;
39
+ const admin_1 = require("@openzeppelin/hardhat-upgrades/dist/admin");
40
+ const submitter_1 = require("./submitter");
41
+ const hardhat_1 = __importStar(require("hardhat"));
42
+ const eoa_submitter_1 = require("./eoa-submitter");
43
+ const safe_submitter_1 = require("./safe-submitter");
44
+ const chalk_1 = __importDefault(require("chalk"));
45
+ const safe_ima_legacy_marionette_submitter_1 = require("./safe-ima-legacy-marionette-submitter");
46
+ const fs_1 = require("fs");
47
+ const marionette_1 = require("./types/marionette");
48
+ class AutoSubmitter extends submitter_1.Submitter {
49
+ submit(transactions) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ let submitter;
52
+ const proxyAdmin = yield (0, admin_1.getManifestAdmin)(hardhat_1.default);
53
+ const owner = yield proxyAdmin.owner();
54
+ if ((yield hardhat_1.default.ethers.provider.getCode(owner)) === "0x") {
55
+ console.log("Owner is not a contract");
56
+ submitter = new eoa_submitter_1.EoaSubmitter();
57
+ }
58
+ else {
59
+ console.log("Owner is a contract");
60
+ if (hardhat_1.ethers.utils.getAddress(owner) == hardhat_1.ethers.utils.getAddress(marionette_1.MARIONETTE_ADDRESS)) {
61
+ console.log("Marionette owner is detected");
62
+ const imaAbi = yield this._getImaAbi();
63
+ const safeAddress = this._getSafeAddress();
64
+ const schainHash = this._getSchainHash();
65
+ const mainnetChainId = this._getMainnetChainId();
66
+ // TODO: after marionette has multiSend functionality
67
+ // query version and properly select a submitter
68
+ // based on it
69
+ //
70
+ // if (await this._versionFunctionExists()) {
71
+ // console.log("version() function was found. Use normal Marionette")
72
+ // submitter = new SafeImaMarionetteSubmitter(
73
+ // safeAddress,
74
+ // imaAbi,
75
+ // schainHash,
76
+ // mainnetChainId
77
+ // )
78
+ // } else {
79
+ // console.log("No version() function was found. Use legacy Marionette")
80
+ // submitter = new SafeImaLegacyMarionetteSubmitter(
81
+ // safeAddress,
82
+ // imaAbi,
83
+ // schainHash,
84
+ // mainnetChainId
85
+ // )
86
+ // }
87
+ submitter = new safe_ima_legacy_marionette_submitter_1.SafeImaLegacyMarionetteSubmitter(safeAddress, imaAbi, schainHash, mainnetChainId);
88
+ }
89
+ else {
90
+ // assuming owner is a Gnosis Safe
91
+ console.log("Using Gnosis Safe");
92
+ submitter = new safe_submitter_1.SafeSubmitter(owner);
93
+ }
94
+ }
95
+ yield submitter.submit(transactions);
96
+ });
97
+ }
98
+ // private
99
+ _getImaAbi() {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ if (!process.env.IMA_ABI) {
102
+ console.log(chalk_1.default.red("Set path to ima abi to IMA_ABI environment variable"));
103
+ process.exit(1);
104
+ }
105
+ return JSON.parse(yield fs_1.promises.readFile(process.env.IMA_ABI, "utf-8"));
106
+ });
107
+ }
108
+ _getSafeAddress() {
109
+ if (!process.env.SAFE_ADDRESS) {
110
+ console.log(chalk_1.default.red("Set Gnosis Safe owner address to SAFE_ADDRESS environment variable"));
111
+ process.exit(1);
112
+ }
113
+ return process.env.SAFE_ADDRESS;
114
+ }
115
+ _getSchainHash() {
116
+ // query Context to get schain hash
117
+ if (!process.env.SCHAIN_HASH) {
118
+ if (!process.env.SCHAIN_NAME) {
119
+ console.log(chalk_1.default.red("Set schain name to SCHAIN_NAME environment variable"));
120
+ console.log(chalk_1.default.red("or schain hash to SCHAIN_HASH environment variable"));
121
+ process.exit(1);
122
+ }
123
+ else {
124
+ return hardhat_1.ethers.utils.solidityKeccak256(["string"], [process.env.SCHAIN_NAME]);
125
+ }
126
+ }
127
+ else {
128
+ return process.env.SCHAIN_HASH;
129
+ }
130
+ }
131
+ _getMainnetChainId() {
132
+ if (!process.env.MAINNET_CHAIN_ID) {
133
+ console.log(chalk_1.default.red("Set chainId of mainnet to MAINNET_CHAIN_ID environment variable"));
134
+ console.log(chalk_1.default.red("Use 1 for Ethereum mainnet or 5 for Goerli"));
135
+ process.exit(1);
136
+ }
137
+ else {
138
+ return Number.parseInt(process.env.MAINNET_CHAIN_ID);
139
+ }
140
+ }
141
+ _versionFunctionExists() {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ const bytecode = yield hardhat_1.default.ethers.provider.getCode(marionette_1.MARIONETTE_ADDRESS);
144
+ // If the bytecode doesn't include the function selector version()
145
+ // is definitely not present
146
+ if (!bytecode.includes(hardhat_1.ethers.utils.id("version()").slice(2, 10))) {
147
+ return false;
148
+ }
149
+ const marionette = new hardhat_1.ethers.Contract(marionette_1.MARIONETTE_ADDRESS, [{
150
+ "inputs": [],
151
+ "name": "version",
152
+ "outputs": [
153
+ {
154
+ "internalType": "string",
155
+ "name": "",
156
+ "type": "string"
157
+ }
158
+ ],
159
+ "stateMutability": "view",
160
+ "type": "function"
161
+ }], hardhat_1.default.ethers.provider);
162
+ // If gas estimation doesn't revert then an execution is possible
163
+ // given the provided function selector
164
+ try {
165
+ yield marionette.estimateGas.version();
166
+ return true;
167
+ }
168
+ catch (_a) {
169
+ // Otherwise (revert) we assume that there is no entry in the jump table
170
+ // meaning that the contract doesn't include version()
171
+ return false;
172
+ }
173
+ });
174
+ }
175
+ }
176
+ exports.AutoSubmitter = AutoSubmitter;
@@ -0,0 +1,5 @@
1
+ import { UnsignedTransaction } from "ethers";
2
+ import { Submitter } from "./submitter";
3
+ export declare class EoaSubmitter extends Submitter {
4
+ submit(transactions: UnsignedTransaction[]): Promise<void>;
5
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.EoaSubmitter = void 0;
13
+ const hardhat_1 = require("hardhat");
14
+ const submitter_1 = require("./submitter");
15
+ class EoaSubmitter extends submitter_1.Submitter {
16
+ submit(transactions) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ this._atomicityWarning();
19
+ const [deployer] = yield hardhat_1.ethers.getSigners();
20
+ for (const transaction of transactions) {
21
+ console.log("Send transaction");
22
+ const response = yield deployer.sendTransaction({
23
+ to: transaction.to,
24
+ value: transaction.value,
25
+ data: transaction.data
26
+ });
27
+ console.log(`Waiting for a transaction with nonce ${response.nonce}`);
28
+ yield response.wait();
29
+ console.log("The transaction was sent");
30
+ }
31
+ });
32
+ }
33
+ }
34
+ exports.EoaSubmitter = EoaSubmitter;
@@ -0,0 +1,6 @@
1
+ export * from "./auto-submitter";
2
+ export * from "./eoa-submitter";
3
+ export * from "./safe-ima-legacy-marionette-submitter";
4
+ export * from "./safe-submitter";
5
+ export * from "./safe-to-ima-submitter";
6
+ export * from "./submitter";
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./auto-submitter"), exports);
18
+ __exportStar(require("./eoa-submitter"), exports);
19
+ __exportStar(require("./safe-ima-legacy-marionette-submitter"), exports);
20
+ __exportStar(require("./safe-submitter"), exports);
21
+ __exportStar(require("./safe-to-ima-submitter"), exports);
22
+ __exportStar(require("./submitter"), exports);
@@ -0,0 +1,6 @@
1
+ import { UnsignedTransaction } from "ethers";
2
+ import { SafeToImaSubmitter } from "./safe-to-ima-submitter";
3
+ export declare class SafeImaLegacyMarionetteSubmitter extends SafeToImaSubmitter {
4
+ marionette: import("ethers").Contract;
5
+ submit(transactions: UnsignedTransaction[]): Promise<void>;
6
+ }