@arcblock/erc721did-contract 0.2.4

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/lib/helper.js ADDED
@@ -0,0 +1,216 @@
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
+ };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@arcblock/erc721did-contract",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.2.4",
7
+ "main": "./lib",
8
+ "module": "./lib",
9
+ "typings": "./lib",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./lib",
13
+ "require": "./lib"
14
+ },
15
+ "./contract": {
16
+ "import": "./lib/contract.js",
17
+ "require": "./lib/contract.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "lib"
22
+ ],
23
+ "devDependencies": {
24
+ "@arcblock/eslint-config-base": "^0.2.3",
25
+ "@nomiclabs/hardhat-ethers": "^2.2.3",
26
+ "@nomiclabs/hardhat-waffle": "^2.0.5",
27
+ "@ocap/mcrypto": "1.18.34",
28
+ "@ocap/merkle-tree": "1.18.34",
29
+ "@ocap/util": "1.18.34",
30
+ "@ocap/wallet": "1.18.34",
31
+ "@openzeppelin/contracts": "^4.8.3",
32
+ "@types/mocha": "^10.0.1",
33
+ "@types/node": "^18.15.11",
34
+ "chai": "^4.3.7",
35
+ "dotenv-flow": "^3.2.0",
36
+ "envfile": "^6.18.0",
37
+ "ethereum-cryptography": "^0.1.3",
38
+ "ethereum-waffle": "^3.4.4",
39
+ "ethereumjs-util": "^7.1.5",
40
+ "ethereumjs-wallet": "^1.0.2",
41
+ "ethers": "^5.7.2",
42
+ "hardhat": "^2.14.0",
43
+ "hardhat-contract-sizer": "^2.8.0",
44
+ "hardhat-deploy": "^0.9.29",
45
+ "hardhat-gas-reporter": "^1.0.9",
46
+ "lodash": "^4.17.21",
47
+ "prettier": "^2.8.7",
48
+ "solidity-coverage": "^0.7.22",
49
+ "web3": "^1.9.0",
50
+ "web3-utils": "^1.9.0"
51
+ },
52
+ "dependencies": {
53
+ "axios": "^1.3.5",
54
+ "eslint": "^8.38.0",
55
+ "p-wait-for": "^3.2.0"
56
+ },
57
+ "scripts": {
58
+ "deploy": "hardhat deploy",
59
+ "copy-to-lib": "node tools/copy-to-lib.js",
60
+ "lint": "eslint tests tools lib",
61
+ "test": "hardhat test",
62
+ "test:local": "hardhat test --network localhost",
63
+ "deploy:local": "NODE_ENV=local hardhat deploy --network localhost",
64
+ "clean": "hardhat clean",
65
+ "publish:contracts": "hardhat compile",
66
+ "compile": "hardhat compile",
67
+ "coverage": "hardhat coverage",
68
+ "codesize": "hardhat size-contracts",
69
+ "node": "hardhat node",
70
+ "dev": "nodemon --exec 'npm run copy-to-lib' --ignore 'lib/*'"
71
+ }
72
+ }