@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 +31 -19
- package/lib/EvmChainList.json +50 -0
- package/lib/contract.js +160 -45
- package/package.json +17 -17
- package/lib/helper.js +0 -216
- /package/lib/{erc721did.json → ERC721DID.json} +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
##
|
|
1
|
+
## ERC721DID Contracts
|
|
2
2
|
|
|
3
|
-
Solidity contracts that powers
|
|
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
|
|
10
|
-
3. deploy
|
|
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
|
-
|
|
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
|
|
34
|
+
#### Deploy ERC721DID Parent Contract + ERC721DID Factory Contract
|
|
29
35
|
|
|
30
|
-
> Will update .env
|
|
36
|
+
> Will update .env
|
|
31
37
|
|
|
32
38
|
```bash
|
|
33
|
-
|
|
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
|
-
####
|
|
50
|
+
#### Dev ERC721DID Parent Contract + ERC721DID Factory Contract
|
|
37
51
|
|
|
38
|
-
> Will update .env.
|
|
52
|
+
> Will update .env.local
|
|
39
53
|
|
|
40
54
|
```bash
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#### Deploy ERC20Rollup
|
|
55
|
+
# bash 1
|
|
56
|
+
npm run node
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
# bash 2
|
|
59
|
+
npm run dev
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
:
|
|
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,
|
|
21
|
-
const provider =
|
|
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,
|
|
29
|
-
const provider =
|
|
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
|
|
107
|
+
const chainId = await getChainId({ contract });
|
|
40
108
|
|
|
41
109
|
// ethereum
|
|
42
|
-
if ([1, '1', 'mainnet', 'eth-main'].includes(
|
|
43
|
-
const { data } = await axios.get(`https://token-data.arcblock.io/api/gas-prices?chainId=${
|
|
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(
|
|
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(
|
|
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
|
|
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:
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
return
|
|
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
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
|
170
|
-
return
|
|
236
|
+
const getChainInfo = (chainId) => {
|
|
237
|
+
return {
|
|
238
|
+
...CHAIN_MAP[chainId],
|
|
239
|
+
...CUSTOM_CHAIN_MAP[chainId],
|
|
240
|
+
};
|
|
171
241
|
};
|
|
172
242
|
|
|
173
|
-
const
|
|
174
|
-
|
|
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 = ({
|
|
178
|
-
return
|
|
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
|
-
|
|
201
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
30
|
+
"@openzeppelin/contracts": "^4.9.0",
|
|
31
31
|
"@types/mocha": "^10.0.1",
|
|
32
|
-
"@types/node": "^18.
|
|
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.
|
|
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.
|
|
44
|
+
"prettier": "^2.8.8",
|
|
45
45
|
"solidity-coverage": "^0.7.22",
|
|
46
|
-
"web3": "^1.
|
|
47
|
-
"web3-utils": "^1.
|
|
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
|
-
"
|
|
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
|