@cheny56/node-client 1.0.14 → 1.0.16
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 +343 -170
- package/package.json +4 -5
- package/src/wallet.js +2 -1
package/README.md
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @cheny56/node-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- ✅ **TypeScript Support**: Full TypeScript definitions included
|
|
7
|
+
- **Post-Quantum Cryptography**: Support for Dilithium (ML-DSA-65) signatures
|
|
8
|
+
- **Hybrid Signatures**: Combine ECDSA and PQC for enhanced security
|
|
9
|
+
- **Zero-Knowledge Proofs**: Support for ZK transactions (Groth16, PLONK, STARK)
|
|
10
|
+
- **Transaction Types**: Legacy, AccessList, and DynamicFee transactions
|
|
11
|
+
- **ERC20 Token Support**: Simplified interface for token transfers
|
|
12
|
+
- **CommonJS First**: Uses `require()` syntax by default (JavaScript-friendly)
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
@@ -18,301 +17,475 @@ A comprehensive JavaScript/TypeScript client library for interacting with Quorum
|
|
|
18
17
|
npm install @cheny56/node-client
|
|
19
18
|
```
|
|
20
19
|
|
|
20
|
+
## Dependencies
|
|
21
|
+
|
|
22
|
+
- `ethers@^5.7.2` - Ethereum library
|
|
23
|
+
- `dilithium-crystals@^1.0.0` - Post-quantum cryptography implementation
|
|
24
|
+
|
|
21
25
|
## Quick Start
|
|
22
26
|
|
|
23
|
-
###
|
|
27
|
+
### Using CommonJS (Default)
|
|
24
28
|
|
|
25
29
|
```javascript
|
|
26
|
-
|
|
30
|
+
const { QuorumProvider, ECDSAWallet, PQCWallet, HybridWallet } = require('@cheny56/node-client');
|
|
27
31
|
|
|
28
32
|
// Connect to Quorum node
|
|
29
33
|
const provider = new QuorumProvider('http://localhost:8545');
|
|
30
34
|
|
|
31
|
-
// Create
|
|
35
|
+
// Create ECDSA wallet (synchronous)
|
|
32
36
|
const ecdsaWallet = new ECDSAWallet('0x...', provider);
|
|
33
|
-
|
|
37
|
+
|
|
38
|
+
// Create PQC wallet (async - keys are generated asynchronously)
|
|
39
|
+
const pqcWallet = new PQCWallet();
|
|
40
|
+
await pqcWallet._initPromise; // Wait for keys to be generated
|
|
41
|
+
|
|
42
|
+
// Or use the static factory method (recommended)
|
|
43
|
+
const pqcWallet2 = await PQCWallet.create();
|
|
44
|
+
|
|
45
|
+
// Create hybrid wallet
|
|
34
46
|
const hybridWallet = new HybridWallet(ecdsaWallet, pqcWallet);
|
|
47
|
+
const hybridAddress = await hybridWallet.getAddress();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Using ES Modules (Optional)
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { QuorumProvider, ECDSAWallet, PQCWallet } from '@cheny56/node-client';
|
|
54
|
+
|
|
55
|
+
// Same usage as CommonJS
|
|
56
|
+
const provider = new QuorumProvider('http://localhost:8545');
|
|
57
|
+
const pqcWallet = await PQCWallet.create();
|
|
35
58
|
```
|
|
36
59
|
|
|
37
|
-
|
|
60
|
+
## Wallets
|
|
38
61
|
|
|
39
|
-
|
|
40
|
-
import { QuorumProvider, ECDSAWallet, PQCWallet, HybridWallet } from '@cheny56/node-client';
|
|
62
|
+
### ECDSA Wallet
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
Standard Ethereum wallet using ECDSA signatures.
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const { ECDSAWallet } = require('@cheny56/node-client');
|
|
68
|
+
|
|
69
|
+
// Create from private key
|
|
70
|
+
const wallet = new ECDSAWallet('0x...', provider);
|
|
71
|
+
|
|
72
|
+
// Get address
|
|
73
|
+
console.log(wallet.address);
|
|
74
|
+
|
|
75
|
+
// Sign message
|
|
76
|
+
const signature = await wallet.signMessage('Hello, World!');
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### PQC Wallet
|
|
80
|
+
|
|
81
|
+
Post-quantum wallet using Dilithium signatures. **Note: Key generation is asynchronous.**
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const { PQCWallet } = require('@cheny56/node-client');
|
|
85
|
+
|
|
86
|
+
// Method 1: Create and wait for initialization
|
|
87
|
+
const wallet = new PQCWallet();
|
|
88
|
+
await wallet._initPromise; // Keys are generated in the background
|
|
89
|
+
console.log(wallet.address); // Now available
|
|
90
|
+
|
|
91
|
+
// Method 2: Use static factory (recommended)
|
|
92
|
+
const wallet2 = await PQCWallet.create();
|
|
93
|
+
console.log(wallet2.address); // Immediately available
|
|
94
|
+
|
|
95
|
+
// Method 3: Create from existing keys
|
|
96
|
+
const wallet3 = PQCWallet.fromSecretKey(secretKey, publicKey);
|
|
97
|
+
|
|
98
|
+
// Sign message hash
|
|
99
|
+
const hash = new Uint8Array(32); // Your message hash
|
|
100
|
+
const signature = await wallet.sign(hash);
|
|
44
101
|
|
|
45
|
-
//
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
102
|
+
// Verify signature
|
|
103
|
+
const isValid = await wallet.verify(hash, signature);
|
|
104
|
+
|
|
105
|
+
// Get keys (async)
|
|
106
|
+
const publicKeyHex = await wallet.getPublicKeyHex();
|
|
107
|
+
const secretKeyHex = await wallet.getSecretKeyHex();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Important Notes:**
|
|
111
|
+
- PQC key generation uses `dilithium.keyPair()` which is async
|
|
112
|
+
- Keys are generated in the background when you create a new wallet
|
|
113
|
+
- Always await `_initPromise` or use `PQCWallet.create()` before accessing keys/address
|
|
114
|
+
- The `dilithium-crystals` package returns `{ publicKey, privateKey }` - the library maps `privateKey` to `secretKey` internally
|
|
115
|
+
|
|
116
|
+
### Hybrid Wallet
|
|
117
|
+
|
|
118
|
+
Combines ECDSA and PQC signatures for enhanced security.
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
const { HybridWallet, ECDSAWallet, PQCWallet } = require('@cheny56/node-client');
|
|
122
|
+
|
|
123
|
+
// Create from ECDSA and PQC wallets
|
|
124
|
+
const ecdsaWallet = new ECDSAWallet('0x...');
|
|
125
|
+
const pqcWallet = await PQCWallet.create();
|
|
126
|
+
const hybridWallet = new HybridWallet(ecdsaWallet, pqcWallet);
|
|
127
|
+
|
|
128
|
+
// Get hybrid address (async - waits for PQC keys)
|
|
129
|
+
const address = await hybridWallet.getAddress();
|
|
130
|
+
|
|
131
|
+
// Or use static factory
|
|
132
|
+
const hybridWallet2 = await HybridWallet.create('0x...'); // ECDSA private key
|
|
133
|
+
|
|
134
|
+
// Create from existing keys
|
|
135
|
+
const hybridWallet3 = HybridWallet.fromKeys(
|
|
136
|
+
ecdsaPrivateKey,
|
|
137
|
+
pqcSecretKey,
|
|
138
|
+
pqcPublicKey
|
|
139
|
+
);
|
|
49
140
|
```
|
|
50
141
|
|
|
51
|
-
|
|
142
|
+
## Transactions
|
|
143
|
+
|
|
144
|
+
### Legacy Transactions (Type 0)
|
|
52
145
|
|
|
53
146
|
#### ECDSA Transaction
|
|
54
147
|
|
|
55
148
|
```javascript
|
|
56
|
-
|
|
149
|
+
const { LegacyTransaction } = require('@cheny56/node-client');
|
|
57
150
|
|
|
58
151
|
const tx = new LegacyTransaction({
|
|
59
|
-
|
|
152
|
+
chainId: 1337,
|
|
153
|
+
nonce: 0,
|
|
154
|
+
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
|
|
155
|
+
gasLimit: 21000,
|
|
156
|
+
to: '0x...',
|
|
60
157
|
value: ethers.utils.parseEther('1.0'),
|
|
61
|
-
gasPrice: 0n,
|
|
62
|
-
gasLimit: 21000n,
|
|
63
158
|
});
|
|
64
159
|
|
|
65
160
|
const signedTx = await tx.sign(ecdsaWallet);
|
|
66
161
|
const txHash = await provider.sendRawTransaction(signedTx);
|
|
67
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
68
162
|
```
|
|
69
163
|
|
|
70
164
|
#### PQC Transaction
|
|
71
165
|
|
|
72
166
|
```javascript
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// Get nonce first
|
|
76
|
-
const nonce = await provider.getTransactionCount(pqcWallet.address, 'pending');
|
|
167
|
+
const { PQCLegacyTransaction } = require('@cheny56/node-client');
|
|
77
168
|
|
|
78
169
|
const tx = new PQCLegacyTransaction({
|
|
79
170
|
chainId: 1337,
|
|
80
|
-
nonce:
|
|
81
|
-
|
|
171
|
+
nonce: 0,
|
|
172
|
+
gasPrice: 0n, // 0 if node doesn't charge gas
|
|
173
|
+
gasLimit: 21000,
|
|
174
|
+
to: '0x...',
|
|
82
175
|
value: ethers.utils.parseEther('1.0'),
|
|
83
|
-
gasPrice: 0n,
|
|
84
|
-
gasLimit: 21000n,
|
|
85
176
|
});
|
|
86
177
|
|
|
87
|
-
|
|
178
|
+
// Sign with PQC wallet (async)
|
|
179
|
+
await tx.sign(pqcWallet);
|
|
88
180
|
const serialized = tx.getHex();
|
|
89
181
|
const txHash = await provider.sendRawTransaction(serialized);
|
|
90
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
91
182
|
```
|
|
92
183
|
|
|
93
184
|
#### Hybrid Transaction
|
|
94
185
|
|
|
95
186
|
```javascript
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const nonce = await provider.getTransactionCount(hybridWallet.address, 'pending');
|
|
187
|
+
const { HybridLegacyTransaction } = require('@cheny56/node-client');
|
|
99
188
|
|
|
100
189
|
const tx = new HybridLegacyTransaction({
|
|
101
190
|
chainId: 1337,
|
|
102
|
-
nonce:
|
|
103
|
-
|
|
191
|
+
nonce: 0,
|
|
192
|
+
gasPrice: 0n,
|
|
193
|
+
gasLimit: 21000,
|
|
194
|
+
to: '0x...',
|
|
104
195
|
value: ethers.utils.parseEther('1.0'),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Sign with both wallets (async)
|
|
199
|
+
await tx.sign(ecdsaWallet, pqcWallet);
|
|
200
|
+
const serialized = tx.getHex();
|
|
201
|
+
const txHash = await provider.sendRawTransaction(serialized);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### AccessList Transactions (Type 1)
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
const { PQCAccessListTransaction } = require('@cheny56/node-client');
|
|
208
|
+
|
|
209
|
+
const tx = new PQCAccessListTransaction({
|
|
210
|
+
chainId: 1337,
|
|
211
|
+
nonce: 0,
|
|
105
212
|
gasPrice: 0n,
|
|
106
|
-
gasLimit:
|
|
213
|
+
gasLimit: 21000,
|
|
214
|
+
to: '0x...',
|
|
215
|
+
value: ethers.utils.parseEther('1.0'),
|
|
216
|
+
accessList: [],
|
|
107
217
|
});
|
|
108
218
|
|
|
109
|
-
tx.sign(
|
|
219
|
+
await tx.sign(pqcWallet);
|
|
220
|
+
const serialized = tx.getHex();
|
|
221
|
+
const txHash = await provider.sendRawTransaction(serialized);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### DynamicFee Transactions (Type 2)
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const { PQCDynamicFeeTransaction } = require('@cheny56/node-client');
|
|
228
|
+
|
|
229
|
+
const tx = new PQCDynamicFeeTransaction({
|
|
230
|
+
chainId: 1337,
|
|
231
|
+
nonce: 0,
|
|
232
|
+
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
|
|
233
|
+
maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'),
|
|
234
|
+
gasLimit: 21000,
|
|
235
|
+
to: '0x...',
|
|
236
|
+
value: ethers.utils.parseEther('1.0'),
|
|
237
|
+
accessList: [],
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await tx.sign(pqcWallet);
|
|
110
241
|
const serialized = tx.getHex();
|
|
111
242
|
const txHash = await provider.sendRawTransaction(serialized);
|
|
112
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
113
243
|
```
|
|
114
244
|
|
|
115
|
-
|
|
245
|
+
## ERC20 Tokens
|
|
116
246
|
|
|
117
|
-
|
|
247
|
+
### Standard Transfer (ECDSA)
|
|
118
248
|
|
|
119
249
|
```javascript
|
|
120
|
-
|
|
250
|
+
const { ERC20Token } = require('@cheny56/node-client');
|
|
121
251
|
|
|
122
252
|
const token = new ERC20Token(tokenAddress, provider, ecdsaWallet);
|
|
123
|
-
|
|
124
|
-
|
|
253
|
+
|
|
254
|
+
// Transfer tokens
|
|
255
|
+
const tx = await token.transfer(recipientAddress, amount, {
|
|
256
|
+
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
|
|
257
|
+
gasLimit: 100000,
|
|
258
|
+
});
|
|
125
259
|
```
|
|
126
260
|
|
|
127
|
-
|
|
261
|
+
### PQC Token Transfer
|
|
128
262
|
|
|
129
263
|
```javascript
|
|
130
|
-
|
|
264
|
+
const { ERC20Token } = require('@cheny56/node-client');
|
|
131
265
|
|
|
132
266
|
const token = new ERC20Token(tokenAddress, provider);
|
|
267
|
+
|
|
268
|
+
// Transfer using PQC wallet (async)
|
|
133
269
|
const txHash = await token.transferPQC(
|
|
134
270
|
pqcWallet,
|
|
135
271
|
provider,
|
|
136
272
|
recipientAddress,
|
|
137
|
-
|
|
138
|
-
{
|
|
273
|
+
amount,
|
|
274
|
+
{
|
|
275
|
+
chainId: 1337,
|
|
276
|
+
gasPrice: 0n,
|
|
277
|
+
gasLimit: 100000,
|
|
278
|
+
}
|
|
139
279
|
);
|
|
140
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
141
280
|
```
|
|
142
281
|
|
|
143
|
-
|
|
282
|
+
### Hybrid Token Transfer
|
|
144
283
|
|
|
145
284
|
```javascript
|
|
146
|
-
|
|
285
|
+
const { ERC20Token } = require('@cheny56/node-client');
|
|
147
286
|
|
|
148
287
|
const token = new ERC20Token(tokenAddress, provider);
|
|
288
|
+
|
|
289
|
+
// Transfer using hybrid wallet (async)
|
|
149
290
|
const txHash = await token.transferHybrid(
|
|
150
291
|
hybridWallet,
|
|
151
292
|
provider,
|
|
152
293
|
recipientAddress,
|
|
153
|
-
|
|
154
|
-
{
|
|
294
|
+
amount,
|
|
295
|
+
{
|
|
296
|
+
chainId: 1337,
|
|
297
|
+
gasPrice: 0n,
|
|
298
|
+
gasLimit: 100000,
|
|
299
|
+
}
|
|
155
300
|
);
|
|
156
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
157
301
|
```
|
|
158
302
|
|
|
159
|
-
|
|
303
|
+
## Zero-Knowledge Proof Transactions
|
|
160
304
|
|
|
161
305
|
```javascript
|
|
162
|
-
|
|
306
|
+
const { ZKTransaction, ZK_PROOF_SYSTEM } = require('@cheny56/node-client');
|
|
163
307
|
|
|
164
308
|
const zkTx = new ZKTransaction({
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
data: encodedFunctionData,
|
|
309
|
+
chainId: 1337,
|
|
310
|
+
nonce: 0,
|
|
168
311
|
gasPrice: 0n,
|
|
169
|
-
gasLimit:
|
|
312
|
+
gasLimit: 21000,
|
|
313
|
+
to: '0x...',
|
|
314
|
+
value: ethers.utils.parseEther('1.0'),
|
|
170
315
|
zkProofSystem: ZK_PROOF_SYSTEM.GROTH16,
|
|
171
316
|
zkProof: proofBytes,
|
|
172
|
-
zkPublicInputs:
|
|
317
|
+
zkPublicInputs: publicInputs,
|
|
173
318
|
zkVerificationKeyHash: vkHash,
|
|
174
319
|
});
|
|
175
320
|
|
|
176
321
|
const txHash = await zkTx.send(provider, senderAddress);
|
|
177
|
-
const receipt = await provider.waitForTransaction(txHash);
|
|
178
322
|
```
|
|
179
323
|
|
|
180
|
-
##
|
|
181
|
-
|
|
182
|
-
### Providers
|
|
183
|
-
|
|
184
|
-
#### `QuorumProvider`
|
|
324
|
+
## Provider
|
|
185
325
|
|
|
186
326
|
```javascript
|
|
187
|
-
const
|
|
188
|
-
```
|
|
327
|
+
const { QuorumProvider } = require('@cheny56/node-client');
|
|
189
328
|
|
|
190
|
-
|
|
191
|
-
- `sendRawTransaction(signedTx)`: Send raw transaction
|
|
192
|
-
- `getTransactionReceipt(txHash)`: Get transaction receipt
|
|
193
|
-
- `waitForTransaction(txHash, confirmations)`: Wait for transaction
|
|
194
|
-
- `getTransactionCount(address, blockTag)`: Get nonce
|
|
195
|
-
- `getBalance(address, blockTag)`: Get balance
|
|
196
|
-
- `estimateGas(transaction)`: Estimate gas
|
|
197
|
-
- `getGasPrice()`: Get current gas price
|
|
198
|
-
- `getBlockNumber()`: Get current block number
|
|
329
|
+
const provider = new QuorumProvider('http://localhost:8545');
|
|
199
330
|
|
|
200
|
-
|
|
331
|
+
// Get block number
|
|
332
|
+
const blockNumber = await provider.getBlockNumber();
|
|
201
333
|
|
|
202
|
-
|
|
334
|
+
// Get balance
|
|
335
|
+
const balance = await provider.getBalance(address);
|
|
203
336
|
|
|
204
|
-
|
|
337
|
+
// Get transaction count (nonce)
|
|
338
|
+
const nonce = await provider.getTransactionCount(address);
|
|
205
339
|
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
```
|
|
340
|
+
// Send raw transaction
|
|
341
|
+
const txHash = await provider.sendRawTransaction(signedTxHex);
|
|
209
342
|
|
|
210
|
-
|
|
343
|
+
// Wait for transaction
|
|
344
|
+
const receipt = await provider.waitForTransaction(txHash);
|
|
345
|
+
```
|
|
211
346
|
|
|
212
|
-
|
|
347
|
+
## Constants
|
|
213
348
|
|
|
214
349
|
```javascript
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
350
|
+
const {
|
|
351
|
+
TX_TYPE,
|
|
352
|
+
PQC_TYPE,
|
|
353
|
+
ZK_PROOF_SYSTEM,
|
|
354
|
+
DEFAULT_CHAIN_ID,
|
|
355
|
+
} = require('@cheny56/node-client');
|
|
356
|
+
|
|
357
|
+
// Transaction types
|
|
358
|
+
TX_TYPE.LEGACY // 0
|
|
359
|
+
TX_TYPE.ACCESS_LIST // 1
|
|
360
|
+
TX_TYPE.DYNAMIC_FEE // 2
|
|
361
|
+
TX_TYPE.ZK_PRIVATE // 4
|
|
362
|
+
|
|
363
|
+
// PQC types
|
|
364
|
+
PQC_TYPE.NONE // 0
|
|
365
|
+
PQC_TYPE.DILITHIUM // 1
|
|
366
|
+
|
|
367
|
+
// ZK proof systems
|
|
368
|
+
ZK_PROOF_SYSTEM.GROTH16 // 1
|
|
369
|
+
ZK_PROOF_SYSTEM.PLONK // 2
|
|
370
|
+
ZK_PROOF_SYSTEM.STARK // 3
|
|
371
|
+
|
|
372
|
+
// Default chain ID
|
|
373
|
+
DEFAULT_CHAIN_ID // 1337
|
|
218
374
|
```
|
|
219
375
|
|
|
220
|
-
|
|
221
|
-
- `sign(hash)`: Sign a message hash
|
|
222
|
-
- `verify(hash, signature)`: Verify a signature
|
|
223
|
-
- `getPublicKeyHex()`: Get public key as hex
|
|
224
|
-
- `getSecretKeyHex()`: Get secret key as hex (use with caution!)
|
|
225
|
-
|
|
226
|
-
#### `HybridWallet`
|
|
227
|
-
|
|
228
|
-
Hybrid wallet using both ECDSA and PQC signatures.
|
|
376
|
+
## Utilities
|
|
229
377
|
|
|
230
378
|
```javascript
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
379
|
+
const {
|
|
380
|
+
derivePQCAddress,
|
|
381
|
+
deriveHybridAddress,
|
|
382
|
+
isValidAddress,
|
|
383
|
+
encodeUint64,
|
|
384
|
+
encodeBigInt,
|
|
385
|
+
encodeSignature,
|
|
386
|
+
} = require('@cheny56/node-client');
|
|
387
|
+
|
|
388
|
+
// Derive PQC address from public key
|
|
389
|
+
const address = derivePQCAddress(publicKey);
|
|
390
|
+
|
|
391
|
+
// Derive hybrid address from ECDSA + PQC public keys
|
|
392
|
+
const hybridAddress = deriveHybridAddress(ecdsaPublicKey, pqcPublicKey);
|
|
393
|
+
|
|
394
|
+
// Validate address
|
|
395
|
+
const isValid = isValidAddress('0x...');
|
|
396
|
+
|
|
397
|
+
// RLP encoding utilities
|
|
398
|
+
const nonceHex = encodeUint64(5);
|
|
399
|
+
const valueHex = encodeBigInt(ethers.utils.parseEther('1.0'));
|
|
400
|
+
const sigHex = encodeSignature('0x...');
|
|
234
401
|
```
|
|
235
402
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
#### Transaction Types
|
|
239
|
-
|
|
240
|
-
- `LegacyTransaction`: Type 0, ECDSA only
|
|
241
|
-
- `PQCLegacyTransaction`: Type 0, PQC only
|
|
242
|
-
- `HybridLegacyTransaction`: Type 0, ECDSA + PQC
|
|
243
|
-
- `AccessListTransaction`: Type 1, ECDSA only
|
|
244
|
-
- `PQCAccessListTransaction`: Type 1, PQC only
|
|
245
|
-
- `DynamicFeeTransaction`: Type 2, ECDSA only
|
|
246
|
-
- `PQCDynamicFeeTransaction`: Type 2, PQC only
|
|
247
|
-
|
|
248
|
-
#### Common Transaction Methods
|
|
249
|
-
|
|
250
|
-
- `sign(wallet)`: Sign transaction (for ECDSA)
|
|
251
|
-
- `sign(wallet)` or `sign(ecdsaWallet, pqcWallet)`: Sign transaction (for PQC/Hybrid)
|
|
252
|
-
- `getHex()`: Get serialized transaction as hex
|
|
253
|
-
- `verify()`: Verify PQC signature (for PQC transactions)
|
|
254
|
-
|
|
255
|
-
### Contracts
|
|
256
|
-
|
|
257
|
-
#### `Contract`
|
|
258
|
-
|
|
259
|
-
Generic contract interface.
|
|
403
|
+
## Complete Example
|
|
260
404
|
|
|
261
405
|
```javascript
|
|
262
|
-
const
|
|
406
|
+
const { QuorumProvider, PQCWallet, PQCLegacyTransaction } = require('@cheny56/node-client');
|
|
407
|
+
const { ethers } = require('ethers');
|
|
408
|
+
|
|
409
|
+
async function main() {
|
|
410
|
+
// Connect to node
|
|
411
|
+
const provider = new QuorumProvider('http://localhost:8545');
|
|
412
|
+
|
|
413
|
+
// Create PQC wallet (async)
|
|
414
|
+
const wallet = await PQCWallet.create();
|
|
415
|
+
console.log('PQC Address:', wallet.address);
|
|
416
|
+
|
|
417
|
+
// Get nonce
|
|
418
|
+
const nonce = await provider.getTransactionCount(wallet.address, 'pending');
|
|
419
|
+
|
|
420
|
+
// Create transaction
|
|
421
|
+
const tx = new PQCLegacyTransaction({
|
|
422
|
+
chainId: 1337,
|
|
423
|
+
nonce: nonce,
|
|
424
|
+
gasPrice: 0n, // 0 if node doesn't charge gas
|
|
425
|
+
gasLimit: 21000,
|
|
426
|
+
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
|
|
427
|
+
value: ethers.utils.parseEther('0.1'),
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Sign transaction (async)
|
|
431
|
+
await tx.sign(wallet);
|
|
432
|
+
const serialized = tx.getHex();
|
|
433
|
+
|
|
434
|
+
// Send transaction
|
|
435
|
+
const txHash = await provider.sendRawTransaction(serialized);
|
|
436
|
+
console.log('Transaction hash:', txHash);
|
|
437
|
+
|
|
438
|
+
// Wait for confirmation
|
|
439
|
+
const receipt = await provider.waitForTransaction(txHash);
|
|
440
|
+
console.log('Transaction confirmed in block:', receipt.blockNumber);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
main().catch(console.error);
|
|
263
444
|
```
|
|
264
445
|
|
|
265
|
-
|
|
446
|
+
## API Reference
|
|
266
447
|
|
|
267
|
-
|
|
448
|
+
### PQCWallet
|
|
449
|
+
|
|
450
|
+
#### Constructor
|
|
268
451
|
|
|
269
452
|
```javascript
|
|
270
|
-
|
|
453
|
+
new PQCWallet(secretKey?, publicKey?)
|
|
271
454
|
```
|
|
272
455
|
|
|
273
|
-
|
|
274
|
-
- `
|
|
275
|
-
-
|
|
276
|
-
- `transferHybrid(wallet, provider, to, amount, txOptions)`: Transfer tokens (Hybrid)
|
|
277
|
-
- `balanceOf(address)`: Get balance
|
|
278
|
-
- `name()`, `symbol()`, `decimals()`, `totalSupply()`: Token info
|
|
279
|
-
|
|
280
|
-
## TypeScript Support
|
|
456
|
+
- `secretKey` (optional): Existing secret key (Uint8Array or hex string)
|
|
457
|
+
- `publicKey` (optional): Existing public key (Uint8Array or hex string)
|
|
458
|
+
- If both are omitted, keys are generated asynchronously
|
|
281
459
|
|
|
282
|
-
|
|
460
|
+
#### Static Methods
|
|
283
461
|
|
|
284
|
-
-
|
|
285
|
-
-
|
|
286
|
-
- Proper type inference for transaction parameters and return values
|
|
462
|
+
- `PQCWallet.create()`: Returns `Promise<PQCWallet>` - Creates wallet with initialized keys
|
|
463
|
+
- `PQCWallet.fromSecretKey(secretKey, publicKey)`: Creates wallet from existing keys
|
|
287
464
|
|
|
288
|
-
|
|
465
|
+
#### Instance Methods
|
|
289
466
|
|
|
290
|
-
|
|
467
|
+
- `async sign(hash: Uint8Array)`: Sign a message hash
|
|
468
|
+
- `async verify(hash: Uint8Array, signature: Uint8Array)`: Verify a signature
|
|
469
|
+
- `async getAddress()`: Get wallet address (waits for initialization if needed)
|
|
470
|
+
- `async getPublicKeyHex()`: Get public key as hex string
|
|
471
|
+
- `async getSecretKeyHex()`: Get secret key as hex string
|
|
291
472
|
|
|
292
|
-
|
|
473
|
+
#### Properties
|
|
293
474
|
|
|
294
|
-
- `
|
|
295
|
-
- `
|
|
296
|
-
- `
|
|
475
|
+
- `secretKey`: Uint8Array (null until initialized)
|
|
476
|
+
- `publicKey`: Uint8Array (null until initialized)
|
|
477
|
+
- `address`: string (null until initialized)
|
|
478
|
+
- `_initialized`: boolean
|
|
479
|
+
- `_initPromise`: Promise - Wait for this to ensure keys are generated
|
|
297
480
|
|
|
298
|
-
##
|
|
481
|
+
## Notes
|
|
299
482
|
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
- `ethers`: ^5.7.2
|
|
306
|
-
- `@noble/post-quantum`: ^0.5.4
|
|
483
|
+
- **CommonJS Default**: This library uses CommonJS (`require`) by default for JavaScript compatibility
|
|
484
|
+
- **Async Key Generation**: PQC keys are generated asynchronously - always await initialization before use
|
|
485
|
+
- **Gas Fees**: Set `gasPrice` to `0n` if your Quorum node doesn't charge gas fees
|
|
486
|
+
- **RLP Encoding**: The library uses custom RLP encoding compatible with Go's RLP implementation
|
|
487
|
+
- **Dilithium Package**: Uses `dilithium-crystals` package which returns `{ publicKey, privateKey }` from `keyPair()`
|
|
307
488
|
|
|
308
489
|
## License
|
|
309
490
|
|
|
310
491
|
LGPL-3.0
|
|
311
|
-
|
|
312
|
-
## Contributing
|
|
313
|
-
|
|
314
|
-
Contributions are welcome! Please open an issue or submit a pull request.
|
|
315
|
-
|
|
316
|
-
## Support
|
|
317
|
-
|
|
318
|
-
For issues and questions, please open an issue on the repository.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cheny56/node-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -38,11 +38,10 @@
|
|
|
38
38
|
"author": "",
|
|
39
39
|
"license": "LGPL-3.0",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"
|
|
42
|
-
"dilithium-crystals": "^1.0.0"
|
|
41
|
+
"@cheny56/node-client": "^1.0.15",
|
|
42
|
+
"dilithium-crystals": "^1.0.0",
|
|
43
|
+
"ethers": "^5.7.2"
|
|
43
44
|
},
|
|
44
|
-
"peerDependencies": {},
|
|
45
|
-
"devDependencies": {},
|
|
46
45
|
"directories": {
|
|
47
46
|
"example": "examples"
|
|
48
47
|
}
|
package/src/wallet.js
CHANGED
|
@@ -104,8 +104,9 @@ class PQCWallet {
|
|
|
104
104
|
throw new Error('dilithium-crystals does not expose keyPair method. Please check the package API.');
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// dilithium.keyPair() is async and returns { publicKey, privateKey }
|
|
107
108
|
const keyPair = await dilithium.keyPair();
|
|
108
|
-
this.secretKey = keyPair.secretKey
|
|
109
|
+
this.secretKey = keyPair.privateKey; // dilithium-crystals uses 'privateKey', not 'secretKey'
|
|
109
110
|
this.publicKey = keyPair.publicKey;
|
|
110
111
|
this.address = derivePQCAddress(this.publicKey);
|
|
111
112
|
this._initialized = true;
|