@cheny56/zk-kyc-did 1.0.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 +520 -0
- package/circuits/credential-proof.circom +108 -0
- package/client/index.d.ts +5 -0
- package/client/index.js +13 -0
- package/client/kyc-client.js +243 -0
- package/contracts/CredentialVerifier.sol +119 -0
- package/contracts/interfaces/IVerifier.sol +23 -0
- package/examples/create-credential.js +141 -0
- package/examples/generate-proof.js +176 -0
- package/examples/verify-credential.js +150 -0
- package/examples/verify-setup.js +177 -0
- package/lib/credential.js +366 -0
- package/lib/index.d.ts +212 -0
- package/lib/index.js +39 -0
- package/lib/predicate.js +209 -0
- package/package.json +80 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cheny56/zk-kyc-did
|
|
3
|
+
* Type definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Verifiable Credential
|
|
8
|
+
*/
|
|
9
|
+
export declare class VerifiableCredential {
|
|
10
|
+
issuer: string;
|
|
11
|
+
subject: string;
|
|
12
|
+
claims: Record<string, any>;
|
|
13
|
+
type: string;
|
|
14
|
+
issuedAt: number;
|
|
15
|
+
expirationDate: number | null;
|
|
16
|
+
id: string;
|
|
17
|
+
claimCommitments: Record<string, bigint>;
|
|
18
|
+
blindingFactors: Record<string, bigint>;
|
|
19
|
+
signature: bigint | null;
|
|
20
|
+
|
|
21
|
+
constructor(options: {
|
|
22
|
+
issuer: string;
|
|
23
|
+
subject: string;
|
|
24
|
+
claims: Record<string, any>;
|
|
25
|
+
type?: string;
|
|
26
|
+
expirationDate?: number;
|
|
27
|
+
id?: string;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize credential (compute commitments)
|
|
32
|
+
*/
|
|
33
|
+
init(): Promise<VerifiableCredential>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sign the credential
|
|
37
|
+
*/
|
|
38
|
+
sign(issuerPrivateKey: bigint): bigint;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Verify credential signature
|
|
42
|
+
*/
|
|
43
|
+
verifySignature(issuerPublicKey: bigint): boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get commitment for a claim
|
|
47
|
+
*/
|
|
48
|
+
getCommitment(claimKey: string): string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get all commitments
|
|
52
|
+
*/
|
|
53
|
+
getAllCommitments(): Record<string, string>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get blinding factor
|
|
57
|
+
*/
|
|
58
|
+
getBlindingFactor(claimKey: string): bigint;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if expired
|
|
62
|
+
*/
|
|
63
|
+
isExpired(): boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Serialize
|
|
67
|
+
*/
|
|
68
|
+
toJSON(): object;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Deserialize
|
|
72
|
+
*/
|
|
73
|
+
static fromJSON(json: object, claims?: Record<string, any>): Promise<VerifiableCredential>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Credential Wallet
|
|
78
|
+
*/
|
|
79
|
+
export declare class CredentialWallet {
|
|
80
|
+
subjectDID: string;
|
|
81
|
+
|
|
82
|
+
constructor(subjectDID?: string);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Initialize wallet
|
|
86
|
+
*/
|
|
87
|
+
init(): Promise<void>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate DID
|
|
91
|
+
*/
|
|
92
|
+
generateDID(): string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Add credential
|
|
96
|
+
*/
|
|
97
|
+
addCredential(credential: VerifiableCredential): void;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get credential
|
|
101
|
+
*/
|
|
102
|
+
getCredential(credentialId: string): VerifiableCredential | null;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get all credentials
|
|
106
|
+
*/
|
|
107
|
+
getAllCredentials(): VerifiableCredential[];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get credentials by type
|
|
111
|
+
*/
|
|
112
|
+
getCredentialsByType(type: string): VerifiableCredential[];
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Remove credential
|
|
116
|
+
*/
|
|
117
|
+
removeCredential(credentialId: string): void;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Export wallet
|
|
121
|
+
*/
|
|
122
|
+
toJSON(): object;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Import wallet
|
|
126
|
+
*/
|
|
127
|
+
static fromJSON(json: object): Promise<CredentialWallet>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Predicate operators
|
|
132
|
+
*/
|
|
133
|
+
export declare const PredicateOp: {
|
|
134
|
+
EQ: 'eq';
|
|
135
|
+
NE: 'ne';
|
|
136
|
+
GT: 'gt';
|
|
137
|
+
GTE: 'gte';
|
|
138
|
+
LT: 'lt';
|
|
139
|
+
LTE: 'lte';
|
|
140
|
+
IN: 'in';
|
|
141
|
+
NOT_IN: 'not_in';
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Predicate
|
|
146
|
+
*/
|
|
147
|
+
export declare class Predicate {
|
|
148
|
+
claimKey: string;
|
|
149
|
+
op: string;
|
|
150
|
+
value: any;
|
|
151
|
+
|
|
152
|
+
constructor(options: {
|
|
153
|
+
claimKey: string;
|
|
154
|
+
op: string;
|
|
155
|
+
value: any;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Evaluate predicate
|
|
160
|
+
*/
|
|
161
|
+
evaluate(claimValue: any): boolean;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Serialize
|
|
165
|
+
*/
|
|
166
|
+
toJSON(): object;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generate proof inputs
|
|
171
|
+
*/
|
|
172
|
+
export declare function generateProofInputs(
|
|
173
|
+
credential: VerifiableCredential,
|
|
174
|
+
predicates: Predicate[]
|
|
175
|
+
): object;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Prepare public inputs
|
|
179
|
+
*/
|
|
180
|
+
export declare function preparePublicInputs(
|
|
181
|
+
predicates: Predicate[],
|
|
182
|
+
issuerPublicKey: string
|
|
183
|
+
): object;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Verify predicate proof
|
|
187
|
+
*/
|
|
188
|
+
export declare function verifyPredicateProof(
|
|
189
|
+
proof: object,
|
|
190
|
+
publicInputs: object,
|
|
191
|
+
credential: VerifiableCredential
|
|
192
|
+
): Promise<boolean>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Initialize library
|
|
196
|
+
*/
|
|
197
|
+
export declare function init(): Promise<boolean>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Poseidon hash
|
|
201
|
+
*/
|
|
202
|
+
export declare function poseidonHash(inputs: bigint[]): string;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Random field element
|
|
206
|
+
*/
|
|
207
|
+
export declare function randomFieldElement(): bigint;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Package version
|
|
211
|
+
*/
|
|
212
|
+
export declare const version: string;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cheny56/zk-kyc-did
|
|
3
|
+
*
|
|
4
|
+
* Zero-Knowledge KYC and Decentralized Identity
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Verifiable Credentials (W3C standard)
|
|
8
|
+
* - Selective disclosure (prove predicates without revealing values)
|
|
9
|
+
* - On-chain verification via ZK proofs
|
|
10
|
+
* - Privacy-preserving identity verification
|
|
11
|
+
*
|
|
12
|
+
* @module @cheny56/zk-kyc-did
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { VerifiableCredential, CredentialWallet, init, poseidonHash, randomFieldElement } = require('./credential');
|
|
16
|
+
const { Predicate, PredicateOp, generateProofInputs, preparePublicInputs, verifyPredicateProof } = require('./predicate');
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
// Core classes
|
|
20
|
+
VerifiableCredential,
|
|
21
|
+
CredentialWallet,
|
|
22
|
+
|
|
23
|
+
// Predicates
|
|
24
|
+
Predicate,
|
|
25
|
+
PredicateOp,
|
|
26
|
+
|
|
27
|
+
// Proof generation
|
|
28
|
+
generateProofInputs,
|
|
29
|
+
preparePublicInputs,
|
|
30
|
+
verifyPredicateProof,
|
|
31
|
+
|
|
32
|
+
// Utilities
|
|
33
|
+
init,
|
|
34
|
+
poseidonHash,
|
|
35
|
+
randomFieldElement,
|
|
36
|
+
|
|
37
|
+
// Version
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
};
|
package/lib/predicate.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predicate Proof Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates ZK proofs for credential predicates without revealing claim values.
|
|
5
|
+
*
|
|
6
|
+
* Example predicates:
|
|
7
|
+
* - age >= 18
|
|
8
|
+
* - country IN ["US", "UK", "CA"]
|
|
9
|
+
* - balance > 1000
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { buildPoseidon } = require('circomlibjs');
|
|
13
|
+
|
|
14
|
+
let poseidon = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize Poseidon
|
|
18
|
+
*/
|
|
19
|
+
async function init() {
|
|
20
|
+
if (!poseidon) {
|
|
21
|
+
poseidon = await buildPoseidon();
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Predicate operators
|
|
28
|
+
*/
|
|
29
|
+
const PredicateOp = {
|
|
30
|
+
EQ: 'eq', // Equal
|
|
31
|
+
NE: 'ne', // Not equal
|
|
32
|
+
GT: 'gt', // Greater than
|
|
33
|
+
GTE: 'gte', // Greater than or equal
|
|
34
|
+
LT: 'lt', // Less than
|
|
35
|
+
LTE: 'lte', // Less than or equal
|
|
36
|
+
IN: 'in', // In set
|
|
37
|
+
NOT_IN: 'not_in', // Not in set
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Predicate definition
|
|
42
|
+
*/
|
|
43
|
+
class Predicate {
|
|
44
|
+
/**
|
|
45
|
+
* Create a predicate
|
|
46
|
+
* @param {Object} options
|
|
47
|
+
* @param {string} options.claimKey - Claim to check
|
|
48
|
+
* @param {string} options.op - Operator (PredicateOp)
|
|
49
|
+
* @param {any} options.value - Value to compare against
|
|
50
|
+
*/
|
|
51
|
+
constructor(options) {
|
|
52
|
+
this.claimKey = options.claimKey;
|
|
53
|
+
this.op = options.op;
|
|
54
|
+
this.value = options.value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if a claim value satisfies this predicate
|
|
59
|
+
* @param {any} claimValue
|
|
60
|
+
* @returns {boolean}
|
|
61
|
+
*/
|
|
62
|
+
evaluate(claimValue) {
|
|
63
|
+
switch (this.op) {
|
|
64
|
+
case PredicateOp.EQ:
|
|
65
|
+
return claimValue === this.value;
|
|
66
|
+
case PredicateOp.NE:
|
|
67
|
+
return claimValue !== this.value;
|
|
68
|
+
case PredicateOp.GT:
|
|
69
|
+
return Number(claimValue) > Number(this.value);
|
|
70
|
+
case PredicateOp.GTE:
|
|
71
|
+
return Number(claimValue) >= Number(this.value);
|
|
72
|
+
case PredicateOp.LT:
|
|
73
|
+
return Number(claimValue) < Number(this.value);
|
|
74
|
+
case PredicateOp.LTE:
|
|
75
|
+
return Number(claimValue) <= Number(this.value);
|
|
76
|
+
case PredicateOp.IN:
|
|
77
|
+
return Array.isArray(this.value) && this.value.includes(claimValue);
|
|
78
|
+
case PredicateOp.NOT_IN:
|
|
79
|
+
return Array.isArray(this.value) && !this.value.includes(claimValue);
|
|
80
|
+
default:
|
|
81
|
+
throw new Error(`Unknown operator: ${this.op}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Serialize predicate
|
|
87
|
+
*/
|
|
88
|
+
toJSON() {
|
|
89
|
+
return {
|
|
90
|
+
claimKey: this.claimKey,
|
|
91
|
+
op: this.op,
|
|
92
|
+
value: this.value,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generate private inputs for ZK proof
|
|
99
|
+
* @param {Object} credential - VerifiableCredential
|
|
100
|
+
* @param {Predicate[]} predicates - Predicates to prove
|
|
101
|
+
* @returns {Object} Private inputs for circuit
|
|
102
|
+
*/
|
|
103
|
+
async function generateProofInputs(credential, predicates) {
|
|
104
|
+
await init();
|
|
105
|
+
|
|
106
|
+
const inputs = {
|
|
107
|
+
// Credential commitments
|
|
108
|
+
claimCommitments: {},
|
|
109
|
+
|
|
110
|
+
// Claim values (private)
|
|
111
|
+
claimValues: {},
|
|
112
|
+
|
|
113
|
+
// Blinding factors (private)
|
|
114
|
+
blindingFactors: {},
|
|
115
|
+
|
|
116
|
+
// Predicates
|
|
117
|
+
predicates: predicates.map(p => ({
|
|
118
|
+
claimKey: p.claimKey,
|
|
119
|
+
op: p.op,
|
|
120
|
+
value: p.value,
|
|
121
|
+
})),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Collect all unique claim keys from predicates
|
|
125
|
+
const claimKeys = new Set(predicates.map(p => p.claimKey));
|
|
126
|
+
|
|
127
|
+
for (const claimKey of claimKeys) {
|
|
128
|
+
// Verify claim exists
|
|
129
|
+
if (!credential.claims[claimKey]) {
|
|
130
|
+
throw new Error(`Claim "${claimKey}" not found in credential`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Verify predicate is satisfied
|
|
134
|
+
const predicate = predicates.find(p => p.claimKey === claimKey);
|
|
135
|
+
if (predicate && !predicate.evaluate(credential.claims[claimKey])) {
|
|
136
|
+
throw new Error(`Predicate not satisfied for claim "${claimKey}"`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
inputs.claimCommitments[claimKey] = credential.getCommitment(claimKey);
|
|
140
|
+
inputs.claimValues[claimKey] = credential.claims[claimKey];
|
|
141
|
+
inputs.blindingFactors[claimKey] = credential.getBlindingFactor(claimKey).toString();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Credential signature
|
|
145
|
+
inputs.issuer = credential.issuer;
|
|
146
|
+
inputs.signature = credential.signature?.toString() || '0';
|
|
147
|
+
|
|
148
|
+
return inputs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Prepare public inputs for verification
|
|
153
|
+
* @param {Predicate[]} predicates
|
|
154
|
+
* @param {string} issuerPublicKey
|
|
155
|
+
* @returns {Object} Public inputs
|
|
156
|
+
*/
|
|
157
|
+
function preparePublicInputs(predicates, issuerPublicKey) {
|
|
158
|
+
return {
|
|
159
|
+
predicates: predicates.map(p => ({
|
|
160
|
+
claimKey: p.claimKey,
|
|
161
|
+
op: p.op,
|
|
162
|
+
value: p.value,
|
|
163
|
+
})),
|
|
164
|
+
issuerPublicKey,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Verify a predicate proof (simplified - actual verification in circuit)
|
|
170
|
+
* @param {Object} proof - ZK proof
|
|
171
|
+
* @param {Object} publicInputs - Public inputs
|
|
172
|
+
* @param {Object} credential - Original credential
|
|
173
|
+
* @returns {Promise<boolean>}
|
|
174
|
+
*/
|
|
175
|
+
async function verifyPredicateProof(proof, publicInputs, credential) {
|
|
176
|
+
await init();
|
|
177
|
+
|
|
178
|
+
// Verify issuer matches
|
|
179
|
+
if (publicInputs.issuerPublicKey !== credential.issuer) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Verify credential signature
|
|
184
|
+
if (!credential.verifySignature(BigInt(publicInputs.issuerPublicKey))) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Verify predicates are satisfied (this would be done in ZK circuit)
|
|
189
|
+
for (const predicate of publicInputs.predicates) {
|
|
190
|
+
const p = new Predicate(predicate);
|
|
191
|
+
if (!p.evaluate(credential.claims[p.claimKey])) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// In production, verify the actual ZK proof using snarkjs
|
|
197
|
+
// For now, this is a placeholder
|
|
198
|
+
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = {
|
|
203
|
+
Predicate,
|
|
204
|
+
PredicateOp,
|
|
205
|
+
generateProofInputs,
|
|
206
|
+
preparePublicInputs,
|
|
207
|
+
verifyPredicateProof,
|
|
208
|
+
init,
|
|
209
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cheny56/zk-kyc-did",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Zero-Knowledge KYC and Decentralized Identity - Prove credentials without revealing personal data",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./lib/index.js",
|
|
10
|
+
"types": "./lib/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./lib": {
|
|
13
|
+
"require": "./lib/index.js",
|
|
14
|
+
"types": "./lib/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./client": {
|
|
17
|
+
"require": "./client/kyc-client.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"lib/",
|
|
22
|
+
"client/",
|
|
23
|
+
"contracts/",
|
|
24
|
+
"circuits/",
|
|
25
|
+
"examples/",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "node examples/verify-setup.js",
|
|
30
|
+
"example:credential": "node examples/create-credential.js",
|
|
31
|
+
"example:proof": "node examples/generate-proof.js",
|
|
32
|
+
"example:verify": "node examples/verify-credential.js",
|
|
33
|
+
"circuits:compile": "bash scripts/compile-circuits.sh",
|
|
34
|
+
"circuits:setup": "bash scripts/trusted-setup.sh"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"zk",
|
|
38
|
+
"zero-knowledge",
|
|
39
|
+
"kyc",
|
|
40
|
+
"did",
|
|
41
|
+
"decentralized-identity",
|
|
42
|
+
"credentials",
|
|
43
|
+
"privacy",
|
|
44
|
+
"selective-disclosure",
|
|
45
|
+
"verifiable-credentials",
|
|
46
|
+
"ethereum",
|
|
47
|
+
"quorum",
|
|
48
|
+
"circom",
|
|
49
|
+
"snarkjs"
|
|
50
|
+
],
|
|
51
|
+
"author": "cheny56",
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "git+https://github.com/cheny56/zk-kyc-did.git"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/cheny56/zk-kyc-did#readme",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/cheny56/zk-kyc-did/issues"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"circomlibjs": "^0.1.7"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"circomlib": "^2.0.5",
|
|
66
|
+
"snarkjs": "^0.7.3",
|
|
67
|
+
"hardhat": "^2.19.0",
|
|
68
|
+
"@nomicfoundation/hardhat-toolbox": "^4.0.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"ethers": "^6.0.0"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=18.0.0"
|
|
75
|
+
},
|
|
76
|
+
"directories": {
|
|
77
|
+
"example": "examples",
|
|
78
|
+
"lib": "lib"
|
|
79
|
+
}
|
|
80
|
+
}
|