@skalenetwork/upgrade-tools 2.0.0-refactor.8 → 3.0.0-skale-contracts.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/README.md +66 -11
- package/dist/hardhat.config.js +1 -0
- package/dist/src/deploy.js +44 -63
- package/dist/src/gnosis-safe.d.ts +2 -2
- package/dist/src/gnosis-safe.js +129 -103
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/submitters/auto-submitter.d.ts +7 -2
- package/dist/src/submitters/auto-submitter.js +145 -21
- package/dist/src/submitters/eoa-submitter.js +14 -25
- package/dist/src/submitters/index.d.ts +6 -0
- package/dist/src/submitters/index.js +22 -0
- package/dist/src/submitters/safe-ima-legacy-marionette-submitter.js +16 -28
- package/dist/src/submitters/safe-ima-marionette-submitter.d.ts +7 -0
- package/dist/src/submitters/safe-ima-marionette-submitter.js +66 -0
- package/dist/src/submitters/safe-submitter.js +16 -27
- package/dist/src/submitters/safe-to-ima-submitter.d.ts +6 -4
- package/dist/src/submitters/safe-to-ima-submitter.js +19 -27
- package/dist/src/submitters/types/marionette.d.ts +13 -0
- package/dist/src/submitters/types/marionette.js +4 -0
- package/dist/src/upgrader.d.ts +3 -4
- package/dist/src/upgrader.js +81 -101
- package/dist/src/verification.js +23 -36
- package/dist/src/version.js +11 -22
- package/dist/typechain-types/AccessControlEnumerableUpgradeable.d.ts +9 -9
- package/dist/typechain-types/AccessControlUpgradeable.d.ts +9 -9
- package/dist/typechain-types/AdminUpgradeabilityProxy.d.ts +14 -99
- package/dist/typechain-types/ContextUpgradeable.d.ts +3 -3
- package/dist/typechain-types/ERC165Upgradeable.d.ts +3 -3
- package/dist/typechain-types/IAccessControlEnumerableUpgradeable.d.ts +7 -7
- package/dist/typechain-types/IAccessControlUpgradeable.d.ts +7 -7
- package/dist/typechain-types/IERC165Upgradeable.d.ts +1 -1
- package/dist/typechain-types/ISafeMock.d.ts +1 -1
- package/dist/typechain-types/Initializable.d.ts +3 -3
- package/dist/typechain-types/OwnableUpgradeable.d.ts +5 -5
- package/dist/typechain-types/ProxyAdmin.d.ts +3 -3
- package/dist/typechain-types/SafeMock.d.ts +5 -5
- package/dist/typechain-types/common.d.ts +4 -4
- package/dist/typechain-types/factories/AdminUpgradeabilityProxy__factory.d.ts +2 -27
- package/dist/typechain-types/factories/AdminUpgradeabilityProxy__factory.js +1 -71
- package/dist/typechain-types/factories/ProxyAdmin__factory.d.ts +2 -2
- package/dist/typechain-types/factories/ProxyAdmin__factory.js +6 -6
- package/dist/typechain-types/factories/SafeMock__factory.d.ts +1 -1
- package/package.json +8 -7
- package/dist/src/types/SkaleABIFile.d.ts +0 -3
- package/dist/src/types/SkaleABIFile.js +0 -2
- package/dist/src/upgrade.d.ts +0 -8
- package/dist/src/upgrade.js +0 -234
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
|
|
7
|
+
To write an upgrade script extend `Upgrader` class.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
import {
|
|
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
|
-
|
|
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
|
-
- `
|
|
16
|
-
- `
|
|
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
|
package/dist/hardhat.config.js
CHANGED
package/dist/src/deploy.js
CHANGED
|
@@ -1,34 +1,21 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.getContractFactory = exports.getManifestFile = exports.getLinkedContractFactory = exports.deployLibraries = void 0;
|
|
13
4
|
const upgrades_core_1 = require("@openzeppelin/upgrades-core");
|
|
14
5
|
const hardhat_1 = require("hardhat");
|
|
15
6
|
const fs_1 = require("fs");
|
|
16
|
-
function _deployLibrary(libraryName) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return library.address;
|
|
22
|
-
});
|
|
7
|
+
async function _deployLibrary(libraryName) {
|
|
8
|
+
const Library = await hardhat_1.ethers.getContractFactory(libraryName);
|
|
9
|
+
const library = await Library.deploy();
|
|
10
|
+
await library.deployed();
|
|
11
|
+
return library.address;
|
|
23
12
|
}
|
|
24
|
-
function deployLibraries(libraryNames) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return libraries;
|
|
31
|
-
});
|
|
13
|
+
async function deployLibraries(libraryNames) {
|
|
14
|
+
const libraries = new Map();
|
|
15
|
+
for (const libraryName of libraryNames) {
|
|
16
|
+
libraries.set(libraryName, await _deployLibrary(libraryName));
|
|
17
|
+
}
|
|
18
|
+
return libraries;
|
|
32
19
|
}
|
|
33
20
|
exports.deployLibraries = deployLibraries;
|
|
34
21
|
function _linkBytecode(artifact, libraries) {
|
|
@@ -49,49 +36,43 @@ function _linkBytecode(artifact, libraries) {
|
|
|
49
36
|
}
|
|
50
37
|
return bytecode;
|
|
51
38
|
}
|
|
52
|
-
function getLinkedContractFactory(contractName, libraries) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return ContractFactory;
|
|
58
|
-
});
|
|
39
|
+
async function getLinkedContractFactory(contractName, libraries) {
|
|
40
|
+
const cArtifact = await hardhat_1.artifacts.readArtifact(contractName);
|
|
41
|
+
const linkedBytecode = _linkBytecode(cArtifact, libraries);
|
|
42
|
+
const ContractFactory = await hardhat_1.ethers.getContractFactory(cArtifact.abi, linkedBytecode);
|
|
43
|
+
return ContractFactory;
|
|
59
44
|
}
|
|
60
45
|
exports.getLinkedContractFactory = getLinkedContractFactory;
|
|
61
|
-
function getManifestFile() {
|
|
62
|
-
return
|
|
63
|
-
return (yield upgrades_core_1.Manifest.forNetwork(hardhat_1.ethers.provider)).file;
|
|
64
|
-
});
|
|
46
|
+
async function getManifestFile() {
|
|
47
|
+
return (await upgrades_core_1.Manifest.forNetwork(hardhat_1.ethers.provider)).file;
|
|
65
48
|
}
|
|
66
49
|
exports.getManifestFile = getManifestFile;
|
|
67
|
-
function getContractFactory(contract) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Object.assign(manifest, { libraries: libraryArtifacts });
|
|
91
|
-
}
|
|
92
|
-
yield fs_1.promises.writeFile(yield getManifestFile(), JSON.stringify(manifest, null, 4));
|
|
50
|
+
async function getContractFactory(contract) {
|
|
51
|
+
const { linkReferences } = await hardhat_1.artifacts.readArtifact(contract);
|
|
52
|
+
if (!Object.keys(linkReferences).length)
|
|
53
|
+
return await hardhat_1.ethers.getContractFactory(contract);
|
|
54
|
+
const libraryNames = [];
|
|
55
|
+
for (const key of Object.keys(linkReferences)) {
|
|
56
|
+
const libraryName = Object.keys(linkReferences[key])[0];
|
|
57
|
+
libraryNames.push(libraryName);
|
|
58
|
+
}
|
|
59
|
+
const libraries = await deployLibraries(libraryNames);
|
|
60
|
+
const libraryArtifacts = {};
|
|
61
|
+
for (const [libraryName, libraryAddress] of libraries.entries()) {
|
|
62
|
+
const { bytecode } = await hardhat_1.artifacts.readArtifact(libraryName);
|
|
63
|
+
libraryArtifacts[libraryName] = { "address": libraryAddress, "bytecodeHash": (0, upgrades_core_1.hashBytecode)(bytecode) };
|
|
64
|
+
}
|
|
65
|
+
let manifest;
|
|
66
|
+
try {
|
|
67
|
+
manifest = JSON.parse(await fs_1.promises.readFile(await getManifestFile(), "utf-8"));
|
|
68
|
+
Object.assign(libraryArtifacts, manifest.libraries);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
if (manifest !== undefined) {
|
|
72
|
+
Object.assign(manifest, { libraries: libraryArtifacts });
|
|
93
73
|
}
|
|
94
|
-
|
|
95
|
-
}
|
|
74
|
+
await fs_1.promises.writeFile(await getManifestFile(), JSON.stringify(manifest, null, 4));
|
|
75
|
+
}
|
|
76
|
+
return await getLinkedContractFactory(contract, libraries);
|
|
96
77
|
}
|
|
97
78
|
exports.getContractFactory = getContractFactory;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ethers } from "ethers";
|
|
2
2
|
import { HardhatEthersHelpers } from "@nomiclabs/hardhat-ethers/types";
|
|
3
|
-
|
|
3
|
+
type Ethers = typeof ethers & HardhatEthersHelpers;
|
|
4
4
|
interface SafeMultisigTransaction {
|
|
5
5
|
safe: string;
|
|
6
6
|
to: string;
|
|
@@ -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[], nonce?: number): 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 {};
|
package/dist/src/gnosis-safe.js
CHANGED
|
@@ -22,15 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
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
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
@@ -87,102 +78,99 @@ function getSafeRelayUrl(chainId) {
|
|
|
87
78
|
}
|
|
88
79
|
}
|
|
89
80
|
exports.getSafeRelayUrl = getSafeRelayUrl;
|
|
90
|
-
function createMultiSendTransaction(ethers, safeAddress, privateKey, transactions, nonce) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (isNaN(Number.parseInt(process.env.NONCE))) {
|
|
104
|
-
// NONCE variable is not a number
|
|
105
|
-
if (process.env.NONCE.toLowerCase() === "pending") {
|
|
106
|
-
nonceValue = yield getSafeNonceWithPending(chainId, safeAddress);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
nonceValue = yield getSafeNonce(chainId, safeAddress);
|
|
110
|
-
}
|
|
81
|
+
async function createMultiSendTransaction(ethers, safeAddress, privateKey, transactions, chainId, nonce) {
|
|
82
|
+
const multiSendAddress = getMultiSendAddress(chainId);
|
|
83
|
+
const multiSendAbi = [{ "constant": false, "inputs": [{ "internalType": "bytes", "name": "transactions", "type": "bytes" }], "name": "multiSend", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }];
|
|
84
|
+
const multiSend = new ethers.Contract(multiSendAddress, new ethers.utils.Interface(multiSendAbi), ethers.provider);
|
|
85
|
+
let nonceValue = 0;
|
|
86
|
+
if (nonce === undefined) {
|
|
87
|
+
try {
|
|
88
|
+
if (process.env.NONCE) {
|
|
89
|
+
// NONCE variable is set
|
|
90
|
+
if (isNaN(Number.parseInt(process.env.NONCE))) {
|
|
91
|
+
// NONCE variable is not a number
|
|
92
|
+
if (process.env.NONCE.toLowerCase() === "pending") {
|
|
93
|
+
nonceValue = await getSafeNonceWithPending(chainId, safeAddress);
|
|
111
94
|
}
|
|
112
95
|
else {
|
|
113
|
-
|
|
114
|
-
nonceValue = Number.parseInt(process.env.NONCE);
|
|
96
|
+
nonceValue = await getSafeNonce(chainId, safeAddress);
|
|
115
97
|
}
|
|
116
98
|
}
|
|
117
99
|
else {
|
|
118
|
-
// NONCE variable is
|
|
119
|
-
nonceValue =
|
|
100
|
+
// NONCE variable is a number
|
|
101
|
+
nonceValue = Number.parseInt(process.env.NONCE);
|
|
120
102
|
}
|
|
121
103
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
104
|
+
else {
|
|
105
|
+
// NONCE variable is not set
|
|
106
|
+
nonceValue = await getSafeNonce(chainId, safeAddress);
|
|
126
107
|
}
|
|
127
108
|
}
|
|
128
|
-
|
|
129
|
-
|
|
109
|
+
catch (e) {
|
|
110
|
+
if (!(e instanceof Error) || !e.toString().startsWith("Error: Can't get safe-transaction url")) {
|
|
111
|
+
throw e;
|
|
112
|
+
}
|
|
130
113
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
nonceValue = nonce;
|
|
117
|
+
}
|
|
118
|
+
console.log("Will send tx to Gnosis with nonce", nonceValue);
|
|
119
|
+
const tx = {
|
|
120
|
+
"safe": safeAddress,
|
|
121
|
+
"to": multiSend.address,
|
|
122
|
+
"value": 0,
|
|
123
|
+
"data": multiSend.interface.encodeFunctionData("multiSend", [concatTransactions(transactions)]),
|
|
124
|
+
"operation": 1,
|
|
125
|
+
"gasToken": ethers.constants.AddressZero,
|
|
126
|
+
"safeTxGas": 0,
|
|
127
|
+
"baseGas": 0,
|
|
128
|
+
"gasPrice": 0,
|
|
129
|
+
"refundReceiver": ethers.constants.AddressZero,
|
|
130
|
+
"nonce": nonceValue, // Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce
|
|
131
|
+
};
|
|
132
|
+
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);
|
|
133
|
+
const privateKeyBuffer = ethUtil.toBuffer(privateKey);
|
|
134
|
+
const { r, s, v } = ethUtil.ecsign(ethUtil.toBuffer(digestHex), privateKeyBuffer);
|
|
135
|
+
const signature = ethUtil.toRpcSig(v, r, s).toString();
|
|
136
|
+
const txToSend = {
|
|
137
|
+
...tx,
|
|
138
|
+
"contractTransactionHash": digestHex,
|
|
139
|
+
// Owner of the Safe proposing the transaction. Must match one of the signatures
|
|
140
|
+
"sender": ethers.utils.getAddress(ethUtil.bufferToHex(ethUtil.privateToAddress(privateKeyBuffer))),
|
|
141
|
+
"signature": signature,
|
|
142
|
+
"origin": "Upgrade skale-manager" // Give more information about the transaction, e.g. "My Custom Safe app"
|
|
143
|
+
};
|
|
144
|
+
return txToSend;
|
|
155
145
|
}
|
|
156
146
|
exports.createMultiSendTransaction = createMultiSendTransaction;
|
|
157
|
-
function sendSafeTransaction(safe, chainId, safeTx) {
|
|
158
|
-
|
|
147
|
+
async function sendSafeTransaction(safe, chainId, safeTx) {
|
|
148
|
+
try {
|
|
149
|
+
console.log("Estimate gas");
|
|
150
|
+
const estimateRequest = safeTx;
|
|
159
151
|
try {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const estimateResponse = yield axios_1.default.post(`${getSafeRelayUrl(chainId)}/api/v2/safes/${safe}/transactions/estimate/`, estimateRequest);
|
|
164
|
-
console.log(chalk_1.default.cyan(`Recommend to set gas limit to ${parseInt(estimateResponse.data.safeTxGas, 10) + parseInt(estimateResponse.data.baseGas, 10)}`));
|
|
165
|
-
}
|
|
166
|
-
catch (e) {
|
|
167
|
-
console.log(chalk_1.default.red("Failed to estimate gas"));
|
|
168
|
-
console.log(e);
|
|
169
|
-
}
|
|
170
|
-
console.log(chalk_1.default.green("Send transaction to gnosis safe"));
|
|
171
|
-
yield axios_1.default.post(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safe}/multisig-transactions/`, safeTx);
|
|
152
|
+
const estimateResponse = await axios_1.default.post(`${getSafeRelayUrl(chainId)}/api/v2/safes/${safe}/transactions/estimate/`, estimateRequest);
|
|
153
|
+
console.log(chalk_1.default.cyan(`Recommend to set gas limit to ${parseInt(estimateResponse.data.safeTxGas, 10) + parseInt(estimateResponse.data.baseGas, 10)}`));
|
|
172
154
|
}
|
|
173
155
|
catch (e) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
156
|
+
console.log(chalk_1.default.red("Failed to estimate gas"));
|
|
157
|
+
console.log(e);
|
|
158
|
+
}
|
|
159
|
+
console.log(chalk_1.default.green("Send transaction to gnosis safe"));
|
|
160
|
+
await axios_1.default.post(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safe}/multisig-transactions/`, safeTx);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
if (axios_1.default.isAxiosError(e)) {
|
|
164
|
+
if (e.response) {
|
|
165
|
+
console.log(JSON.stringify(e.response.data, null, 4));
|
|
166
|
+
console.log(chalk_1.default.red(`Request failed with ${e.response.status} code`));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.log(chalk_1.default.red("Request failed with unknown reason"));
|
|
182
170
|
}
|
|
183
|
-
throw e;
|
|
184
171
|
}
|
|
185
|
-
|
|
172
|
+
throw e;
|
|
173
|
+
}
|
|
186
174
|
}
|
|
187
175
|
exports.sendSafeTransaction = sendSafeTransaction;
|
|
188
176
|
// private functions
|
|
@@ -207,20 +195,58 @@ function concatTransactions(transactions) {
|
|
|
207
195
|
}
|
|
208
196
|
}).join("");
|
|
209
197
|
}
|
|
210
|
-
function getSafeNonce(chainId, safeAddress) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return safeInfo.data.nonce;
|
|
214
|
-
});
|
|
198
|
+
async function getSafeNonce(chainId, safeAddress) {
|
|
199
|
+
const safeInfo = await axios_1.default.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/`);
|
|
200
|
+
return safeInfo.data.nonce;
|
|
215
201
|
}
|
|
216
|
-
function getSafeNonceWithPending(chainId, safeAddress) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
202
|
+
async function getSafeNonceWithPending(chainId, safeAddress) {
|
|
203
|
+
const allTransactions = await axios_1.default.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/all-transactions/?executed=false&queued=true&trusted=true`);
|
|
204
|
+
if (allTransactions.data.results.length > 0) {
|
|
205
|
+
return allTransactions.data.results[0].nonce + 1;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function getDomainSeparator(safeAddress, chainId) {
|
|
212
|
+
const DOMAIN_SEPARATOR_TYPEHASH = "0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218";
|
|
213
|
+
return ethers_1.ethers.utils.solidityKeccak256(["bytes"], [
|
|
214
|
+
ethers_1.ethers.utils.defaultAbiCoder.encode(["bytes32", "uint256", "address"], [DOMAIN_SEPARATOR_TYPEHASH, chainId, safeAddress])
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
function encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId) {
|
|
218
|
+
const dataHash = ethers_1.ethers.utils.solidityKeccak256(["bytes"], [data]);
|
|
219
|
+
const SAFE_TX_TYPEHASH = "0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8";
|
|
220
|
+
const encoded = ethers_1.ethers.utils.defaultAbiCoder.encode([
|
|
221
|
+
"bytes32",
|
|
222
|
+
"address",
|
|
223
|
+
"uint256",
|
|
224
|
+
"bytes32",
|
|
225
|
+
"uint256",
|
|
226
|
+
"uint256",
|
|
227
|
+
"uint256",
|
|
228
|
+
"uint256",
|
|
229
|
+
"address",
|
|
230
|
+
"address",
|
|
231
|
+
"uint256"
|
|
232
|
+
], [
|
|
233
|
+
SAFE_TX_TYPEHASH,
|
|
234
|
+
to,
|
|
235
|
+
value,
|
|
236
|
+
dataHash,
|
|
237
|
+
operation,
|
|
238
|
+
safeTxGas,
|
|
239
|
+
baseGas,
|
|
240
|
+
gasPrice,
|
|
241
|
+
gasToken,
|
|
242
|
+
refundReceiver,
|
|
243
|
+
_nonce
|
|
244
|
+
]);
|
|
245
|
+
const encodedHash = ethers_1.ethers.utils.solidityKeccak256(["bytes"], [encoded]);
|
|
246
|
+
return ethers_1.ethers.utils.solidityPack(["bytes1", "bytes1", "bytes32", "bytes32"], ["0x19", "0x01", getDomainSeparator(safeAddress, chainId), encodedHash]);
|
|
247
|
+
}
|
|
248
|
+
function getTransactionHash(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId) {
|
|
249
|
+
return ethers_1.ethers.utils.solidityKeccak256(["bytes"], [
|
|
250
|
+
encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce, safeAddress, chainId)
|
|
251
|
+
]);
|
|
226
252
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -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 "./
|
|
5
|
+
export * from "./submitters";
|
|
6
6
|
export * from "./verification";
|
|
7
7
|
export * from "./version";
|
|
8
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("./
|
|
21
|
+
__exportStar(require("./submitters"), exports);
|
|
22
22
|
__exportStar(require("./verification"), exports);
|
|
23
23
|
__exportStar(require("./version"), exports);
|
|
24
24
|
__exportStar(require("./upgrader"), exports);
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Transaction } from "ethers";
|
|
2
2
|
import { Submitter } from "./submitter";
|
|
3
3
|
export declare class AutoSubmitter extends Submitter {
|
|
4
|
-
submit(transactions:
|
|
4
|
+
submit(transactions: Transaction[]): Promise<void>;
|
|
5
|
+
_getImaInstance(): Promise<import("@skalenetwork/skale-contracts").Instance>;
|
|
6
|
+
_getSafeAddress(): string;
|
|
7
|
+
_getSchainHash(): string;
|
|
8
|
+
_getMainnetChainId(): number;
|
|
9
|
+
_versionFunctionExists(): Promise<boolean>;
|
|
5
10
|
}
|