@0xpolygonid/js-sdk 1.23.0 → 1.25.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/dist/browser/esm/index.js +2573 -392
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +2575 -390
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/circuits/auth-v2.js +6 -0
- package/dist/node/cjs/credentials/credential-wallet.js +11 -78
- package/dist/node/cjs/credentials/index.js +1 -0
- package/dist/node/cjs/credentials/status/did-resolver-revocation.js +21 -0
- package/dist/node/cjs/iden3comm/handlers/contract-request.js +7 -1
- package/dist/node/cjs/iden3comm/handlers/fetch.js +32 -0
- package/dist/node/cjs/iden3comm/handlers/payment.js +30 -24
- package/dist/node/cjs/iden3comm/utils/contract-request.utils.js +59 -0
- package/dist/node/cjs/iden3comm/utils/index.js +1 -0
- package/dist/node/cjs/proof/proof-service.js +6 -0
- package/dist/node/cjs/storage/blockchain/abi/ERC20.json +1 -0
- package/dist/node/cjs/storage/blockchain/did-resolver-readonly-storage.js +72 -0
- package/dist/node/cjs/storage/blockchain/{erc20-permit-sig.js → erc20-helper.js} +14 -1
- package/dist/node/cjs/storage/blockchain/index.js +3 -1
- package/dist/node/cjs/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +245 -0
- package/dist/node/cjs/storage/blockchain/onchain-issuer.js +82 -0
- package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +90 -77
- package/dist/node/cjs/storage/interfaces/index.js +1 -0
- package/dist/node/cjs/storage/interfaces/onchain-issuer.js +2 -0
- package/dist/node/cjs/utils/did-helper.js +11 -6
- package/dist/node/cjs/verifiable/constants.js +2 -2
- package/dist/node/cjs/verifiable/credential.js +86 -0
- package/dist/node/esm/circuits/auth-v2.js +6 -0
- package/dist/node/esm/credentials/credential-wallet.js +12 -79
- package/dist/node/esm/credentials/index.js +1 -0
- package/dist/node/esm/credentials/status/did-resolver-revocation.js +17 -0
- package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -1
- package/dist/node/esm/iden3comm/handlers/fetch.js +32 -0
- package/dist/node/esm/iden3comm/handlers/payment.js +30 -24
- package/dist/node/esm/iden3comm/utils/contract-request.utils.js +54 -0
- package/dist/node/esm/iden3comm/utils/index.js +1 -0
- package/dist/node/esm/proof/proof-service.js +6 -0
- package/dist/node/esm/storage/blockchain/abi/ERC20.json +1 -0
- package/dist/node/esm/storage/blockchain/did-resolver-readonly-storage.js +68 -0
- package/dist/node/esm/storage/blockchain/{erc20-permit-sig.js → erc20-helper.js} +14 -2
- package/dist/node/esm/storage/blockchain/index.js +3 -1
- package/dist/node/esm/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +241 -0
- package/dist/node/esm/storage/blockchain/onchain-issuer.js +78 -0
- package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +92 -79
- package/dist/node/esm/storage/interfaces/index.js +1 -0
- package/dist/node/esm/storage/interfaces/onchain-issuer.js +1 -0
- package/dist/node/esm/utils/did-helper.js +11 -6
- package/dist/node/esm/verifiable/constants.js +2 -2
- package/dist/node/esm/verifiable/credential.js +88 -2
- package/dist/types/circuits/auth-v2.d.ts +3 -2
- package/dist/types/credentials/credential-wallet.d.ts +0 -6
- package/dist/types/credentials/index.d.ts +1 -0
- package/dist/types/credentials/models.d.ts +8 -0
- package/dist/types/credentials/status/did-resolver-revocation.d.ts +7 -0
- package/dist/types/iden3comm/handlers/fetch.d.ts +8 -0
- package/dist/types/iden3comm/handlers/payment.d.ts +7 -10
- package/dist/types/iden3comm/types/protocol/payment.d.ts +6 -5
- package/dist/types/iden3comm/utils/contract-request.utils.d.ts +20 -0
- package/dist/types/iden3comm/utils/index.d.ts +1 -0
- package/dist/types/proof/proof-service.d.ts +10 -0
- package/dist/types/storage/blockchain/did-resolver-readonly-storage.d.ts +16 -0
- package/dist/types/storage/blockchain/{erc20-permit-sig.d.ts → erc20-helper.d.ts} +8 -1
- package/dist/types/storage/blockchain/index.d.ts +3 -1
- package/dist/types/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.d.ts +66 -0
- package/dist/types/storage/blockchain/onchain-issuer.d.ts +40 -0
- package/dist/types/storage/blockchain/onchain-zkp-verifier.d.ts +13 -12
- package/dist/types/storage/entities/state.d.ts +2 -0
- package/dist/types/storage/interfaces/index.d.ts +1 -0
- package/dist/types/storage/interfaces/onchain-issuer.d.ts +12 -0
- package/dist/types/verifiable/constants.d.ts +2 -2
- package/dist/types/verifiable/credential.d.ts +15 -2
- package/package.json +3 -2
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { Claim, DID, Id } from '@iden3/js-iden3-core';
|
|
2
|
+
import { NonMerklizedIssuerBase__factory } from '@iden3/onchain-non-merklized-issuer-base-abi';
|
|
3
|
+
import { CredentialStatusType, DisplayMethodType, Iden3SparseMerkleTreeProof, W3CCredential } from '../../../../../../verifiable';
|
|
4
|
+
import { Merklizer, Path } from '@iden3/js-jsonld-merklization';
|
|
5
|
+
import { XSDNS } from '../../../../../../circuits';
|
|
6
|
+
import { Hash, Proof } from '@iden3/js-merkletree';
|
|
7
|
+
import { ethers } from 'ethers';
|
|
8
|
+
import { getDateFromUnixTimestamp } from '@iden3/js-iden3-core';
|
|
9
|
+
var NonMerklizedIssuerInterfaces;
|
|
10
|
+
(function (NonMerklizedIssuerInterfaces) {
|
|
11
|
+
NonMerklizedIssuerInterfaces["InterfaceDetection"] = "0x01ffc9a7";
|
|
12
|
+
NonMerklizedIssuerInterfaces["InterfaceNonMerklizedIssuer"] = "0x58874949";
|
|
13
|
+
NonMerklizedIssuerInterfaces["InterfaceGetCredential"] = "0x5d1ca631";
|
|
14
|
+
})(NonMerklizedIssuerInterfaces || (NonMerklizedIssuerInterfaces = {}));
|
|
15
|
+
var ValueHashes;
|
|
16
|
+
(function (ValueHashes) {
|
|
17
|
+
ValueHashes["BooleanTrue"] = "18586133768512220936620570745912940619677854269274689475585506675881198879027";
|
|
18
|
+
ValueHashes["BooleanFalse"] = "19014214495641488759237505126948346942972912379615652741039992445865937985820";
|
|
19
|
+
})(ValueHashes || (ValueHashes = {}));
|
|
20
|
+
/**
|
|
21
|
+
* `OnchainNonMerklizedIssuerAdapter` provides functionality to interact with a non-merklized on-chain credential issuer.
|
|
22
|
+
* This adapter enables interface detection, credential retrieval, and conversion to the W3C Verifiable Credential format.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
* @beta
|
|
26
|
+
* @class OnchainNonMerklizedIssuerAdapter
|
|
27
|
+
*/
|
|
28
|
+
export class OnchainNonMerklizedIssuerAdapter {
|
|
29
|
+
/**
|
|
30
|
+
* Initializes an instance of `OnchainNonMerklizedIssuerAdapter`.
|
|
31
|
+
*
|
|
32
|
+
* @param ethConnectionConfig The configuration for the Ethereum connection.
|
|
33
|
+
* @param issuerDid The decentralized identifier (DID) of the issuer.
|
|
34
|
+
* @param merklizationOptions Optional settings for merklization.
|
|
35
|
+
*/
|
|
36
|
+
constructor(ethConnectionConfig, issuerDid, options) {
|
|
37
|
+
if (!ethConnectionConfig.chainId) {
|
|
38
|
+
throw new Error('Chain ID is required');
|
|
39
|
+
}
|
|
40
|
+
this._chainId = ethConnectionConfig.chainId;
|
|
41
|
+
this._contractAddress = ethers.getAddress(ethers.hexlify(Id.ethAddressFromId(DID.idFromDID(issuerDid))));
|
|
42
|
+
this._contract = NonMerklizedIssuerBase__factory.connect(this._contractAddress, new ethers.JsonRpcProvider(ethConnectionConfig.url));
|
|
43
|
+
this._issuerDid = issuerDid;
|
|
44
|
+
this._merklizationOptions = options?.merklizationOptions;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the contract supports required interfaces.
|
|
48
|
+
* Throws an error if any required interface is unsupported.
|
|
49
|
+
*
|
|
50
|
+
* @throws Error - If required interfaces are not supported.
|
|
51
|
+
*/
|
|
52
|
+
async isInterfaceSupported() {
|
|
53
|
+
const supportedInterfaces = [
|
|
54
|
+
{
|
|
55
|
+
name: 'Interface detection ERC-165',
|
|
56
|
+
value: NonMerklizedIssuerInterfaces.InterfaceDetection
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Interface non-merklized issuer',
|
|
60
|
+
value: NonMerklizedIssuerInterfaces.InterfaceNonMerklizedIssuer
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'Interface get credential',
|
|
64
|
+
value: NonMerklizedIssuerInterfaces.InterfaceGetCredential
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
const unsupportedInterfaces = await Promise.all(supportedInterfaces.map(async (interfaceObj) => {
|
|
68
|
+
const isSupported = await this._contract.supportsInterface(interfaceObj.value);
|
|
69
|
+
return isSupported ? null : interfaceObj.name;
|
|
70
|
+
}));
|
|
71
|
+
const unsupportedInterfacesFiltered = unsupportedInterfaces.filter((interfaceName) => interfaceName !== null);
|
|
72
|
+
if (unsupportedInterfacesFiltered.length > 0) {
|
|
73
|
+
throw new Error(`Unsupported interfaces: ${unsupportedInterfacesFiltered.join(', ')}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Retrieves a credential from the on-chain non-merklized contract.
|
|
78
|
+
* @param userId The user's core.Id.
|
|
79
|
+
* @param credentialId The unique identifier of the credential.
|
|
80
|
+
*/
|
|
81
|
+
async getCredential(userId, credentialId) {
|
|
82
|
+
const [credentialData, coreClaimBigInts, credentialSubjectFields] = await this._contract.getCredential(userId.bigInt(), credentialId);
|
|
83
|
+
return { credentialData, coreClaimBigInts, credentialSubjectFields };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Retrieves the credential IDs of a user.
|
|
87
|
+
* @param userId The user's core.Id.
|
|
88
|
+
* @returns An array of credential IDs.
|
|
89
|
+
*/
|
|
90
|
+
async getUserCredentialsIds(userId) {
|
|
91
|
+
return this._contract.getUserCredentialIds(userId.bigInt());
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Converts on-chain credential to a verifiable credential.
|
|
95
|
+
*
|
|
96
|
+
* @param credentialData Data structure of the credential from the contract.
|
|
97
|
+
* @param coreClaimBigInts Claim data in bigint format.
|
|
98
|
+
* @param credentialSubjectFields Subject fields of the credential.
|
|
99
|
+
*/
|
|
100
|
+
async convertOnChainInfoToW3CCredential(credentialData, coreClaimBigInts, credentialSubjectFields) {
|
|
101
|
+
const c = new Claim().unMarshalJson(JSON.stringify(coreClaimBigInts.map((b) => b.toString())));
|
|
102
|
+
const credentialSubject = await this.convertCredentialSubject(c, credentialData.context, credentialData._type, credentialSubjectFields);
|
|
103
|
+
const credentialRequest = {
|
|
104
|
+
id: this.credentialId(credentialData.id),
|
|
105
|
+
credentialSchema: credentialData.credentialSchema.id,
|
|
106
|
+
type: credentialData._type,
|
|
107
|
+
credentialSubject: credentialSubject,
|
|
108
|
+
expiration: c.getExpirationDate()?.getTime(),
|
|
109
|
+
displayMethod: this.convertDisplayMethod(credentialData.displayMethod),
|
|
110
|
+
context: credentialData.context,
|
|
111
|
+
revocationOpts: {
|
|
112
|
+
id: this._contractAddress,
|
|
113
|
+
nonce: Number(c.getRevocationNonce()),
|
|
114
|
+
type: CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023
|
|
115
|
+
},
|
|
116
|
+
issuanceDate: getDateFromUnixTimestamp(Number(credentialData.issuanceDate)).getTime()
|
|
117
|
+
};
|
|
118
|
+
const existenceProof = await this.existenceProof(c);
|
|
119
|
+
const w3c = W3CCredential.fromCredentialRequest(this._issuerDid, credentialRequest);
|
|
120
|
+
w3c.proof = [existenceProof];
|
|
121
|
+
return w3c;
|
|
122
|
+
}
|
|
123
|
+
credentialId(id) {
|
|
124
|
+
return `urn:iden3:onchain:${this._chainId}:${this._contractAddress}:${id}`;
|
|
125
|
+
}
|
|
126
|
+
async convertCredentialSubject(coreClaim, contractContexts, credentialType, credentialSubjectFields) {
|
|
127
|
+
const contractContextsStr = JSON.stringify({
|
|
128
|
+
'@context': contractContexts
|
|
129
|
+
});
|
|
130
|
+
const credentialSubject = {};
|
|
131
|
+
for (const f of credentialSubjectFields) {
|
|
132
|
+
const dataType = await Path.newTypeFromContext(contractContextsStr, `${credentialType}.${f.key}`, this._merklizationOptions);
|
|
133
|
+
switch (dataType) {
|
|
134
|
+
case XSDNS.Boolean: {
|
|
135
|
+
switch (f.rawValue.toString()) {
|
|
136
|
+
case ValueHashes.BooleanTrue:
|
|
137
|
+
credentialSubject[f.key] = true;
|
|
138
|
+
break;
|
|
139
|
+
case ValueHashes.BooleanFalse:
|
|
140
|
+
credentialSubject[f.key] = false;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case (XSDNS.NonNegativeInteger,
|
|
146
|
+
XSDNS.NonPositiveInteger,
|
|
147
|
+
XSDNS.NegativeInteger,
|
|
148
|
+
XSDNS.PositiveInteger):
|
|
149
|
+
{
|
|
150
|
+
credentialSubject[f.key] = f.value.toString();
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case XSDNS.Integer: {
|
|
154
|
+
credentialSubject[f.key] = Number(f.value);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case XSDNS.String: {
|
|
158
|
+
this.validateSourceValue(dataType, f.value, f.rawValue);
|
|
159
|
+
credentialSubject[f.key] = f.rawValue;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case XSDNS.DateTime: {
|
|
163
|
+
const timestamp = BigInt(f.rawValue);
|
|
164
|
+
const sourceTimestamp = getDateFromUnixTimestamp(Number(timestamp)).toISOString();
|
|
165
|
+
this.validateSourceValue(dataType, f.value, sourceTimestamp);
|
|
166
|
+
credentialSubject[f.key] = sourceTimestamp;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case XSDNS.Double: {
|
|
170
|
+
const rawFloat = Number(f.rawValue);
|
|
171
|
+
this.validateSourceValue(dataType, f.value, rawFloat);
|
|
172
|
+
credentialSubject[f.key] = rawFloat;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
default: {
|
|
176
|
+
throw new Error(`Unsupported data type ${dataType}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
credentialSubject['type'] = credentialType;
|
|
181
|
+
const subjectId = coreClaim.getId();
|
|
182
|
+
const subjectDid = DID.parseFromId(subjectId);
|
|
183
|
+
credentialSubject['id'] = subjectDid.string();
|
|
184
|
+
return credentialSubject;
|
|
185
|
+
}
|
|
186
|
+
async existenceProof(coreClaim) {
|
|
187
|
+
const [mtpProof, stateInfo] = await this._contract.getClaimProofWithStateInfo(coreClaim.hIndex());
|
|
188
|
+
if (!mtpProof.existence) {
|
|
189
|
+
throw new Error('Claim does not exist');
|
|
190
|
+
}
|
|
191
|
+
const latestStateHash = Hash.fromBigInt(stateInfo.state);
|
|
192
|
+
const latestClaimsOfRootHash = Hash.fromBigInt(stateInfo.claimsRoot);
|
|
193
|
+
const latestRevocationOfRootHash = Hash.fromBigInt(stateInfo.revocationsRoot);
|
|
194
|
+
const latestRootsOfRootHash = Hash.fromBigInt(stateInfo.rootsRoot);
|
|
195
|
+
const p = new Proof({
|
|
196
|
+
siblings: mtpProof.siblings.map((s) => Hash.fromBigInt(s)),
|
|
197
|
+
existence: mtpProof.existence,
|
|
198
|
+
nodeAux: mtpProof.auxExistence
|
|
199
|
+
? {
|
|
200
|
+
key: Hash.fromBigInt(mtpProof.auxIndex),
|
|
201
|
+
value: Hash.fromBigInt(mtpProof.auxValue)
|
|
202
|
+
}
|
|
203
|
+
: undefined
|
|
204
|
+
});
|
|
205
|
+
return new Iden3SparseMerkleTreeProof({
|
|
206
|
+
issuerData: {
|
|
207
|
+
id: this._issuerDid,
|
|
208
|
+
state: {
|
|
209
|
+
value: latestStateHash,
|
|
210
|
+
claimsTreeRoot: latestClaimsOfRootHash,
|
|
211
|
+
revocationTreeRoot: latestRevocationOfRootHash,
|
|
212
|
+
rootOfRoots: latestRootsOfRootHash
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
mtp: p,
|
|
216
|
+
coreClaim: coreClaim
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async validateSourceValue(dataType, originHash, source) {
|
|
220
|
+
const sourceHash = await Merklizer.hashValue(dataType, source);
|
|
221
|
+
if (sourceHash !== originHash) {
|
|
222
|
+
throw new Error(`Invalid source value for ${dataType} type`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
convertDisplayMethod(onchainDisplayMethod) {
|
|
226
|
+
if (!onchainDisplayMethod.id || !onchainDisplayMethod._type) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
switch (onchainDisplayMethod._type) {
|
|
230
|
+
case DisplayMethodType.Iden3BasicDisplayMethodV1: {
|
|
231
|
+
return {
|
|
232
|
+
id: onchainDisplayMethod.id,
|
|
233
|
+
type: DisplayMethodType.Iden3BasicDisplayMethodV1
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
default: {
|
|
237
|
+
throw new Error(`Unsupported display method type ${onchainDisplayMethod._type}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DID, Id, chainIDfromDID } from '@iden3/js-iden3-core';
|
|
2
|
+
import { Contract, ethers } from 'ethers';
|
|
3
|
+
import { INonMerklizedIssuerABI as abi } from '@iden3/onchain-non-merklized-issuer-base-abi';
|
|
4
|
+
import { OnchainNonMerklizedIssuerAdapter } from './onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter';
|
|
5
|
+
/**
|
|
6
|
+
* Represents an adapter for interacting with on-chain issuers.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
* @beta
|
|
10
|
+
* @class OnchainIssuer
|
|
11
|
+
*/
|
|
12
|
+
export class OnchainIssuer {
|
|
13
|
+
/**
|
|
14
|
+
* Initializes an instance of `Adapter`.
|
|
15
|
+
* @param config The configuration for the Ethereum connection.
|
|
16
|
+
* @param merklizationOptions Optional settings for merklization.
|
|
17
|
+
*/
|
|
18
|
+
constructor(config, options) {
|
|
19
|
+
this._ethConnectionConfig = config;
|
|
20
|
+
this._onchainIssuerOptions = options;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves a credential from the on-chain issuer.
|
|
24
|
+
* @param issuerDID The issuer's core.DID.
|
|
25
|
+
* @param userId The user's core.Id.
|
|
26
|
+
* @param credentialId The unique identifier of the credential.
|
|
27
|
+
*/
|
|
28
|
+
async getCredential(issuerDID, userDID, credentialId) {
|
|
29
|
+
const { contract, connection } = this.getContractConnection(issuerDID);
|
|
30
|
+
const response = await contract.getCredentialAdapterVersion();
|
|
31
|
+
switch (response) {
|
|
32
|
+
case '0.0.1': {
|
|
33
|
+
const adapter = new OnchainNonMerklizedIssuerAdapter(connection, issuerDID, {
|
|
34
|
+
merklizationOptions: this._onchainIssuerOptions?.merklizationOptions
|
|
35
|
+
});
|
|
36
|
+
await adapter.isInterfaceSupported();
|
|
37
|
+
const { credentialData, coreClaimBigInts, credentialSubjectFields } = await adapter.getCredential(DID.idFromDID(userDID), credentialId);
|
|
38
|
+
return await adapter.convertOnChainInfoToW3CCredential(credentialData, coreClaimBigInts, credentialSubjectFields);
|
|
39
|
+
}
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unsupported adapter version ${response}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves the credential identifiers for a user from the on-chain issuer.
|
|
46
|
+
* @param issuerDID The issuer's core.DID.
|
|
47
|
+
* @param userId The user's core.Id.
|
|
48
|
+
*/
|
|
49
|
+
async getUserCredentialIds(issuerDID, userDID) {
|
|
50
|
+
const { contract, connection } = this.getContractConnection(issuerDID);
|
|
51
|
+
const response = await contract.getCredentialAdapterVersion();
|
|
52
|
+
switch (response) {
|
|
53
|
+
case '0.0.1': {
|
|
54
|
+
const adapter = new OnchainNonMerklizedIssuerAdapter(connection, issuerDID, {
|
|
55
|
+
merklizationOptions: this._onchainIssuerOptions?.merklizationOptions
|
|
56
|
+
});
|
|
57
|
+
await adapter.isInterfaceSupported();
|
|
58
|
+
return await adapter.getUserCredentialsIds(DID.idFromDID(userDID));
|
|
59
|
+
}
|
|
60
|
+
default:
|
|
61
|
+
throw new Error(`Unsupported adapter version ${response}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
getContractConnection(did) {
|
|
65
|
+
const issuerId = DID.idFromDID(did);
|
|
66
|
+
const chainId = chainIDfromDID(did);
|
|
67
|
+
const contractAddress = ethers.getAddress(ethers.hexlify(Id.ethAddressFromId(issuerId)));
|
|
68
|
+
const connection = this._ethConnectionConfig.find((c) => c.chainId === chainId);
|
|
69
|
+
if (!connection) {
|
|
70
|
+
throw new Error(`No connection found for chain ID ${chainId}`);
|
|
71
|
+
}
|
|
72
|
+
if (!connection.url) {
|
|
73
|
+
throw new Error(`No URL found for chain ID ${chainId}`);
|
|
74
|
+
}
|
|
75
|
+
const contract = new Contract(contractAddress, abi, new ethers.JsonRpcProvider(connection.url));
|
|
76
|
+
return { contract, connection };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { JsonRpcProvider, Contract, ethers } from 'ethers';
|
|
2
2
|
import abi from './abi/ZkpVerifier.json';
|
|
3
3
|
import { TransactionService } from '../../blockchain';
|
|
4
|
-
import { DID } from '@iden3/js-iden3-core';
|
|
5
|
-
import { AtomicQueryMTPV2OnChainPubSignals, AtomicQuerySigV2OnChainPubSignals, AtomicQueryV3OnChainPubSignals, CircuitId } from '../../circuits';
|
|
4
|
+
import { chainIDfromDID, DID, Id } from '@iden3/js-iden3-core';
|
|
5
|
+
import { AtomicQueryMTPV2OnChainPubSignals, AtomicQuerySigV2OnChainPubSignals, AtomicQueryV3OnChainPubSignals, AuthV2PubSignals, CircuitId } from '../../circuits';
|
|
6
6
|
import { byteEncoder, DIDDocumentSignature, resolveDidDocument } from '../../utils';
|
|
7
7
|
import { poseidon } from '@iden3/js-crypto';
|
|
8
|
+
import { Hash } from '@iden3/js-merkletree';
|
|
8
9
|
const maxGasLimit = 10000000n;
|
|
9
10
|
/**
|
|
10
11
|
* Supported function signature for SubmitZKPResponse
|
|
@@ -37,23 +38,8 @@ export class OnChainZKPVerifier {
|
|
|
37
38
|
constructor(_configs, _opts) {
|
|
38
39
|
this._configs = _configs;
|
|
39
40
|
this._opts = _opts;
|
|
40
|
-
/**
|
|
41
|
-
* supported circuits
|
|
42
|
-
*/
|
|
43
|
-
this._supportedCircuits = [
|
|
44
|
-
CircuitId.AtomicQueryMTPV2OnChain,
|
|
45
|
-
CircuitId.AtomicQuerySigV2OnChain,
|
|
46
|
-
CircuitId.AtomicQueryV3OnChain
|
|
47
|
-
];
|
|
48
|
-
/**
|
|
49
|
-
* abi coder to encode/decode structures to solidity bytes
|
|
50
|
-
*/
|
|
51
|
-
this._abiCoder = new ethers.AbiCoder();
|
|
52
41
|
}
|
|
53
|
-
|
|
54
|
-
* {@inheritDoc IOnChainZKPVerifier.prepareTxArgsSubmitV1}
|
|
55
|
-
*/
|
|
56
|
-
async prepareTxArgsSubmitV1(txData, zkProofResponse) {
|
|
42
|
+
static async prepareTxArgsSubmitV1(txData, zkProofResponse) {
|
|
57
43
|
if (txData.method_id.replace('0x', '') !== FunctionSignatures.SubmitZKPResponseV1) {
|
|
58
44
|
throw new Error(`prepareTxArgsSubmitV1 function doesn't implement requested method id. Only '0x${FunctionSignatures.SubmitZKPResponseV1}' is supported.`);
|
|
59
45
|
}
|
|
@@ -71,6 +57,12 @@ export class OnChainZKPVerifier {
|
|
|
71
57
|
];
|
|
72
58
|
return payload;
|
|
73
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* {@inheritDoc IOnChainZKPVerifier.prepareTxArgsSubmitV1}
|
|
62
|
+
*/
|
|
63
|
+
async prepareTxArgsSubmitV1(txData, zkProofResponse) {
|
|
64
|
+
return OnChainZKPVerifier.prepareTxArgsSubmitV1(txData, zkProofResponse);
|
|
65
|
+
}
|
|
74
66
|
/**
|
|
75
67
|
* {@inheritDoc IOnChainZKPVerifier.submitZKPResponse}
|
|
76
68
|
*/
|
|
@@ -160,55 +152,60 @@ export class OnChainZKPVerifier {
|
|
|
160
152
|
const { txnHash } = await transactionService.sendTransactionRequest(ethSigner, request);
|
|
161
153
|
return new Map().set(txnHash, zkProofResponses);
|
|
162
154
|
}
|
|
163
|
-
|
|
155
|
+
static getCrossChainResolvers(source, txDataChainId, type, didResolverUrl) {
|
|
156
|
+
return [
|
|
157
|
+
...new Set(source.map((info) => JSON.stringify({
|
|
158
|
+
id: info.id.string(),
|
|
159
|
+
[type]: type === 'gist' ? info.root?.string() : info.state?.string()
|
|
160
|
+
})))
|
|
161
|
+
].reduce((acc, s) => {
|
|
162
|
+
const info = JSON.parse(s);
|
|
163
|
+
const id = Id.fromString(info.id);
|
|
164
|
+
const chainId = chainIDfromDID(DID.parseFromId(id));
|
|
165
|
+
if (txDataChainId === chainId) {
|
|
166
|
+
return acc;
|
|
167
|
+
}
|
|
168
|
+
const promise = this.resolveDidDocumentEip712MessageAndSignature(DID.parseFromId(Id.fromString(info.id)), didResolverUrl, {
|
|
169
|
+
[type]: Hash.fromString(info[type])
|
|
170
|
+
});
|
|
171
|
+
return [...acc, promise];
|
|
172
|
+
}, []);
|
|
173
|
+
}
|
|
174
|
+
static async prepareTxArgsSubmitV2(resolverUrl, txData, zkProofResponses) {
|
|
164
175
|
if (txData.method_id.replace('0x', '') !== FunctionSignatures.SubmitZKPResponseV2) {
|
|
165
176
|
throw new Error(`submit cross chain doesn't implement requested method id. Only '0x${FunctionSignatures.SubmitZKPResponseV2}' is supported.`);
|
|
166
177
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
const gistUpdateArr = [];
|
|
171
|
-
const stateUpdateArr = [];
|
|
178
|
+
const gistUpdates = [];
|
|
179
|
+
const stateUpdates = [];
|
|
172
180
|
const payload = [];
|
|
173
|
-
|
|
174
|
-
const gistUpdateResolutionsPending = [];
|
|
175
|
-
const stateUpdateResolutionsPending = [];
|
|
181
|
+
const emptyBytes = '0x';
|
|
176
182
|
for (const zkProof of zkProofResponses) {
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
if (!this._supportedCircuits.includes(
|
|
183
|
+
const { id: requestId, pub_signals: inputs } = zkProof;
|
|
184
|
+
const proofCircuitId = zkProof.circuitId;
|
|
185
|
+
if (!this._supportedCircuits.includes(proofCircuitId)) {
|
|
180
186
|
throw new Error(`Circuit ${zkProof.circuitId} not supported by OnChainZKPVerifier`);
|
|
181
187
|
}
|
|
188
|
+
if (inputs.length === 0) {
|
|
189
|
+
payload.push({
|
|
190
|
+
requestId: requestId,
|
|
191
|
+
zkProof: emptyBytes,
|
|
192
|
+
data: emptyBytes
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
182
196
|
const zkProofEncoded = this.packZkpProof(inputs, zkProof.proof.pi_a.slice(0, 2), [
|
|
183
197
|
[zkProof.proof.pi_b[0][1], zkProof.proof.pi_b[0][0]],
|
|
184
198
|
[zkProof.proof.pi_b[1][1], zkProof.proof.pi_b[1][0]]
|
|
185
199
|
], zkProof.proof.pi_c.slice(0, 2));
|
|
186
|
-
const stateInfo = this.getOnChainGistRootStatePubSignals(
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (gistResolutionPending) {
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
gistUpdateResolutionsPending.push(JSON.stringify(gist));
|
|
194
|
-
gistUpdateResolutions.push(this.resolveDidDocumentEip712MessageAndSignature(DID.parseFromId(gist.id), this._opts.didResolverUrl, { gist: gist.root }));
|
|
195
|
-
}
|
|
196
|
-
const stateUpdateResolutions = [];
|
|
197
|
-
for (const state of stateInfo.states) {
|
|
198
|
-
const stateResolutionPending = stateUpdateResolutionsPending.find((s) => s == JSON.stringify(state));
|
|
199
|
-
if (stateResolutionPending) {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
stateUpdateResolutionsPending.push(JSON.stringify(state));
|
|
203
|
-
stateUpdateResolutions.push(this.resolveDidDocumentEip712MessageAndSignature(DID.parseFromId(state.id), this._opts.didResolverUrl, {
|
|
204
|
-
state: state.state
|
|
205
|
-
}));
|
|
206
|
-
}
|
|
200
|
+
const stateInfo = this.getOnChainGistRootStatePubSignals(proofCircuitId, inputs);
|
|
201
|
+
const chainId = txData.chain_id;
|
|
202
|
+
const gistUpdateResolutions = this.getCrossChainResolvers(stateInfo.gists, chainId, 'gist', resolverUrl);
|
|
203
|
+
const stateUpdateResolutions = this.getCrossChainResolvers(stateInfo.states, chainId, 'state', resolverUrl);
|
|
207
204
|
if (gistUpdateResolutions.length > 0) {
|
|
208
|
-
|
|
205
|
+
gistUpdates.push(...(await Promise.all(gistUpdateResolutions)));
|
|
209
206
|
}
|
|
210
207
|
if (stateUpdateResolutions.length > 0) {
|
|
211
|
-
|
|
208
|
+
stateUpdates.push(...(await Promise.all(stateUpdateResolutions)));
|
|
212
209
|
}
|
|
213
210
|
const metadataArr = [];
|
|
214
211
|
if (zkProof.vp) {
|
|
@@ -224,20 +221,28 @@ export class OnChainZKPVerifier {
|
|
|
224
221
|
});
|
|
225
222
|
}
|
|
226
223
|
}
|
|
227
|
-
const metadata = metadataArr.length ? this.packMetadatas(metadataArr) :
|
|
224
|
+
const metadata = metadataArr.length ? this.packMetadatas(metadataArr) : emptyBytes;
|
|
228
225
|
payload.push({
|
|
229
|
-
requestId:
|
|
226
|
+
requestId: requestId,
|
|
230
227
|
zkProof: zkProofEncoded,
|
|
231
228
|
data: metadata
|
|
232
229
|
});
|
|
233
230
|
}
|
|
234
|
-
const crossChainProofs =
|
|
231
|
+
const crossChainProofs = gistUpdates.length || stateUpdates.length
|
|
232
|
+
? this.packCrossChainProofs(gistUpdates, stateUpdates)
|
|
233
|
+
: emptyBytes;
|
|
235
234
|
return [payload, crossChainProofs];
|
|
236
235
|
}
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
async prepareTxArgsSubmitV2(txData, zkProofResponses) {
|
|
237
|
+
if (!this._opts?.didResolverUrl) {
|
|
238
|
+
throw new Error(`did resolver url required for crosschain verification`);
|
|
239
|
+
}
|
|
240
|
+
return OnChainZKPVerifier.prepareTxArgsSubmitV2(this._opts.didResolverUrl, txData, zkProofResponses);
|
|
239
241
|
}
|
|
240
|
-
|
|
242
|
+
static packZkpProof(inputs, a, b, c) {
|
|
243
|
+
return new ethers.AbiCoder().encode(['uint256[] inputs', 'uint256[2]', 'uint256[2][2]', 'uint256[2]'], [inputs, a, b, c]);
|
|
244
|
+
}
|
|
245
|
+
static packCrossChainProofs(gistUpdateArr, stateUpdateArr) {
|
|
241
246
|
const proofs = [];
|
|
242
247
|
for (const globalStateUpdate of gistUpdateArr) {
|
|
243
248
|
proofs.push({
|
|
@@ -251,10 +256,10 @@ export class OnChainZKPVerifier {
|
|
|
251
256
|
proof: this.packIdentityStateMsg(stateUpdate)
|
|
252
257
|
});
|
|
253
258
|
}
|
|
254
|
-
return
|
|
259
|
+
return new ethers.AbiCoder().encode(['tuple(' + 'string proofType,' + 'bytes proof' + ')[]'], [proofs]);
|
|
255
260
|
}
|
|
256
|
-
packGlobalStateMsg(msg) {
|
|
257
|
-
return
|
|
261
|
+
static packGlobalStateMsg(msg) {
|
|
262
|
+
return new ethers.AbiCoder().encode([
|
|
258
263
|
'tuple(' +
|
|
259
264
|
'tuple(' +
|
|
260
265
|
'uint256 timestamp,' +
|
|
@@ -266,8 +271,8 @@ export class OnChainZKPVerifier {
|
|
|
266
271
|
')'
|
|
267
272
|
], [msg]);
|
|
268
273
|
}
|
|
269
|
-
packIdentityStateMsg(msg) {
|
|
270
|
-
return
|
|
274
|
+
static packIdentityStateMsg(msg) {
|
|
275
|
+
return new ethers.AbiCoder().encode([
|
|
271
276
|
'tuple(' +
|
|
272
277
|
'tuple(' +
|
|
273
278
|
'uint256 timestamp,' +
|
|
@@ -279,27 +284,20 @@ export class OnChainZKPVerifier {
|
|
|
279
284
|
')'
|
|
280
285
|
], [msg]);
|
|
281
286
|
}
|
|
282
|
-
packMetadatas(metas) {
|
|
283
|
-
return
|
|
287
|
+
static packMetadatas(metas) {
|
|
288
|
+
return new ethers.AbiCoder().encode(['tuple(' + 'string key,' + 'bytes value' + ')[]'], [metas]);
|
|
284
289
|
}
|
|
285
|
-
getOnChainGistRootStatePubSignals(onChainCircuitId, inputs) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
atomicQueryPubSignals = new AtomicQueryMTPV2OnChainPubSignals();
|
|
290
|
-
break;
|
|
291
|
-
case CircuitId.AtomicQuerySigV2OnChain:
|
|
292
|
-
atomicQueryPubSignals = new AtomicQuerySigV2OnChainPubSignals();
|
|
293
|
-
break;
|
|
294
|
-
case CircuitId.AtomicQueryV3OnChain:
|
|
295
|
-
atomicQueryPubSignals = new AtomicQueryV3OnChainPubSignals();
|
|
296
|
-
break;
|
|
290
|
+
static getOnChainGistRootStatePubSignals(onChainCircuitId, inputs) {
|
|
291
|
+
const PubSignals = this._supportedCircuitsPubSignalsMap[onChainCircuitId];
|
|
292
|
+
if (!PubSignals) {
|
|
293
|
+
throw new Error(`Circuit ${onChainCircuitId} not supported by OnChainZKPVerifier`);
|
|
297
294
|
}
|
|
295
|
+
const atomicQueryPubSignals = new PubSignals();
|
|
298
296
|
const encodedInputs = byteEncoder.encode(JSON.stringify(inputs));
|
|
299
297
|
atomicQueryPubSignals.pubSignalsUnmarshal(encodedInputs);
|
|
300
298
|
return atomicQueryPubSignals.getStatesInfo();
|
|
301
299
|
}
|
|
302
|
-
async resolveDidDocumentEip712MessageAndSignature(did, resolverUrl, opts) {
|
|
300
|
+
static async resolveDidDocumentEip712MessageAndSignature(did, resolverUrl, opts) {
|
|
303
301
|
const didDoc = await resolveDidDocument(did, resolverUrl, {
|
|
304
302
|
...opts,
|
|
305
303
|
signature: DIDDocumentSignature.EthereumEip712Signature2021
|
|
@@ -332,3 +330,18 @@ export class OnChainZKPVerifier {
|
|
|
332
330
|
};
|
|
333
331
|
}
|
|
334
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* supported circuits
|
|
335
|
+
*/
|
|
336
|
+
OnChainZKPVerifier._supportedCircuits = [
|
|
337
|
+
CircuitId.AuthV2,
|
|
338
|
+
CircuitId.AtomicQueryMTPV2OnChain,
|
|
339
|
+
CircuitId.AtomicQuerySigV2OnChain,
|
|
340
|
+
CircuitId.AtomicQueryV3OnChain
|
|
341
|
+
];
|
|
342
|
+
OnChainZKPVerifier._supportedCircuitsPubSignalsMap = {
|
|
343
|
+
[CircuitId.AtomicQueryMTPV2OnChain]: AtomicQueryMTPV2OnChainPubSignals,
|
|
344
|
+
[CircuitId.AtomicQuerySigV2OnChain]: AtomicQuerySigV2OnChainPubSignals,
|
|
345
|
+
[CircuitId.AtomicQueryV3OnChain]: AtomicQueryV3OnChainPubSignals,
|
|
346
|
+
[CircuitId.AuthV2]: AuthV2PubSignals
|
|
347
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -65,7 +65,7 @@ export const validateDIDDocumentAuth = async (did, resolverURL, state) => {
|
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
67
|
export const resolveDIDDocumentAuth = async (did, resolveURL, state) => {
|
|
68
|
-
let url = `${resolveURL}/${did.string()
|
|
68
|
+
let url = `${resolveURL}/${encodeURIComponent(did.string())}`;
|
|
69
69
|
if (state) {
|
|
70
70
|
url += `?state=${state.hex()}`;
|
|
71
71
|
}
|
|
@@ -81,11 +81,11 @@ function emptyStateDID(did) {
|
|
|
81
81
|
return emptyDID;
|
|
82
82
|
}
|
|
83
83
|
export const resolveDidDocument = async (did, resolverUrl, opts) => {
|
|
84
|
-
let didString = did.string()
|
|
84
|
+
let didString = encodeURIComponent(did.string());
|
|
85
85
|
// for gist resolve we have to `hide` user did (look into resolver implementation)
|
|
86
86
|
const isGistRequest = opts?.gist && !opts.state;
|
|
87
87
|
if (isGistRequest) {
|
|
88
|
-
didString = emptyStateDID(did).string();
|
|
88
|
+
didString = encodeURIComponent(emptyStateDID(did).string());
|
|
89
89
|
}
|
|
90
90
|
let url = `${resolverUrl}/1.0/identifiers/${didString}`;
|
|
91
91
|
if (opts?.signature) {
|
|
@@ -97,9 +97,14 @@ export const resolveDidDocument = async (did, resolverUrl, opts) => {
|
|
|
97
97
|
if (opts?.gist) {
|
|
98
98
|
url += `${url.includes('?') ? '&' : '?'}gist=${opts.gist.hex()}`;
|
|
99
99
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
try {
|
|
101
|
+
const resp = await fetch(url);
|
|
102
|
+
const data = await resp.json();
|
|
103
|
+
return data;
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
throw new Error(`Failed to resolve DID document for ${did} ${e}`);
|
|
107
|
+
}
|
|
103
108
|
};
|
|
104
109
|
export const buildDIDFromEthPubKey = (didType, pubKeyEth) => {
|
|
105
110
|
// Use Keccak-256 hash function to get public key hash
|
|
@@ -146,6 +146,7 @@ export var SupportedPaymentProofType;
|
|
|
146
146
|
/**
|
|
147
147
|
* Media types for Payment supported currencies
|
|
148
148
|
* @beta
|
|
149
|
+
* @deprecated
|
|
149
150
|
* @enum {string}
|
|
150
151
|
*/
|
|
151
152
|
export var SupportedCurrencies;
|
|
@@ -154,8 +155,7 @@ export var SupportedCurrencies;
|
|
|
154
155
|
SupportedCurrencies["ETH_WEI"] = "ETHWEI";
|
|
155
156
|
SupportedCurrencies["ETH_GWEI"] = "ETHGWEI";
|
|
156
157
|
SupportedCurrencies["MATIC"] = "MATIC";
|
|
157
|
-
SupportedCurrencies["
|
|
158
|
-
SupportedCurrencies["USDC"] = "USDC";
|
|
158
|
+
SupportedCurrencies["POL"] = "POL";
|
|
159
159
|
})(SupportedCurrencies || (SupportedCurrencies = {}));
|
|
160
160
|
/**
|
|
161
161
|
* Supported features for payment-request
|