@0xpolygonid/js-sdk 1.6.1 → 1.7.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 +3 -1
- package/dist/browser/esm/index.js +738 -491
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +784 -531
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/circuits/comparer.js +3 -3
- package/dist/node/cjs/credentials/credential-wallet.js +19 -2
- package/dist/node/cjs/credentials/index.js +1 -0
- package/dist/node/cjs/credentials/rhs.js +28 -15
- package/dist/node/cjs/credentials/status/credential-status-publisher.js +84 -0
- package/dist/node/cjs/credentials/utils.js +14 -1
- package/dist/node/cjs/identity/identity-wallet.js +57 -26
- package/dist/node/cjs/storage/blockchain/abi/CredentialStatusResolver.json +1 -1
- package/dist/node/cjs/storage/blockchain/index.js +1 -0
- package/dist/node/cjs/storage/blockchain/onchain-revocation.js +45 -5
- package/dist/node/esm/circuits/comparer.js +3 -3
- package/dist/node/esm/credentials/credential-wallet.js +20 -3
- package/dist/node/esm/credentials/index.js +1 -0
- package/dist/node/esm/credentials/rhs.js +26 -14
- package/dist/node/esm/credentials/status/credential-status-publisher.js +78 -0
- package/dist/node/esm/credentials/utils.js +12 -0
- package/dist/node/esm/identity/identity-wallet.js +52 -21
- package/dist/node/esm/storage/blockchain/abi/CredentialStatusResolver.json +1 -1
- package/dist/node/esm/storage/blockchain/index.js +1 -0
- package/dist/node/esm/storage/blockchain/onchain-revocation.js +45 -5
- package/dist/types/credentials/index.d.ts +1 -0
- package/dist/types/credentials/rhs.d.ts +11 -0
- package/dist/types/credentials/status/credential-status-publisher.d.ts +70 -0
- package/dist/types/credentials/utils.d.ts +2 -0
- package/dist/types/identity/identity-wallet.d.ts +42 -13
- package/dist/types/storage/blockchain/index.d.ts +1 -0
- package/dist/types/storage/blockchain/onchain-revocation.d.ts +7 -3
- package/package.json +1 -1
|
@@ -53,12 +53,12 @@ exports.QueryOperators = {
|
|
|
53
53
|
};
|
|
54
54
|
const allOperations = Object.values(exports.QueryOperators);
|
|
55
55
|
exports.availableTypesOperators = new Map([
|
|
56
|
-
[XSDNS.Boolean, [exports.QueryOperators.$eq, exports.QueryOperators.$ne]],
|
|
56
|
+
[XSDNS.Boolean, [exports.QueryOperators.$eq, exports.QueryOperators.$ne, exports.QueryOperators.$sd]],
|
|
57
57
|
[XSDNS.Integer, allOperations],
|
|
58
58
|
[XSDNS.NonNegativeInteger, allOperations],
|
|
59
59
|
[XSDNS.PositiveInteger, allOperations],
|
|
60
|
-
[XSDNS.Double, [exports.QueryOperators.$eq, exports.QueryOperators.$ne, exports.QueryOperators.$in, exports.QueryOperators.$nin]],
|
|
61
|
-
[XSDNS.String, [exports.QueryOperators.$eq, exports.QueryOperators.$ne, exports.QueryOperators.$in, exports.QueryOperators.$nin]],
|
|
60
|
+
[XSDNS.Double, [exports.QueryOperators.$eq, exports.QueryOperators.$ne, exports.QueryOperators.$in, exports.QueryOperators.$nin, exports.QueryOperators.$sd]],
|
|
61
|
+
[XSDNS.String, [exports.QueryOperators.$eq, exports.QueryOperators.$ne, exports.QueryOperators.$in, exports.QueryOperators.$nin, exports.QueryOperators.$sd]],
|
|
62
62
|
[XSDNS.DateTime, allOperations]
|
|
63
63
|
]);
|
|
64
64
|
/**
|
|
@@ -83,7 +83,7 @@ class CredentialWallet {
|
|
|
83
83
|
id: request.credentialSchema,
|
|
84
84
|
type: verifiable_1.VerifiableConstants.JSON_SCHEMA_VALIDATOR
|
|
85
85
|
};
|
|
86
|
-
cr.credentialStatus = this.buildCredentialStatus(request);
|
|
86
|
+
cr.credentialStatus = this.buildCredentialStatus(request, issuer);
|
|
87
87
|
return cr;
|
|
88
88
|
};
|
|
89
89
|
// if no credential status resolvers are provided
|
|
@@ -149,7 +149,7 @@ class CredentialWallet {
|
|
|
149
149
|
* @param {CredentialRequest} request
|
|
150
150
|
* @returns `CredentialStatus`
|
|
151
151
|
*/
|
|
152
|
-
buildCredentialStatus(request) {
|
|
152
|
+
buildCredentialStatus(request, issuer) {
|
|
153
153
|
const credentialStatus = {
|
|
154
154
|
id: request.revocationOpts.id,
|
|
155
155
|
type: request.revocationOpts.type,
|
|
@@ -168,6 +168,23 @@ class CredentialWallet {
|
|
|
168
168
|
? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${request.revocationOpts.issuerState}`
|
|
169
169
|
: `${credentialStatus.id.replace(/\/$/, '')}`
|
|
170
170
|
};
|
|
171
|
+
case verifiable_1.CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: {
|
|
172
|
+
const issuerId = js_iden3_core_1.DID.idFromDID(issuer);
|
|
173
|
+
const chainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(issuerId), js_iden3_core_1.DID.networkIdFromId(issuerId));
|
|
174
|
+
const searchParams = [
|
|
175
|
+
['revocationNonce', request.revocationOpts.nonce?.toString() || ''],
|
|
176
|
+
['contractAddress', `${chainId}:${request.revocationOpts.id}`],
|
|
177
|
+
['state', request.revocationOpts.issuerState || '']
|
|
178
|
+
]
|
|
179
|
+
.filter(([, value]) => Boolean(value))
|
|
180
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
181
|
+
.join('&');
|
|
182
|
+
return {
|
|
183
|
+
...credentialStatus,
|
|
184
|
+
// `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)`
|
|
185
|
+
id: `${issuer.string()}/credentialStatus?${searchParams}`
|
|
186
|
+
};
|
|
187
|
+
}
|
|
171
188
|
default:
|
|
172
189
|
return credentialStatus;
|
|
173
190
|
}
|
|
@@ -19,6 +19,7 @@ __exportStar(require("./status/reverse-sparse-merkle-tree"), exports);
|
|
|
19
19
|
__exportStar(require("./status/sparse-merkle-tree"), exports);
|
|
20
20
|
__exportStar(require("./status/resolver"), exports);
|
|
21
21
|
__exportStar(require("./status/agent-revocation"), exports);
|
|
22
|
+
__exportStar(require("./status/credential-status-publisher"), exports);
|
|
22
23
|
__exportStar(require("./status/utils"), exports);
|
|
23
24
|
__exportStar(require("./credential-wallet"), exports);
|
|
24
25
|
__exportStar(require("./rhs"), exports);
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pushHashesToRHS = void 0;
|
|
3
|
+
exports.getNodesRepresentation = exports.pushHashesToRHS = void 0;
|
|
4
4
|
const js_merkletree_1 = require("@iden3/js-merkletree");
|
|
5
5
|
const js_merkletree_2 = require("@iden3/js-merkletree");
|
|
6
6
|
const js_merkletree_3 = require("@iden3/js-merkletree");
|
|
7
7
|
const reverse_sparse_merkle_tree_1 = require("./status/reverse-sparse-merkle-tree");
|
|
8
|
+
const credential_status_publisher_1 = require("./status/credential-status-publisher");
|
|
9
|
+
const verifiable_1 = require("../verifiable");
|
|
8
10
|
/**
|
|
9
11
|
* Pushes identity state information to a reverse hash service.
|
|
10
12
|
*
|
|
11
13
|
* A reverse hash service (RHS) is a centralized or decentralized service for storing publicly available data about identity.
|
|
12
14
|
* Such data are identity state and state of revocation tree and roots tree root tree.
|
|
13
15
|
*
|
|
16
|
+
* @deprecated Use `pushHashesToReverseHashService` instead.
|
|
14
17
|
* @param {Hash} state - current state of identity
|
|
15
18
|
* @param {TreesModel} trees - current trees of identity (claims, revocation, rootOfRoots )
|
|
16
19
|
* @param {string} rhsUrl - URL of service
|
|
@@ -18,6 +21,24 @@ const reverse_sparse_merkle_tree_1 = require("./status/reverse-sparse-merkle-tre
|
|
|
18
21
|
* @returns void
|
|
19
22
|
*/
|
|
20
23
|
async function pushHashesToRHS(state, trees, rhsUrl, revokedNonces) {
|
|
24
|
+
const nodes = await getNodesRepresentation(revokedNonces, trees, state);
|
|
25
|
+
const publisher = new credential_status_publisher_1.Iden3SmtRhsCredentialStatusPublisher();
|
|
26
|
+
await publisher.publish({
|
|
27
|
+
nodes,
|
|
28
|
+
credentialStatusType: verifiable_1.CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
|
|
29
|
+
rhsUrl: rhsUrl
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
exports.pushHashesToRHS = pushHashesToRHS;
|
|
33
|
+
/**
|
|
34
|
+
* Retrieves the representation of nodes for generating a proof.
|
|
35
|
+
*
|
|
36
|
+
* @param revokedNonces - An array of revoked nonces.
|
|
37
|
+
* @param trees - The TreesModel object containing the necessary trees.
|
|
38
|
+
* @param state - The hash of the state.
|
|
39
|
+
* @returns A Promise that resolves to an array of ProofNode objects.
|
|
40
|
+
*/
|
|
41
|
+
async function getNodesRepresentation(revokedNonces, trees, state) {
|
|
21
42
|
const nb = new NodesBuilder();
|
|
22
43
|
if (revokedNonces) {
|
|
23
44
|
await addRevocationNode(nb, trees, revokedNonces);
|
|
@@ -31,17 +52,9 @@ async function pushHashesToRHS(state, trees, rhsUrl, revokedNonces) {
|
|
|
31
52
|
await trees.rootsTree.root()
|
|
32
53
|
]));
|
|
33
54
|
}
|
|
34
|
-
|
|
35
|
-
await saveNodes(nb.nodes, rhsUrl);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
exports.pushHashesToRHS = pushHashesToRHS;
|
|
39
|
-
async function saveNodes(nodes, nodeUrl) {
|
|
40
|
-
const nodesJSON = nodes.map((n) => n.toJSON());
|
|
41
|
-
const resp = await fetch(nodeUrl + '/node', { method: 'post', body: JSON.stringify(nodesJSON) });
|
|
42
|
-
const status = resp.status;
|
|
43
|
-
return status === 200;
|
|
55
|
+
return nb.nodes;
|
|
44
56
|
}
|
|
57
|
+
exports.getNodesRepresentation = getNodesRepresentation;
|
|
45
58
|
async function addRoRNode(nb, trees) {
|
|
46
59
|
const currentRootsTree = trees.rootsTree;
|
|
47
60
|
const claimsTree = trees.claimsTree;
|
|
@@ -66,8 +79,8 @@ class NodesBuilder {
|
|
|
66
79
|
}
|
|
67
80
|
async addKey(tree, nodeKey) {
|
|
68
81
|
const { value: nodeValue, siblings } = await tree.get(nodeKey);
|
|
69
|
-
const nodeKeyHash =
|
|
70
|
-
const nodeValueHash =
|
|
82
|
+
const nodeKeyHash = js_merkletree_1.Hash.fromBigInt(nodeKey);
|
|
83
|
+
const nodeValueHash = js_merkletree_1.Hash.fromBigInt(nodeValue);
|
|
71
84
|
const node = new js_merkletree_1.NodeLeaf(nodeKeyHash, nodeValueHash);
|
|
72
85
|
const newNodes = await buildNodesUp(siblings, node);
|
|
73
86
|
for (const n of newNodes) {
|
|
@@ -97,7 +110,7 @@ async function buildNodesUp(siblings, node) {
|
|
|
97
110
|
nodes[index] = new reverse_sparse_merkle_tree_1.ProofNode();
|
|
98
111
|
}
|
|
99
112
|
nodes[sl].hash = prevHash;
|
|
100
|
-
const hashOfOne =
|
|
113
|
+
const hashOfOne = js_merkletree_1.Hash.fromBigInt(BigInt(1));
|
|
101
114
|
nodes[sl].children = [node.entry[0], node.entry[1], hashOfOne];
|
|
102
115
|
const pathKey = node.entry[0];
|
|
103
116
|
for (let i = sl - 1; i >= 0; i--) {
|
|
@@ -111,7 +124,7 @@ async function buildNodesUp(siblings, node) {
|
|
|
111
124
|
nodes[i].children[0] = prevHash;
|
|
112
125
|
nodes[i].children[1] = siblings[i];
|
|
113
126
|
}
|
|
114
|
-
nodes[i].hash =
|
|
127
|
+
nodes[i].hash = (0, js_merkletree_3.hashElems)([nodes[i].children[0].bigInt(), nodes[i].children[1].bigInt()]);
|
|
115
128
|
prevHash = nodes[i].hash;
|
|
116
129
|
}
|
|
117
130
|
return nodes;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Iden3SmtRhsCredentialStatusPublisher = exports.Iden3OnchainSmtCredentialStatusPublisher = exports.CredentialStatusPublisherRegistry = void 0;
|
|
4
|
+
const verifiable_1 = require("../../verifiable");
|
|
5
|
+
/**
|
|
6
|
+
* Registry for managing credential status publishers.
|
|
7
|
+
*/
|
|
8
|
+
class CredentialStatusPublisherRegistry {
|
|
9
|
+
constructor() {
|
|
10
|
+
this._publishers = new Map();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Registers one or more credential status publishers for a given type.
|
|
14
|
+
* @param type - The credential status type.
|
|
15
|
+
* @param publisher - One or more credential status publishers.
|
|
16
|
+
*/
|
|
17
|
+
register(type, ...publisher) {
|
|
18
|
+
const publishers = this._publishers.get(type) ?? [];
|
|
19
|
+
publishers.push(...publisher);
|
|
20
|
+
this._publishers.set(type, publishers);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves the credential status publishers for a given type.
|
|
24
|
+
* @param type - The credential status type.
|
|
25
|
+
* @returns An array of credential status publishers or undefined if none are registered for the given type.
|
|
26
|
+
*/
|
|
27
|
+
get(type) {
|
|
28
|
+
return this._publishers.get(type);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.CredentialStatusPublisherRegistry = CredentialStatusPublisherRegistry;
|
|
32
|
+
/**
|
|
33
|
+
* Implementation of the ICredentialStatusPublisher interface for publishing on-chain credential status.
|
|
34
|
+
*/
|
|
35
|
+
class Iden3OnchainSmtCredentialStatusPublisher {
|
|
36
|
+
constructor(_storage) {
|
|
37
|
+
this._storage = _storage;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Publishes the credential status to the blockchain.
|
|
41
|
+
* @param params - The parameters for publishing the credential status.
|
|
42
|
+
*/
|
|
43
|
+
async publish(params) {
|
|
44
|
+
if (![verifiable_1.CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023].includes(params.credentialStatusType)) {
|
|
45
|
+
throw new Error(`On-chain publishing is not supported for credential status type ${params.credentialStatusType}`);
|
|
46
|
+
}
|
|
47
|
+
const nodesBigInts = params.nodes.map((n) => n.children.map((c) => c.bigInt()));
|
|
48
|
+
const txPromise = this._storage.saveNodes(nodesBigInts);
|
|
49
|
+
if (params.onChain?.txCallback) {
|
|
50
|
+
const cb = params.onChain?.txCallback;
|
|
51
|
+
txPromise.then((receipt) => cb(receipt));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await txPromise;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.Iden3OnchainSmtCredentialStatusPublisher = Iden3OnchainSmtCredentialStatusPublisher;
|
|
58
|
+
/**
|
|
59
|
+
* Implementation of the ICredentialStatusPublisher interface for publishing off-chain credential status.
|
|
60
|
+
*/
|
|
61
|
+
class Iden3SmtRhsCredentialStatusPublisher {
|
|
62
|
+
/**
|
|
63
|
+
* Publishes the credential status to a specified node URL.
|
|
64
|
+
* @param params - The parameters for publishing the credential status.
|
|
65
|
+
* @param params.nodes - The proof nodes to be published.
|
|
66
|
+
* @param params.rhsUrl - The URL of the node to publish the credential status to.
|
|
67
|
+
* @returns A promise that resolves when the credential status is successfully published.
|
|
68
|
+
* @throws An error if the publishing fails.
|
|
69
|
+
*/
|
|
70
|
+
async publish(params) {
|
|
71
|
+
if (![verifiable_1.CredentialStatusType.Iden3ReverseSparseMerkleTreeProof].includes(params.credentialStatusType)) {
|
|
72
|
+
throw new Error(`On-chain publishing is not supported for credential status type ${params.credentialStatusType}`);
|
|
73
|
+
}
|
|
74
|
+
const nodesJSON = params.nodes.map((n) => n.toJSON());
|
|
75
|
+
const resp = await fetch(params.rhsUrl + '/node', {
|
|
76
|
+
method: 'post',
|
|
77
|
+
body: JSON.stringify(nodesJSON)
|
|
78
|
+
});
|
|
79
|
+
if (resp.status !== 200) {
|
|
80
|
+
throw new Error(`Failed to publish credential status. Status: ${resp.status}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.Iden3SmtRhsCredentialStatusPublisher = Iden3SmtRhsCredentialStatusPublisher;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUserDIDFromCredential = void 0;
|
|
3
|
+
exports.getKMSIdByAuthCredential = exports.getUserDIDFromCredential = void 0;
|
|
4
4
|
const js_iden3_core_1 = require("@iden3/js-iden3-core");
|
|
5
|
+
const js_crypto_1 = require("@iden3/js-crypto");
|
|
6
|
+
const kms_1 = require("../kms");
|
|
5
7
|
/**
|
|
6
8
|
* Retrieves the user DID from a given credential.
|
|
7
9
|
* If the credential does not have a credentialSubject.id property, the issuer DID is returned.
|
|
@@ -21,3 +23,14 @@ const getUserDIDFromCredential = (issuerDID, credential) => {
|
|
|
21
23
|
return js_iden3_core_1.DID.parse(credential.credentialSubject.id);
|
|
22
24
|
};
|
|
23
25
|
exports.getUserDIDFromCredential = getUserDIDFromCredential;
|
|
26
|
+
const getKMSIdByAuthCredential = (credential) => {
|
|
27
|
+
if (!credential.type.includes('AuthBJJCredential')) {
|
|
28
|
+
throw new Error("can't sign with not AuthBJJCredential credential");
|
|
29
|
+
}
|
|
30
|
+
const x = credential.credentialSubject['x'];
|
|
31
|
+
const y = credential.credentialSubject['y'];
|
|
32
|
+
const pb = new js_crypto_1.PublicKey([BigInt(x), BigInt(y)]);
|
|
33
|
+
const kp = (0, kms_1.keyPath)(kms_1.KmsKeyType.BabyJubJub, pb.hex());
|
|
34
|
+
return { type: kms_1.KmsKeyType.BabyJubJub, id: kp };
|
|
35
|
+
};
|
|
36
|
+
exports.getKMSIdByAuthCredential = getKMSIdByAuthCredential;
|
|
@@ -31,11 +31,11 @@ const js_merkletree_1 = require("@iden3/js-merkletree");
|
|
|
31
31
|
const common_1 = require("./common");
|
|
32
32
|
const uuid = __importStar(require("uuid"));
|
|
33
33
|
const schema_processor_1 = require("../schema-processor");
|
|
34
|
-
const
|
|
35
|
-
const provider_helpers_1 = require("../kms/provider-helpers");
|
|
34
|
+
const storage_1 = require("../storage");
|
|
36
35
|
const verifiable_1 = require("../verifiable");
|
|
37
36
|
const credentials_1 = require("../credentials");
|
|
38
37
|
const utils_1 = require("../utils");
|
|
38
|
+
const credential_status_publisher_1 = require("../credentials/status/credential-status-publisher");
|
|
39
39
|
/**
|
|
40
40
|
* @public
|
|
41
41
|
* Wallet instance to manage the digital identity based on iden3 protocol
|
|
@@ -56,10 +56,19 @@ class IdentityWallet {
|
|
|
56
56
|
* @param {ICredentialWallet} _credentialWallet - credential wallet instance to quickly access credential CRUD functionality
|
|
57
57
|
* @public
|
|
58
58
|
*/
|
|
59
|
-
constructor(_kms, _storage, _credentialWallet) {
|
|
59
|
+
constructor(_kms, _storage, _credentialWallet, _opts) {
|
|
60
60
|
this._kms = _kms;
|
|
61
61
|
this._storage = _storage;
|
|
62
62
|
this._credentialWallet = _credentialWallet;
|
|
63
|
+
this._opts = _opts;
|
|
64
|
+
if (!_opts?.credentialStatusPublisherRegistry) {
|
|
65
|
+
this._credentialStatusPublisherRegistry = new credential_status_publisher_1.CredentialStatusPublisherRegistry();
|
|
66
|
+
this._credentialStatusPublisherRegistry.register(verifiable_1.CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, new credential_status_publisher_1.Iden3SmtRhsCredentialStatusPublisher());
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this._credentialStatusPublisherRegistry = this._opts
|
|
70
|
+
?.credentialStatusPublisherRegistry;
|
|
71
|
+
}
|
|
63
72
|
}
|
|
64
73
|
/**
|
|
65
74
|
* {@inheritDoc IIdentityWallet.createIdentity}
|
|
@@ -78,8 +87,8 @@ class IdentityWallet {
|
|
|
78
87
|
const authClaim = js_iden3_core_1.Claim.newClaim(schemaHash, js_iden3_core_1.ClaimOptions.withIndexDataInts(pubKey.p[0], pubKey.p[1]), js_iden3_core_1.ClaimOptions.withRevocationNonce(BigInt(0)));
|
|
79
88
|
const revNonce = opts.revocationOpts.nonce ?? 0;
|
|
80
89
|
authClaim.setRevocationNonce(BigInt(revNonce));
|
|
81
|
-
await this._storage.mt.addToMerkleTree(tmpIdentifier,
|
|
82
|
-
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(tmpIdentifier,
|
|
90
|
+
await this._storage.mt.addToMerkleTree(tmpIdentifier, storage_1.MerkleTreeType.Claims, authClaim.hiHv().hi, authClaim.hiHv().hv);
|
|
91
|
+
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(tmpIdentifier, storage_1.MerkleTreeType.Claims);
|
|
83
92
|
const currentState = (0, js_merkletree_1.hashElems)([
|
|
84
93
|
(await claimsTree.root()).bigInt(),
|
|
85
94
|
js_merkletree_1.ZERO_HASH.bigInt(),
|
|
@@ -133,9 +142,10 @@ class IdentityWallet {
|
|
|
133
142
|
coreClaim: authClaim
|
|
134
143
|
});
|
|
135
144
|
credential.proof = [mtpProof];
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
await this.publishRevocationInfoByCredentialStatusType(did, opts.revocationOpts.type, {
|
|
146
|
+
rhsUrl: opts.revocationOpts.id,
|
|
147
|
+
onChain: opts.revocationOpts.onChain
|
|
148
|
+
});
|
|
139
149
|
await this._storage.identity.saveIdentity({
|
|
140
150
|
did: did.string(),
|
|
141
151
|
state: currentState,
|
|
@@ -197,10 +207,11 @@ class IdentityWallet {
|
|
|
197
207
|
}
|
|
198
208
|
/** {@inheritDoc IIdentityWallet.getDIDTreeModel} */
|
|
199
209
|
async getDIDTreeModel(did) {
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
const
|
|
210
|
+
const didStr = did.string();
|
|
211
|
+
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, storage_1.MerkleTreeType.Claims);
|
|
212
|
+
const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, storage_1.MerkleTreeType.Revocations);
|
|
213
|
+
const rootsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(didStr, storage_1.MerkleTreeType.Roots);
|
|
214
|
+
const state = (0, js_merkletree_1.hashElems)([
|
|
204
215
|
(await claimsTree.root()).bigInt(),
|
|
205
216
|
(await revocationTree.root()).bigInt(),
|
|
206
217
|
(await rootsTree.root()).bigInt()
|
|
@@ -217,7 +228,7 @@ class IdentityWallet {
|
|
|
217
228
|
const coreClaim = await this.getCoreClaimFromCredential(credential);
|
|
218
229
|
// todo: Parser.parseClaim
|
|
219
230
|
const treesModel = await this.getDIDTreeModel(did);
|
|
220
|
-
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(),
|
|
231
|
+
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), storage_1.MerkleTreeType.Claims);
|
|
221
232
|
const claimsRoot = await treesModel.claimsTree.root();
|
|
222
233
|
const rootOfRoots = await treesModel.rootsTree.root();
|
|
223
234
|
const revocationRoot = await treesModel.revocationTree.root();
|
|
@@ -237,7 +248,7 @@ class IdentityWallet {
|
|
|
237
248
|
const coreClaim = await this.getCoreClaimFromCredential(credential);
|
|
238
249
|
const revNonce = coreClaim.getRevocationNonce();
|
|
239
250
|
const treesModel = await this.getDIDTreeModel(did);
|
|
240
|
-
const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(),
|
|
251
|
+
const revocationTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(did.string(), storage_1.MerkleTreeType.Revocations);
|
|
241
252
|
const claimsRoot = await treesModel.claimsTree.root();
|
|
242
253
|
const rootOfRoots = await treesModel.rootsTree.root();
|
|
243
254
|
const revocationRoot = await treesModel.revocationTree.root();
|
|
@@ -254,14 +265,14 @@ class IdentityWallet {
|
|
|
254
265
|
}
|
|
255
266
|
/** {@inheritDoc IIdentityWallet.sign} */
|
|
256
267
|
async sign(message, credential) {
|
|
257
|
-
const keyKMSId =
|
|
268
|
+
const keyKMSId = (0, credentials_1.getKMSIdByAuthCredential)(credential);
|
|
258
269
|
const payload = js_crypto_1.poseidon.hashBytes(message);
|
|
259
270
|
const signature = await this._kms.sign(keyKMSId, js_iden3_core_1.BytesHelper.intToBytes(payload));
|
|
260
271
|
return js_crypto_1.Signature.newFromCompressed(signature);
|
|
261
272
|
}
|
|
262
273
|
/** {@inheritDoc IIdentityWallet.signChallenge} */
|
|
263
274
|
async signChallenge(challenge, credential) {
|
|
264
|
-
const keyKMSId =
|
|
275
|
+
const keyKMSId = (0, credentials_1.getKMSIdByAuthCredential)(credential);
|
|
265
276
|
const signature = await this._kms.sign(keyKMSId, js_iden3_core_1.BytesHelper.intToBytes(challenge));
|
|
266
277
|
return js_crypto_1.Signature.newFromCompressed(signature);
|
|
267
278
|
}
|
|
@@ -358,11 +369,11 @@ class IdentityWallet {
|
|
|
358
369
|
if (!coreClaim) {
|
|
359
370
|
throw new Error('credential must have coreClaim representation in the signature proof');
|
|
360
371
|
}
|
|
361
|
-
await this._storage.mt.addToMerkleTree(issuerDID.string(),
|
|
372
|
+
await this._storage.mt.addToMerkleTree(issuerDID.string(), storage_1.MerkleTreeType.Claims, coreClaim.hIndex(), coreClaim.hValue());
|
|
362
373
|
}
|
|
363
374
|
const newIssuerTreeState = await this.getDIDTreeModel(issuerDID);
|
|
364
375
|
const claimTreeRoot = await newIssuerTreeState.claimsTree.root();
|
|
365
|
-
await this._storage.mt.addToMerkleTree(issuerDID.string(),
|
|
376
|
+
await this._storage.mt.addToMerkleTree(issuerDID.string(), storage_1.MerkleTreeType.Roots, claimTreeRoot.bigInt(), BigInt(0));
|
|
366
377
|
const newIssuerTreeStateWithROR = await this.getDIDTreeModel(issuerDID);
|
|
367
378
|
claimsRoot = await newIssuerTreeStateWithROR.claimsTree.root();
|
|
368
379
|
rootOfRoots = await newIssuerTreeStateWithROR.rootsTree.root();
|
|
@@ -429,15 +440,35 @@ class IdentityWallet {
|
|
|
429
440
|
rootsTree: treeState.rootsTree
|
|
430
441
|
}, rhsURL, revokedNonces);
|
|
431
442
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
443
|
+
/** {@inheritDoc IIdentityWallet.publishRevocationInfoByCredentialStatusType} */
|
|
444
|
+
async publishRevocationInfoByCredentialStatusType(issuerDID, credentialStatusType, opts) {
|
|
445
|
+
const rhsPublishers = this._credentialStatusPublisherRegistry.get(credentialStatusType);
|
|
446
|
+
if (!rhsPublishers) {
|
|
447
|
+
throw new Error(`there is no registered publisher to save hash is not registered for ${credentialStatusType} is not registered`);
|
|
448
|
+
}
|
|
449
|
+
let nodes = [];
|
|
450
|
+
if (opts?.treeModel) {
|
|
451
|
+
nodes = await (0, credentials_1.getNodesRepresentation)(opts.revokedNonces, {
|
|
452
|
+
revocationTree: opts.treeModel.revocationTree,
|
|
453
|
+
claimsTree: opts.treeModel.claimsTree,
|
|
454
|
+
state: opts.treeModel.state,
|
|
455
|
+
rootsTree: opts.treeModel.rootsTree
|
|
456
|
+
}, opts.treeModel.state);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
const treeState = await this.getDIDTreeModel(issuerDID);
|
|
460
|
+
nodes = await (0, credentials_1.getNodesRepresentation)(opts?.revokedNonces, {
|
|
461
|
+
revocationTree: treeState.revocationTree,
|
|
462
|
+
claimsTree: treeState.claimsTree,
|
|
463
|
+
state: treeState.state,
|
|
464
|
+
rootsTree: treeState.rootsTree
|
|
465
|
+
}, treeState.state);
|
|
466
|
+
}
|
|
467
|
+
if (!nodes.length) {
|
|
468
|
+
return;
|
|
435
469
|
}
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
const pb = new js_crypto_1.PublicKey([BigInt(x), BigInt(y)]);
|
|
439
|
-
const kp = (0, provider_helpers_1.keyPath)(kms_1.KmsKeyType.BabyJubJub, pb.hex());
|
|
440
|
-
return { type: kms_1.KmsKeyType.BabyJubJub, id: kp };
|
|
470
|
+
const rhsPublishersTask = rhsPublishers.map((publisher) => publisher.publish({ nodes, ...opts, credentialStatusType, issuerDID }));
|
|
471
|
+
await Promise.all(rhsPublishersTask);
|
|
441
472
|
}
|
|
442
473
|
async getCoreClaimFromCredential(credential) {
|
|
443
474
|
const coreClaimFromSigProof = credential.getCoreClaimFromProof(verifiable_1.ProofType.BJJSignature);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{ "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatus", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "
|
|
1
|
+
[{ "inputs": [], "name": "MAX_SMT_DEPTH", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "key", "type": "uint256" }], "name": "getNode", "outputs": [{ "internalType": "uint256[]", "name": "", "type": "uint256[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatus", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" }], "name": "getRevocationStatusByIdAndState", "outputs": [{ "components": [{ "components": [{ "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [{ "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" }], "internalType": "struct IOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" }], "internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [{ "internalType": "address", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint256[][]", "name": "nodes", "type": "uint256[][]" }], "name": "saveNodes", "outputs": [], "stateMutability": "nonpayable", "type": "function" }]
|
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./state"), exports);
|
|
18
18
|
__exportStar(require("./onchain-zkp-verifier"), exports);
|
|
19
|
+
__exportStar(require("./onchain-revocation"), exports);
|
|
@@ -22,9 +22,16 @@ class OnChainRevocationStorage {
|
|
|
22
22
|
* @param {string} - onhcain contract address
|
|
23
23
|
* @param {string} - rpc url to connect to the blockchain
|
|
24
24
|
*/
|
|
25
|
-
constructor(
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
25
|
+
constructor(_config, contractAddress, _signer) {
|
|
26
|
+
this._config = _config;
|
|
27
|
+
this._signer = _signer;
|
|
28
|
+
this._provider = new ethers_1.JsonRpcProvider(_config.url);
|
|
29
|
+
let contract = new ethers_1.Contract(contractAddress, CredentialStatusResolver_json_1.default, this._provider);
|
|
30
|
+
if (this._signer) {
|
|
31
|
+
this._signer = this._signer.connect(this._provider);
|
|
32
|
+
contract = contract.connect(this._signer);
|
|
33
|
+
}
|
|
34
|
+
this._contract = contract;
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* Get revocation status by issuerId, issuerState and nonce from the onchain.
|
|
@@ -32,7 +39,7 @@ class OnChainRevocationStorage {
|
|
|
32
39
|
* @returns Promise<RevocationStatus>
|
|
33
40
|
*/
|
|
34
41
|
async getRevocationStatusByIdAndState(issuerID, state, nonce) {
|
|
35
|
-
const response = await this.
|
|
42
|
+
const response = await this._contract.getRevocationStatusByIdAndState(issuerID, state, nonce);
|
|
36
43
|
const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer);
|
|
37
44
|
const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp);
|
|
38
45
|
return {
|
|
@@ -46,7 +53,7 @@ class OnChainRevocationStorage {
|
|
|
46
53
|
* @returns Promise<RevocationStatus>
|
|
47
54
|
*/
|
|
48
55
|
async getRevocationStatus(issuerID, nonce) {
|
|
49
|
-
const response = await this.
|
|
56
|
+
const response = await this._contract.getRevocationStatus(issuerID, nonce);
|
|
50
57
|
const issuer = OnChainRevocationStorage.convertIssuerInfo(response.issuer);
|
|
51
58
|
const mtp = OnChainRevocationStorage.convertSmtProofToProof(response.mtp);
|
|
52
59
|
return {
|
|
@@ -54,6 +61,39 @@ class OnChainRevocationStorage {
|
|
|
54
61
|
mtp
|
|
55
62
|
};
|
|
56
63
|
}
|
|
64
|
+
async saveNodes(payload) {
|
|
65
|
+
if (!this._signer) {
|
|
66
|
+
throw new Error('No signer provided');
|
|
67
|
+
}
|
|
68
|
+
const feeData = await this._provider.getFeeData();
|
|
69
|
+
const maxFeePerGas = this._config.maxFeePerGas
|
|
70
|
+
? BigInt(this._config.maxFeePerGas)
|
|
71
|
+
: feeData.maxFeePerGas;
|
|
72
|
+
const maxPriorityFeePerGas = this._config.maxPriorityFeePerGas
|
|
73
|
+
? BigInt(this._config.maxPriorityFeePerGas)
|
|
74
|
+
: feeData.maxPriorityFeePerGas;
|
|
75
|
+
const gasLimit = await this._contract.saveNodes.estimateGas(payload);
|
|
76
|
+
const txData = await this._contract.saveNodes.populateTransaction(payload);
|
|
77
|
+
const request = {
|
|
78
|
+
to: txData.to,
|
|
79
|
+
data: txData.data,
|
|
80
|
+
gasLimit,
|
|
81
|
+
maxFeePerGas,
|
|
82
|
+
maxPriorityFeePerGas
|
|
83
|
+
};
|
|
84
|
+
const tx = await this._signer.sendTransaction(request);
|
|
85
|
+
return tx.wait().then((txReceipt) => {
|
|
86
|
+
if (!txReceipt) {
|
|
87
|
+
throw new Error(`transaction: ${tx.hash} failed to mine`);
|
|
88
|
+
}
|
|
89
|
+
const status = txReceipt.status;
|
|
90
|
+
const txnHash = txReceipt.hash;
|
|
91
|
+
if (!status) {
|
|
92
|
+
throw new Error(`transaction: ${txnHash} failed to mine`);
|
|
93
|
+
}
|
|
94
|
+
return txReceipt;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
57
97
|
static convertIssuerInfo(issuer) {
|
|
58
98
|
const [state, claimsTreeRoot, revocationTreeRoot, rootOfRoots] = issuer.map((i) => js_merkletree_1.Hash.fromBigInt(i).hex());
|
|
59
99
|
return {
|
|
@@ -50,12 +50,12 @@ export const QueryOperators = {
|
|
|
50
50
|
};
|
|
51
51
|
const allOperations = Object.values(QueryOperators);
|
|
52
52
|
export const availableTypesOperators = new Map([
|
|
53
|
-
[XSDNS.Boolean, [QueryOperators.$eq, QueryOperators.$ne]],
|
|
53
|
+
[XSDNS.Boolean, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$sd]],
|
|
54
54
|
[XSDNS.Integer, allOperations],
|
|
55
55
|
[XSDNS.NonNegativeInteger, allOperations],
|
|
56
56
|
[XSDNS.PositiveInteger, allOperations],
|
|
57
|
-
[XSDNS.Double, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin]],
|
|
58
|
-
[XSDNS.String, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin]],
|
|
57
|
+
[XSDNS.Double, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin, QueryOperators.$sd]],
|
|
58
|
+
[XSDNS.String, [QueryOperators.$eq, QueryOperators.$ne, QueryOperators.$in, QueryOperators.$nin, QueryOperators.$sd]],
|
|
59
59
|
[XSDNS.DateTime, allOperations]
|
|
60
60
|
]);
|
|
61
61
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DID } from '@iden3/js-iden3-core';
|
|
1
|
+
import { DID, getChainId } from '@iden3/js-iden3-core';
|
|
2
2
|
import { W3CCredential, VerifiableConstants, CredentialStatusType } from './../verifiable';
|
|
3
3
|
import * as uuid from 'uuid';
|
|
4
4
|
import { CredentialStatusResolverRegistry } from './status/resolver';
|
|
@@ -57,7 +57,7 @@ export class CredentialWallet {
|
|
|
57
57
|
id: request.credentialSchema,
|
|
58
58
|
type: VerifiableConstants.JSON_SCHEMA_VALIDATOR
|
|
59
59
|
};
|
|
60
|
-
cr.credentialStatus = this.buildCredentialStatus(request);
|
|
60
|
+
cr.credentialStatus = this.buildCredentialStatus(request, issuer);
|
|
61
61
|
return cr;
|
|
62
62
|
};
|
|
63
63
|
// if no credential status resolvers are provided
|
|
@@ -123,7 +123,7 @@ export class CredentialWallet {
|
|
|
123
123
|
* @param {CredentialRequest} request
|
|
124
124
|
* @returns `CredentialStatus`
|
|
125
125
|
*/
|
|
126
|
-
buildCredentialStatus(request) {
|
|
126
|
+
buildCredentialStatus(request, issuer) {
|
|
127
127
|
const credentialStatus = {
|
|
128
128
|
id: request.revocationOpts.id,
|
|
129
129
|
type: request.revocationOpts.type,
|
|
@@ -142,6 +142,23 @@ export class CredentialWallet {
|
|
|
142
142
|
? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${request.revocationOpts.issuerState}`
|
|
143
143
|
: `${credentialStatus.id.replace(/\/$/, '')}`
|
|
144
144
|
};
|
|
145
|
+
case CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: {
|
|
146
|
+
const issuerId = DID.idFromDID(issuer);
|
|
147
|
+
const chainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId));
|
|
148
|
+
const searchParams = [
|
|
149
|
+
['revocationNonce', request.revocationOpts.nonce?.toString() || ''],
|
|
150
|
+
['contractAddress', `${chainId}:${request.revocationOpts.id}`],
|
|
151
|
+
['state', request.revocationOpts.issuerState || '']
|
|
152
|
+
]
|
|
153
|
+
.filter(([, value]) => Boolean(value))
|
|
154
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
155
|
+
.join('&');
|
|
156
|
+
return {
|
|
157
|
+
...credentialStatus,
|
|
158
|
+
// `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)`
|
|
159
|
+
id: `${issuer.string()}/credentialStatus?${searchParams}`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
145
162
|
default:
|
|
146
163
|
return credentialStatus;
|
|
147
164
|
}
|
|
@@ -3,6 +3,7 @@ export * from './status/reverse-sparse-merkle-tree';
|
|
|
3
3
|
export * from './status/sparse-merkle-tree';
|
|
4
4
|
export * from './status/resolver';
|
|
5
5
|
export * from './status/agent-revocation';
|
|
6
|
+
export * from './status/credential-status-publisher';
|
|
6
7
|
export * from './status/utils';
|
|
7
8
|
export * from './credential-wallet';
|
|
8
9
|
export * from './rhs';
|