@arcblock/erc721did-contract 0.2.5 → 0.3.1

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 CHANGED
@@ -1,13 +1,13 @@
1
- ## ArcBridge Contracts
1
+ ## ERC721DID Contracts
2
2
 
3
- Solidity contracts that powers ArcBridge.
3
+ Solidity contracts that powers ERC721DID.
4
4
 
5
5
  ### How to Deploy
6
6
 
7
7
  0. create dotenv file
8
8
  1. (optional) deploy token
9
- 2. deploy multisig library
10
- 3. deploy rollup contract
9
+ 2. deploy parent contract
10
+ 3. deploy factory contract
11
11
 
12
12
  ### FAQ
13
13
 
@@ -15,7 +15,13 @@ Solidity contracts that powers ArcBridge.
15
15
 
16
16
  ### Getting Started
17
17
 
18
- 如果是本地开发环境,需要修改 src/library/ERC20Token.sol,替换其中的 TokenSymbol 为 DEV,然后再部署
18
+ 如果是本地开发环境,需要复制 .env_example 新建 .env.local,提供里面的环境变量。
19
+
20
+ #### Install
21
+
22
+ ```bash
23
+ pnpm i
24
+ ```
19
25
 
20
26
  #### Cleanup
21
27
 
@@ -25,28 +31,34 @@ Solidity contracts that powers ArcBridge.
25
31
  rm -rf deployments
26
32
  ```
27
33
 
28
- #### Deploy ERC20Token
34
+ #### Deploy ERC721DID Parent Contract + ERC721DID Factory Contract
29
35
 
30
- > Will update .env.dev.tba
36
+ > Will update .env
31
37
 
32
38
  ```bash
33
- NODE_ENV=dev.tba npm run deploy -- --network goerli --tags token
39
+ # deploy goerli
40
+ npm run deploy -- --network goerli --tags deploy
41
+ # deploy base-goerli
42
+ npm run deploy -- --network base-goerli --tags deploy
43
+ # deploy bsc-test
44
+ npm run deploy -- --network bsc-test --tags deploy
45
+
46
+ # generate lib
47
+ npm run copy-to-lib
34
48
  ```
35
49
 
36
- #### Deploy MultiSig
50
+ #### Dev ERC721DID Parent Contract + ERC721DID Factory Contract
37
51
 
38
- > Will update .env.dev.tba
52
+ > Will update .env.local
39
53
 
40
54
  ```bash
41
- NODE_ENV=dev.tba npm run deploy -- --network goerli --tags multisig
42
- ```
43
-
44
- #### Deploy ERC20Rollup
55
+ # bash 1
56
+ npm run node
45
57
 
46
- > Please remember to set `MIGRATED_FROM` and `MIN_SIGNER_COUNT` before deploy.
58
+ # bash 2
59
+ npm run dev
47
60
 
48
- ```bash
49
- NODE_ENV=dev.tba npm run deploy -- --network goerli --tags rollup
61
+ # bash 3 if you want to deploy or test
62
+ npm run deploy:local
63
+ npm run test:local
50
64
  ```
51
-
52
- Then you are all set on ethereum.
@@ -0,0 +1,50 @@
1
+ [
2
+ {
3
+ "chainId": "5",
4
+ "chainName": "Goerli",
5
+ "contractFactoryAddress": "0x8bE1AE46848232C5fD6A08A7bDfcD177daFb8A88",
6
+ "isTest": true,
7
+ "networkName": "goerli",
8
+ "symbol": "ETH (Goerli)",
9
+ "defaultRPC": "https://goerli.infura.io/v3/31276ea517a941c5b91d914fab83494e",
10
+ "explorer": "https://goerli.etherscan.io",
11
+ "icon": "eth",
12
+ "enable": true
13
+ },
14
+ {
15
+ "chainId": "84531",
16
+ "chainName": "Base Goerli",
17
+ "contractFactoryAddress": "0xD462A649154693610F6A46258848e9C338fb7Eb3",
18
+ "isTest": true,
19
+ "networkName": "base-goerli",
20
+ "symbol": "ETH (Base Goerli)",
21
+ "defaultRPC": "https://goerli.base.org",
22
+ "explorer": "https://goerli.basescan.org",
23
+ "icon": "base",
24
+ "enable": true
25
+ },
26
+ {
27
+ "chainId": "11155111",
28
+ "chainName": "Sepolia",
29
+ "contractFactoryAddress": "0xA44112bA00F1a4bc20374C99EC9547C6FA925db7",
30
+ "isTest": true,
31
+ "networkName": "sepolia",
32
+ "symbol": "ETH (Sepolia)",
33
+ "defaultRPC": "https://sepolia.infura.io/v3/31276ea517a941c5b91d914fab83494e",
34
+ "explorer": "https://sepolia.etherscan.io",
35
+ "icon": "eth",
36
+ "enable": false
37
+ },
38
+ {
39
+ "chainId": "97",
40
+ "chainName": "BNB (Binance Smart Chain)",
41
+ "contractFactoryAddress": "0xA44112bA00F1a4bc20374C99EC9547C6FA925db7",
42
+ "isTest": true,
43
+ "networkName": "bsc-test",
44
+ "symbol": "BNB",
45
+ "defaultRPC": "https://bsc.getblock.io/13042277-cdaa-47dc-acda-5a0900eaf4ae/testnet",
46
+ "explorer": "https://testnet.bscscan.com",
47
+ "icon": "bnb",
48
+ "enable": true
49
+ }
50
+ ]
package/lib/contract.js CHANGED
@@ -4,29 +4,97 @@ require('dotenv-flow').config();
4
4
  const ethers = require('ethers');
5
5
  const axios = require('axios');
6
6
  const waitFor = require('p-wait-for');
7
- const { toBase58, toBN } = require('@ocap/util');
7
+ const { toBase58 } = require('@ocap/util');
8
8
  const upperFirst = require('lodash/upperFirst');
9
+ const keyBy = require('lodash/keyBy');
9
10
  const ERC721DID = require('./ERC721DID.json');
10
11
  const ERC721DIDFactory = require('./ERC721DIDFactory.json');
11
12
 
12
13
  const { INFURA_PROJECT_ID } = process.env;
13
14
 
14
- function getDefaultProvider(isLocal = false) {
15
- return isLocal
16
- ? new ethers.providers.JsonRpcProvider('http://localhost:8545')
17
- : new ethers.providers.InfuraProvider('goerli', INFURA_PROJECT_ID);
15
+ const CHAIN_MAP = {
16
+ 1: {
17
+ networkName: 'mainnet',
18
+ chainName: 'Ethereum Mainnet',
19
+ chainId: '1',
20
+ symbol: 'ETH',
21
+ defaultRPC: `https://mainnet.infura.io/v3/${INFURA_PROJECT_ID}`,
22
+ explorer: 'https://etherscan.io',
23
+ icon: 'eth',
24
+ enable: true,
25
+ },
26
+ 5: {
27
+ networkName: 'goerli',
28
+ chainName: 'Goerli',
29
+ chainId: '5',
30
+ symbol: 'ETH (Goerli)',
31
+ defaultRPC: `https://goerli.infura.io/v3/${INFURA_PROJECT_ID}`,
32
+ explorer: 'https://goerli.etherscan.io',
33
+ icon: 'eth',
34
+ enable: true,
35
+ },
36
+ 31337: {
37
+ networkName: 'localhost',
38
+ chainName: 'Localhost',
39
+ chainId: '31337',
40
+ symbol: 'ETH (Localhost)',
41
+ defaultRPC: 'http://localhost:8545',
42
+ explorer: 'http://localhost:8545',
43
+ icon: 'eth',
44
+ enable: true,
45
+ },
46
+ 84531: {
47
+ networkName: 'base-goerli',
48
+ chainName: 'Base Goerli',
49
+ chainId: '84531',
50
+ symbol: 'ETH (Base Goerli)',
51
+ defaultRPC: 'https://goerli.base.org',
52
+ explorer: 'https://goerli.basescan.org',
53
+ icon: 'base',
54
+ enable: true,
55
+ },
56
+ 11155111: {
57
+ networkName: 'sepolia',
58
+ chainName: 'Sepolia',
59
+ chainId: '11155111',
60
+ symbol: 'ETH (Sepolia)',
61
+ defaultRPC: `https://sepolia.infura.io/v3/${INFURA_PROJECT_ID}`,
62
+ explorer: 'https://sepolia.etherscan.io',
63
+ icon: 'eth',
64
+ enable: false, // FIXME
65
+ },
66
+ 97: {
67
+ networkName: 'bsc-test',
68
+ chainName: 'BNB (Binance Smart Chain)',
69
+ chainId: '97',
70
+ symbol: 'BNB',
71
+ defaultRPC: 'https://bsc.getblock.io/13042277-cdaa-47dc-acda-5a0900eaf4ae/testnet',
72
+ explorer: 'https://testnet.bscscan.com',
73
+ icon: 'bnb',
74
+ enable: true,
75
+ },
76
+ };
77
+
78
+ const CUSTOM_CHAIN_MAP = {};
79
+
80
+ let isLocal = false;
81
+
82
+ function getProvider(chainId) {
83
+ const { defaultRPC } = getChainInfo(chainId);
84
+
85
+ return new ethers.providers.JsonRpcProvider(defaultRPC);
18
86
  }
19
87
 
20
- async function getContract({ contractAddress, isLocal = false, signer } = {}) {
21
- const provider = getDefaultProvider(isLocal);
88
+ async function getContract({ contractAddress, chainId, signer } = {}) {
89
+ const provider = getProvider(chainId);
22
90
 
23
91
  const contract = new ethers.Contract(contractAddress, ERC721DID.abi, signer || provider);
24
92
 
25
93
  return contract;
26
94
  }
27
95
 
28
- async function getContractFactory({ contractAddress, isLocal = false, signer } = {}) {
29
- const provider = getDefaultProvider(isLocal);
96
+ async function getContractFactory({ contractAddress, chainId, signer } = {}) {
97
+ const provider = getProvider(chainId);
30
98
 
31
99
  const contract = new ethers.Contract(contractAddress, ERC721DIDFactory.abi, signer || provider);
32
100
 
@@ -36,21 +104,21 @@ async function getContractFactory({ contractAddress, isLocal = false, signer } =
36
104
  async function getGasPrice({ provider }) {
37
105
  const gwei = 1000000000;
38
106
 
39
- const networkId = await getNetworkId({ contract });
107
+ const chainId = await getChainId({ contract });
40
108
 
41
109
  // ethereum
42
- if ([1, '1', 'mainnet', 'eth-main'].includes(networkId)) {
43
- const { data } = await axios.get(`https://token-data.arcblock.io/api/gas-prices?chainId=${networkId}`);
110
+ if ([1, '1', 'mainnet', 'eth-main'].includes(chainId)) {
111
+ const { data } = await axios.get(`https://token-data.arcblock.io/api/gas-prices?chainId=${chainId}`);
44
112
  return (data.fast / 10) * gwei;
45
113
  }
46
114
 
47
- if ([5, '5', 'goerli', 'eth-goerli'].includes(networkId)) {
115
+ if ([5, '5', 'goerli', 'eth-goerli'].includes(chainId)) {
48
116
  const { gasPrice } = await provider.getFeeData();
49
117
  return gasPrice.toString();
50
118
  }
51
119
 
52
120
  // hardhat
53
- if ([31337, '31337', 'hardhat'].includes(networkId)) {
121
+ if ([31337, '31337', 'hardhat'].includes(chainId)) {
54
122
  return 1 * gwei;
55
123
  }
56
124
 
@@ -65,7 +133,7 @@ async function getTxData(params = {}) {
65
133
  const { contract, fn, args } = params;
66
134
  const txData = contract.interface.encodeFunctionData(fn, args);
67
135
 
68
- const networkId = await getNetworkId({ contract });
136
+ const chainId = await getChainId({ contract });
69
137
 
70
138
  // const gasPrice = await getGasPrice({ provider: contract.provider });
71
139
  // const gasPriceAsGwei = Math.ceil(ethers.utils.formatUnits(gasPrice, 'gwei').toString());
@@ -80,7 +148,7 @@ async function getTxData(params = {}) {
80
148
  return toBase58(
81
149
  Buffer.from(
82
150
  JSON.stringify({
83
- network: networkId,
151
+ network: chainId,
84
152
  tx: {
85
153
  to: contract.address,
86
154
  value: '0',
@@ -141,41 +209,53 @@ const onContractFilter = async ({ contract, fn, onSuccess }) => {
141
209
  );
142
210
  };
143
211
 
144
- const getNetworkId = async ({ contract }) => {
145
- const networkId = await contract.provider.getNetwork().then((res) => res.chainId);
146
- return networkId;
212
+ // @private
213
+ const getChainIdByChainName = (chainName) => {
214
+ return keyBy(
215
+ {
216
+ ...CHAIN_MAP,
217
+ ...CUSTOM_CHAIN_MAP,
218
+ },
219
+ 'networkName'
220
+ )[chainName].chainId;
147
221
  };
148
222
 
149
- const getNetworkName = (networkId) => {
150
- const networkIdString = `${networkId}`;
151
- switch (networkIdString) {
152
- case '1':
153
- return 'mainnet';
154
- case '3':
155
- return 'ropsten';
156
- case '4':
157
- return 'rinkeby';
158
- case '5':
159
- return 'goerli';
160
- case '42':
161
- return 'kovan';
162
- case '31337':
163
- return 'hardhat';
164
- default:
165
- return 'unknown';
166
- }
223
+ const getChainId = async ({ contract }) => {
224
+ const chainId = await contract.provider.getNetwork().then((res) => res.chainId);
225
+ return `${chainId}`;
226
+ };
227
+
228
+ const setupContractEnv = ({ customEvmChainList, isLocal: _isLocal = false }) => {
229
+ customEvmChainList.forEach((chain) => {
230
+ const { chainId } = chain;
231
+ CUSTOM_CHAIN_MAP[chainId] = chain;
232
+ });
233
+ isLocal = _isLocal;
167
234
  };
168
235
 
169
- const getAddressExplorerUrl = ({ networkId, hash }) => {
170
- return `https://${getNetworkName(networkId)}.etherscan.io/address/${hash}`;
236
+ const getChainInfo = (chainId) => {
237
+ return {
238
+ ...CHAIN_MAP[chainId],
239
+ ...CUSTOM_CHAIN_MAP[chainId],
240
+ };
171
241
  };
172
242
 
173
- const getBlockExplorerUrl = ({ networkId, blockletNumber }) => {
174
- return `https://${getNetworkName(networkId)}.etherscan.io/block/${blockletNumber}`;
243
+ const getExplorerUrl = (chainId) => {
244
+ const { explorer } = getChainInfo(chainId);
245
+
246
+ return `${explorer}`;
247
+ };
248
+
249
+ const getAddressExplorerUrl = ({ chainId, hash }) => {
250
+ return `${getExplorerUrl(chainId)}/address/${hash}`;
251
+ };
252
+
253
+ const getBlockExplorerUrl = ({ chainId, blockletNumber }) => {
254
+ return `${getExplorerUrl(chainId)}/block/${blockletNumber}`;
175
255
  };
176
256
 
177
- const getTxExplorerUrl = ({ networkId, hash }) => {
178
- return `https://${getNetworkName(networkId)}.etherscan.io/tx/${hash}`;
257
+ const getTxExplorerUrl = ({ chainId, hash }) => {
258
+ return `${getExplorerUrl(chainId)}/tx/${hash}`;
179
259
  };
180
260
 
181
261
  const getCloneContractArgs = ({
@@ -190,6 +270,38 @@ const getCloneContractArgs = ({
190
270
  return params;
191
271
  };
192
272
 
273
+ const getEvmChainList = () => {
274
+ try {
275
+ // eslint-disable-next-line global-require
276
+ let defaultChainList = require('./EvmChainList.json');
277
+ if (isLocal) {
278
+ defaultChainList = [
279
+ ...defaultChainList,
280
+ // eslint-disable-next-line global-require
281
+ ...require('./EvmChainList.local.json'),
282
+ ];
283
+ }
284
+ // CUSTOM_CHAIN_MAP is setup by setupContractEnv
285
+ if (Object.keys(CUSTOM_CHAIN_MAP).length > 0) {
286
+ defaultChainList = defaultChainList.map((item) => {
287
+ const { chainId } = item;
288
+ if (CUSTOM_CHAIN_MAP[chainId]) {
289
+ // override
290
+ return {
291
+ ...item,
292
+ ...CUSTOM_CHAIN_MAP[chainId],
293
+ };
294
+ }
295
+ return item;
296
+ });
297
+ }
298
+ return defaultChainList;
299
+ } catch (error) {
300
+ // do nothing
301
+ }
302
+ return [];
303
+ };
304
+
193
305
  module.exports = {
194
306
  getContract,
195
307
  getContractFactory,
@@ -197,10 +309,13 @@ module.exports = {
197
309
  getGasPrice,
198
310
  waitForTxReceipt,
199
311
  onContractFilter,
200
- getNetworkId,
201
- getNetworkName,
312
+ getChainId,
313
+ getChainInfo,
202
314
  getBlockExplorerUrl,
203
315
  getTxExplorerUrl,
204
316
  getAddressExplorerUrl,
205
317
  getCloneContractArgs,
318
+ getEvmChainList,
319
+ setupContractEnv,
320
+ getChainIdByChainName,
206
321
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.5",
6
+ "version": "0.3.1",
7
7
  "main": "./lib",
8
8
  "module": "./lib",
9
9
  "typings": "./lib",
@@ -23,13 +23,13 @@
23
23
  "devDependencies": {
24
24
  "@arcblock/eslint-config-base": "^0.2.3",
25
25
  "@nomiclabs/hardhat-ethers": "^2.2.3",
26
- "@nomiclabs/hardhat-waffle": "^2.0.5",
26
+ "@nomiclabs/hardhat-waffle": "^2.0.6",
27
27
  "@ocap/mcrypto": "1.18.34",
28
28
  "@ocap/merkle-tree": "1.18.34",
29
29
  "@ocap/wallet": "1.18.34",
30
- "@openzeppelin/contracts": "^4.8.3",
30
+ "@openzeppelin/contracts": "^4.9.0",
31
31
  "@types/mocha": "^10.0.1",
32
- "@types/node": "^18.15.11",
32
+ "@types/node": "^18.16.14",
33
33
  "chai": "^4.3.7",
34
34
  "dotenv-flow": "^3.2.0",
35
35
  "envfile": "^6.18.0",
@@ -38,35 +38,35 @@
38
38
  "ethereumjs-util": "^7.1.5",
39
39
  "ethereumjs-wallet": "^1.0.2",
40
40
  "hardhat": "^2.14.0",
41
- "hardhat-contract-sizer": "^2.8.0",
41
+ "hardhat-contract-sizer": "^2.9.0",
42
42
  "hardhat-deploy": "^0.9.29",
43
43
  "hardhat-gas-reporter": "^1.0.9",
44
- "prettier": "^2.8.7",
44
+ "prettier": "^2.8.8",
45
45
  "solidity-coverage": "^0.7.22",
46
- "web3": "^1.9.0",
47
- "web3-utils": "^1.9.0"
46
+ "web3": "^1.10.0",
47
+ "web3-utils": "^1.10.0"
48
48
  },
49
49
  "dependencies": {
50
- "axios": "^1.3.5",
51
- "eslint": "^8.38.0",
52
- "p-wait-for": "^3.2.0",
53
- "ethers": "^5.7.2",
54
50
  "@ocap/util": "1.18.34",
55
- "lodash": "^4.17.21"
51
+ "axios": "^1.4.0",
52
+ "eslint": "^8.41.0",
53
+ "ethers": "^5.7.2",
54
+ "lodash": "^4.17.21",
55
+ "p-wait-for": "^3.2.0"
56
56
  },
57
57
  "scripts": {
58
- "deploy": "hardhat deploy",
59
58
  "copy-to-lib": "node tools/copy-to-lib.js",
60
59
  "lint": "eslint tests tools lib",
61
60
  "test": "hardhat test",
62
- "test:local": "hardhat test --network localhost",
61
+ "test:local": "NODE_ENV=local hardhat test --network localhost",
62
+ "deploy": "hardhat deploy",
63
63
  "deploy:local": "NODE_ENV=local hardhat deploy --network localhost",
64
64
  "clean": "hardhat clean",
65
65
  "publish:contracts": "hardhat compile",
66
66
  "compile": "hardhat compile",
67
67
  "coverage": "hardhat coverage",
68
68
  "codesize": "hardhat size-contracts",
69
- "node": "hardhat node",
70
- "dev": "nodemon --exec 'npm run copy-to-lib' --ignore 'lib/*'"
69
+ "node": "ps -ef | grep hardhat | grep -v grep | awk '{print $2}' | xargs kill -9 && hardhat node",
70
+ "dev": "NODE_ENV=local nodemon --exec 'npm run copy-to-lib' --ignore 'lib/*' --ignore 'tools/*.json'"
71
71
  }
72
72
  }
package/lib/helper.js DELETED
@@ -1,216 +0,0 @@
1
- /* eslint-disable no-await-in-loop */
2
- const fs = require('fs');
3
- const assert = require('assert');
4
- const path = require('path');
5
- const pick = require('lodash/pick');
6
- const Web3 = require('web3');
7
- const crypto = require('crypto');
8
- const random = require('lodash/random');
9
- const chunk = require('lodash/chunk');
10
- const bip39 = require('ethereum-cryptography/bip39');
11
- const wallet = require('ethereumjs-wallet');
12
- const MerkleTree = require('@ocap/merkle-tree');
13
- const Mcrypto = require('@ocap/mcrypto');
14
- const { hexToBytes } = require('web3-utils');
15
- const { ethers } = require('hardhat');
16
- const { parse, stringify } = require('envfile');
17
-
18
- const BLACK_HOLE = '0x0000000000000000000000000000000000000000';
19
-
20
- const keccak256 = Mcrypto.Hasher.Keccak.hash256;
21
-
22
- const web3 = new Web3();
23
-
24
- // prepare accounts
25
- const HD_MNEMONIC = 'test test test test test test test test test test test junk';
26
- const HD_DERIVE_PATH = "m/44'/60'/0'/0/";
27
- const hdwallet = wallet.hdkey.fromMasterSeed(bip39.mnemonicToSeedSync(HD_MNEMONIC));
28
- const accounts = {};
29
- const names = [
30
- 'deployer',
31
- 'seed1',
32
- 'seed2',
33
- 'validator1',
34
- 'validator2',
35
- 'user1',
36
- 'user2',
37
- 'user3',
38
- 'user4',
39
- 'vault',
40
- 'vault2',
41
- ];
42
- for (let i = 0; i < names.length; i++) {
43
- const { privateKey } = hdwallet.derivePath(HD_DERIVE_PATH + i).getWallet();
44
- const account = web3.eth.accounts.privateKeyToAccount(web3.utils.toHex(privateKey));
45
- account.index = i;
46
- account.name = names[i];
47
- accounts[names[i]] = account;
48
- accounts[account.address] = account;
49
- }
50
- const seedValidators = [accounts.seed1.address, accounts.seed2.address];
51
- const seedSigners = [accounts.seed1, accounts.seed2];
52
-
53
- // prepare singers
54
- const getSingers = async () => {
55
- const signers = await ethers.getSigners();
56
-
57
- const getSigner = (name) => signers.find((x) => x.address === accounts[name].address) || signers[0];
58
-
59
- return { signers, getSigner };
60
- };
61
-
62
- // prepare contracts
63
- const getContracts = async ({ deployArgsMap = {} } = {}) => {
64
- const ERC721DIDParentContract = await ethers.getContractFactory('ERC721DID');
65
- const ERC721DIDParent = await ERC721DIDParentContract.deploy(...(deployArgsMap?.ERC721DIDParent || []));
66
-
67
- const ERC721DIDFactoryContract = await ethers.getContractFactory('ERC721DIDFactory');
68
- const ERC721DIDFactory = await ERC721DIDFactoryContract.deploy(
69
- ...(deployArgsMap?.ERC721DIDFactory || [ERC721DIDParent.address])
70
- );
71
-
72
- return { ERC721DIDParent, ERC721DIDFactory };
73
- };
74
-
75
- const getSignatures = (message, signers = seedSigners, nonces = {}, forceInvalid = false) =>
76
- signers.map((x) => {
77
- const nonce = nonces[x.address] || 0;
78
- const encoded = MerkleTree.encodePacked({ type: 'uint256', value: nonce }, { type: 'bytes32', value: message });
79
- return {
80
- signer: x.address,
81
- signature: hexToBytes(
82
- web3.eth.accounts.sign(forceInvalid ? encoded : keccak256(encoded), x.privateKey).signature
83
- ),
84
- nonce,
85
- };
86
- });
87
-
88
- const getTxHash = (size = 32) => `0x${crypto.randomBytes(size).toString('hex').toUpperCase()}`;
89
-
90
- const getUser = () => {
91
- const users = ['user1', 'user2', 'user3', 'user4'];
92
- return accounts[users[random(0, users.length - 1)]];
93
- };
94
-
95
- const getTx = (account, type, amount) => ({
96
- type,
97
- hash: getTxHash(),
98
- to: account.address,
99
- amount: web3.utils.toWei(String(amount), 'ether'),
100
- });
101
-
102
- const getTxs = (count = 10) => {
103
- const txs = [];
104
- for (let i = 0; i < count; i++) {
105
- txs.push(getTx(getUser(), 'withdraw', random(100, 200)));
106
- }
107
- return txs;
108
- };
109
-
110
- const getBlocks = (count = 9, size = 4) => {
111
- const groups = chunk(getTxs(count * size), size);
112
- const blocks = [];
113
- groups.forEach((txs, index) => {
114
- const height = index + 1;
115
-
116
- let previousHash;
117
- if (height > 1) {
118
- previousHash = blocks[index - 1].blockHash;
119
- } else {
120
- previousHash = '';
121
- }
122
-
123
- const txsHash = MerkleTree.getListHash(txs.map((x) => x.hash));
124
- const merkleTree = MerkleTree.getBlockMerkleTree(txs);
125
- const merkleRoot = merkleTree.getHexRoot();
126
- const blockHash = MerkleTree.getBlockHash({ height, previousHash, merkleRoot, txsHash });
127
-
128
- blocks.push({ height, blockHash, merkleRoot, txsHash, txs });
129
- });
130
-
131
- return blocks;
132
- };
133
-
134
- const insertBlock = (blocks, txs, height) => {
135
- assert(height >= 1, 'height must be >= 1');
136
- const previousHash = height >= 2 ? blocks[height - 2].blockHash : '';
137
- const txsHash = MerkleTree.getListHash(txs.map((x) => x.hash));
138
- const merkleTree = MerkleTree.getBlockMerkleTree(txs);
139
- const merkleRoot = merkleTree.getHexRoot();
140
- const blockHash = MerkleTree.getBlockHash({ height, previousHash, merkleRoot, txsHash });
141
- const block = { height, blockHash, merkleRoot, txsHash, txs };
142
-
143
- blocks.splice(height - 1, 0, block);
144
-
145
- for (let i = height; i < blocks.length; i++) {
146
- const previous = blocks[i - 1];
147
- const current = blocks[i];
148
- current.height = i + 1;
149
- current.previousHash = previous.blockHash;
150
- current.blockHash = MerkleTree.getBlockHash(pick(current, ['height', 'previousHash', 'merkleRoot', 'txsHash']));
151
- blocks[i] = current;
152
- }
153
- };
154
-
155
- const getProofs = (tx, height, blocks) => {
156
- const { txs } = blocks[height - 1];
157
- const tree = MerkleTree.getBlockMerkleTree(txs);
158
-
159
- const element = MerkleTree.encodePacked(
160
- { type: 'bytes32', value: tx.hash },
161
- { type: 'address', value: tx.to },
162
- { type: 'uint256', value: tx.amount }
163
- );
164
-
165
- return tree.getHexProof(element);
166
- };
167
-
168
- const updateEnvFile = (updates) => {
169
- const filePath = path.join(__dirname, '../', process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : '.env');
170
- if (!fs.existsSync(filePath)) {
171
- fs.writeFileSync(filePath, '');
172
- }
173
- const env = Object.assign(parse(fs.readFileSync(filePath, 'utf8')), updates);
174
- fs.writeFileSync(filePath, stringify(env));
175
- };
176
-
177
- const getEnvFile = () => {
178
- const filePath = path.join(__dirname, '../', process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : '.env');
179
- if (!fs.existsSync(filePath)) {
180
- return {};
181
- }
182
- const env = parse(fs.readFileSync(filePath, 'utf8'));
183
- return env;
184
- };
185
-
186
- const getNonces = async (contract, force = 0) => {
187
- const nonces = {};
188
- const validators = await contract.getValidators();
189
- for (const validator of validators) {
190
- const nonce = await contract.getNonce(validator);
191
- nonces[validator] = force || nonce.toNumber();
192
- }
193
-
194
- return nonces;
195
- };
196
-
197
- module.exports = {
198
- BLACK_HOLE,
199
- web3,
200
- accounts,
201
- insertBlock,
202
- seedValidators,
203
- seedSigners,
204
- getSingers,
205
- getContracts,
206
- getSignatures,
207
- getUser,
208
- getTxHash,
209
- getTx,
210
- getTxs,
211
- getBlocks,
212
- getProofs,
213
- getNonces,
214
- updateEnvFile,
215
- getEnvFile,
216
- };
File without changes