@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
|
@@ -51,6 +51,92 @@ class W3CCredential {
|
|
|
51
51
|
this.credentialSubject = {};
|
|
52
52
|
this.issuer = '';
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* @param issuer - DID of the issuer
|
|
57
|
+
* @param request - Credential request
|
|
58
|
+
* @returns - W3C Credential
|
|
59
|
+
*/
|
|
60
|
+
static fromCredentialRequest(issuer, request) {
|
|
61
|
+
if (!request.id) {
|
|
62
|
+
throw new Error('Credential id is required');
|
|
63
|
+
}
|
|
64
|
+
if (!request.context) {
|
|
65
|
+
throw new Error('Credential context is required');
|
|
66
|
+
}
|
|
67
|
+
const context = [
|
|
68
|
+
constants_1.VerifiableConstants.JSONLD_SCHEMA.W3C_CREDENTIAL_2018,
|
|
69
|
+
constants_1.VerifiableConstants.JSONLD_SCHEMA.IDEN3_CREDENTIAL,
|
|
70
|
+
...request.context
|
|
71
|
+
];
|
|
72
|
+
const credentialType = [
|
|
73
|
+
constants_1.VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_CREDENTIAL,
|
|
74
|
+
request.type
|
|
75
|
+
];
|
|
76
|
+
const credentialSubject = request.credentialSubject;
|
|
77
|
+
credentialSubject['type'] = request.type;
|
|
78
|
+
const cr = new W3CCredential();
|
|
79
|
+
cr.id = request.id;
|
|
80
|
+
cr['@context'] = context;
|
|
81
|
+
cr.type = credentialType;
|
|
82
|
+
cr.credentialSubject = credentialSubject;
|
|
83
|
+
cr.issuer = issuer.string();
|
|
84
|
+
cr.credentialSchema = {
|
|
85
|
+
id: request.credentialSchema,
|
|
86
|
+
type: constants_1.VerifiableConstants.JSON_SCHEMA_VALIDATOR
|
|
87
|
+
};
|
|
88
|
+
cr.credentialStatus = W3CCredential.buildCredentialStatus(request, issuer);
|
|
89
|
+
request.expiration && (cr.expirationDate = new Date(request.expiration).toISOString());
|
|
90
|
+
request.refreshService && (cr.refreshService = request.refreshService);
|
|
91
|
+
request.displayMethod && (cr.displayMethod = request.displayMethod);
|
|
92
|
+
request.issuanceDate && (cr.issuanceDate = new Date(request.issuanceDate).toISOString());
|
|
93
|
+
return cr;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Builds credential status
|
|
97
|
+
* @param {CredentialRequest} request
|
|
98
|
+
* @returns `CredentialStatus`
|
|
99
|
+
*/
|
|
100
|
+
static buildCredentialStatus(request, issuer) {
|
|
101
|
+
const credentialStatus = {
|
|
102
|
+
id: request.revocationOpts.id,
|
|
103
|
+
type: request.revocationOpts.type,
|
|
104
|
+
revocationNonce: request.revocationOpts.nonce
|
|
105
|
+
};
|
|
106
|
+
switch (request.revocationOpts.type) {
|
|
107
|
+
case constants_1.CredentialStatusType.SparseMerkleTreeProof:
|
|
108
|
+
return {
|
|
109
|
+
...credentialStatus,
|
|
110
|
+
id: `${credentialStatus.id.replace(/\/$/, '')}/${credentialStatus.revocationNonce}`
|
|
111
|
+
};
|
|
112
|
+
case constants_1.CredentialStatusType.Iden3ReverseSparseMerkleTreeProof:
|
|
113
|
+
return {
|
|
114
|
+
...credentialStatus,
|
|
115
|
+
id: request.revocationOpts.issuerState
|
|
116
|
+
? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${request.revocationOpts.issuerState}`
|
|
117
|
+
: `${credentialStatus.id.replace(/\/$/, '')}`
|
|
118
|
+
};
|
|
119
|
+
case constants_1.CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: {
|
|
120
|
+
const issuerId = js_iden3_core_1.DID.idFromDID(issuer);
|
|
121
|
+
const chainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(issuerId), js_iden3_core_1.DID.networkIdFromId(issuerId));
|
|
122
|
+
const searchParams = [
|
|
123
|
+
['revocationNonce', request.revocationOpts.nonce?.toString() || ''],
|
|
124
|
+
['contractAddress', `${chainId}:${request.revocationOpts.id}`],
|
|
125
|
+
['state', request.revocationOpts.issuerState || '']
|
|
126
|
+
]
|
|
127
|
+
.filter(([, value]) => Boolean(value))
|
|
128
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
129
|
+
.join('&');
|
|
130
|
+
return {
|
|
131
|
+
...credentialStatus,
|
|
132
|
+
// `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)`
|
|
133
|
+
id: `${issuer.string()}/credentialStatus?${searchParams}`
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
default:
|
|
137
|
+
return credentialStatus;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
54
140
|
toJSON() {
|
|
55
141
|
return {
|
|
56
142
|
...this,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DID
|
|
1
|
+
import { DID } from '@iden3/js-iden3-core';
|
|
2
2
|
import { W3CCredential, VerifiableConstants, CredentialStatusType, DisplayMethodType } from './../verifiable';
|
|
3
3
|
import * as uuid from 'uuid';
|
|
4
4
|
import { CredentialStatusResolverRegistry } from './status/resolver';
|
|
@@ -31,40 +31,18 @@ export class CredentialWallet {
|
|
|
31
31
|
if (!schema.$metadata.uris['jsonLdContext']) {
|
|
32
32
|
throw new Error('jsonLdContext is missing is the schema');
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// do copy of request to avoid mutation
|
|
35
|
+
const r = { ...request };
|
|
36
|
+
r.context = r.context ?? [];
|
|
37
|
+
if (r.displayMethod?.type === DisplayMethodType.Iden3BasicDisplayMethodV1 &&
|
|
38
|
+
!r.context.includes(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD)) {
|
|
39
|
+
r.context.push(VerifiableConstants.JSONLD_SCHEMA.IDEN3_DISPLAY_METHOD);
|
|
38
40
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
];
|
|
45
|
-
const credentialType = [
|
|
46
|
-
VerifiableConstants.CREDENTIAL_TYPE.W3C_VERIFIABLE_CREDENTIAL,
|
|
47
|
-
request.type
|
|
48
|
-
];
|
|
49
|
-
const expirationDate = !request.expiration || request.expiration == 0 ? null : request.expiration;
|
|
50
|
-
const credentialSubject = request.credentialSubject;
|
|
51
|
-
credentialSubject['type'] = request.type;
|
|
52
|
-
const cr = new W3CCredential();
|
|
53
|
-
cr.id = `urn:${uuid.v4()}`;
|
|
54
|
-
cr['@context'] = context;
|
|
55
|
-
cr.type = credentialType;
|
|
56
|
-
cr.expirationDate = expirationDate ? new Date(expirationDate * 1000).toISOString() : undefined;
|
|
57
|
-
cr.refreshService = request.refreshService;
|
|
58
|
-
cr.displayMethod = request.displayMethod;
|
|
59
|
-
cr.issuanceDate = new Date().toISOString();
|
|
60
|
-
cr.credentialSubject = credentialSubject;
|
|
61
|
-
cr.issuer = issuer.string();
|
|
62
|
-
cr.credentialSchema = {
|
|
63
|
-
id: request.credentialSchema,
|
|
64
|
-
type: VerifiableConstants.JSON_SCHEMA_VALIDATOR
|
|
65
|
-
};
|
|
66
|
-
cr.credentialStatus = this.buildCredentialStatus(request, issuer);
|
|
67
|
-
return cr;
|
|
41
|
+
r.context.push(schema.$metadata.uris['jsonLdContext']);
|
|
42
|
+
r.expiration = r.expiration ? r.expiration * 1000 : undefined;
|
|
43
|
+
r.id = r.id ? r.id : `urn:${uuid.v4()}`;
|
|
44
|
+
r.issuanceDate = r.issuanceDate ? r.issuanceDate * 1000 : Date.now();
|
|
45
|
+
return W3CCredential.fromCredentialRequest(issuer, r);
|
|
68
46
|
};
|
|
69
47
|
// if no credential status resolvers are provided
|
|
70
48
|
// register default issuer resolver
|
|
@@ -134,51 +112,6 @@ export class CredentialWallet {
|
|
|
134
112
|
}
|
|
135
113
|
return statusResolver.resolve(credStatus, credentialStatusResolveOptions);
|
|
136
114
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Builds credential status
|
|
139
|
-
* @param {CredentialRequest} request
|
|
140
|
-
* @returns `CredentialStatus`
|
|
141
|
-
*/
|
|
142
|
-
buildCredentialStatus(request, issuer) {
|
|
143
|
-
const credentialStatus = {
|
|
144
|
-
id: request.revocationOpts.id,
|
|
145
|
-
type: request.revocationOpts.type,
|
|
146
|
-
revocationNonce: request.revocationOpts.nonce
|
|
147
|
-
};
|
|
148
|
-
switch (request.revocationOpts.type) {
|
|
149
|
-
case CredentialStatusType.SparseMerkleTreeProof:
|
|
150
|
-
return {
|
|
151
|
-
...credentialStatus,
|
|
152
|
-
id: `${credentialStatus.id.replace(/\/$/, '')}/${credentialStatus.revocationNonce}`
|
|
153
|
-
};
|
|
154
|
-
case CredentialStatusType.Iden3ReverseSparseMerkleTreeProof:
|
|
155
|
-
return {
|
|
156
|
-
...credentialStatus,
|
|
157
|
-
id: request.revocationOpts.issuerState
|
|
158
|
-
? `${credentialStatus.id.replace(/\/$/, '')}/node?state=${request.revocationOpts.issuerState}`
|
|
159
|
-
: `${credentialStatus.id.replace(/\/$/, '')}`
|
|
160
|
-
};
|
|
161
|
-
case CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023: {
|
|
162
|
-
const issuerId = DID.idFromDID(issuer);
|
|
163
|
-
const chainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId));
|
|
164
|
-
const searchParams = [
|
|
165
|
-
['revocationNonce', request.revocationOpts.nonce?.toString() || ''],
|
|
166
|
-
['contractAddress', `${chainId}:${request.revocationOpts.id}`],
|
|
167
|
-
['state', request.revocationOpts.issuerState || '']
|
|
168
|
-
]
|
|
169
|
-
.filter(([, value]) => Boolean(value))
|
|
170
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
171
|
-
.join('&');
|
|
172
|
-
return {
|
|
173
|
-
...credentialStatus,
|
|
174
|
-
// `[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)`
|
|
175
|
-
id: `${issuer.string()}/credentialStatus?${searchParams}`
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
default:
|
|
179
|
-
return credentialStatus;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
115
|
/**
|
|
183
116
|
* {@inheritDoc ICredentialWallet.findById}
|
|
184
117
|
*/
|
|
@@ -4,6 +4,7 @@ export * from './status/sparse-merkle-tree';
|
|
|
4
4
|
export * from './status/resolver';
|
|
5
5
|
export * from './status/agent-revocation';
|
|
6
6
|
export * from './status/credential-status-publisher';
|
|
7
|
+
export * from './status/did-resolver-revocation';
|
|
7
8
|
export * from './credential-wallet';
|
|
8
9
|
export * from './rhs';
|
|
9
10
|
export * from './utils';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class DidDocumentCredentialStatusResolver {
|
|
2
|
+
constructor(didResolverUrl) {
|
|
3
|
+
this.didResolverUrl = didResolverUrl;
|
|
4
|
+
}
|
|
5
|
+
async resolve(credentialStatus, opts) {
|
|
6
|
+
if (!opts?.issuerDID) {
|
|
7
|
+
throw new Error('IssuerDID is not set in options');
|
|
8
|
+
}
|
|
9
|
+
const url = `${this.didResolverUrl}/1.0/credential-status/${encodeURIComponent(opts.issuerDID.string())}`;
|
|
10
|
+
const resp = await fetch(url, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
body: JSON.stringify(credentialStatus)
|
|
13
|
+
});
|
|
14
|
+
const data = await resp.json();
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -27,6 +27,7 @@ export class ContractRequestHandler extends AbstractMessageHandler {
|
|
|
27
27
|
this._proofService = _proofService;
|
|
28
28
|
this._zkpVerifier = _zkpVerifier;
|
|
29
29
|
this._supportedCircuits = [
|
|
30
|
+
CircuitId.AuthV2,
|
|
30
31
|
CircuitId.AtomicQueryMTPV2OnChain,
|
|
31
32
|
CircuitId.AtomicQuerySigV2OnChain,
|
|
32
33
|
CircuitId.AtomicQueryV3OnChain
|
|
@@ -57,7 +58,12 @@ export class ContractRequestHandler extends AbstractMessageHandler {
|
|
|
57
58
|
throw new Error(`Invalid chain id ${chain_id}`);
|
|
58
59
|
}
|
|
59
60
|
const verifierDid = message.from ? DID.parse(message.from) : undefined;
|
|
60
|
-
const
|
|
61
|
+
const { scope = [] } = message.body;
|
|
62
|
+
const zkpResponses = await processZeroKnowledgeProofRequests(did, scope, verifierDid, this._proofService, {
|
|
63
|
+
ethSigner,
|
|
64
|
+
challenge,
|
|
65
|
+
supportedCircuits: this._supportedCircuits
|
|
66
|
+
});
|
|
61
67
|
const methodId = message.body.transaction_data.method_id.replace('0x', '');
|
|
62
68
|
switch (methodId) {
|
|
63
69
|
case FunctionSignatures.SubmitZKPResponseV2:
|
|
@@ -47,10 +47,34 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
47
47
|
return this.handleFetchRequest(message);
|
|
48
48
|
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE:
|
|
49
49
|
return this.handleIssuanceResponseMsg(message);
|
|
50
|
+
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE: {
|
|
51
|
+
const result = await this.handleOnchainOfferMessage(message);
|
|
52
|
+
if (Array.isArray(result)) {
|
|
53
|
+
const credWallet = this.opts?.credentialWallet;
|
|
54
|
+
if (!credWallet)
|
|
55
|
+
throw new Error('Credential wallet is not provided');
|
|
56
|
+
await credWallet.saveAll(result);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
50
61
|
default:
|
|
51
62
|
return super.handle(message, ctx);
|
|
52
63
|
}
|
|
53
64
|
}
|
|
65
|
+
async handleOnchainOfferMessage(offerMessage) {
|
|
66
|
+
if (!this.opts?.onchainIssuer) {
|
|
67
|
+
throw new Error('onchain issuer is not provided');
|
|
68
|
+
}
|
|
69
|
+
const credentials = [];
|
|
70
|
+
for (const credentialInfo of offerMessage.body.credentials) {
|
|
71
|
+
const issuerDID = DID.parse(offerMessage.from);
|
|
72
|
+
const userDID = DID.parse(offerMessage.to);
|
|
73
|
+
const credential = await this.opts.onchainIssuer.getCredential(issuerDID, userDID, BigInt(credentialInfo.id));
|
|
74
|
+
credentials.push(credential);
|
|
75
|
+
}
|
|
76
|
+
return credentials;
|
|
77
|
+
}
|
|
54
78
|
async handleOfferMessage(offerMessage, ctx) {
|
|
55
79
|
if (!ctx.mediaType) {
|
|
56
80
|
ctx.mediaType = MediaType.ZKPMessage;
|
|
@@ -135,6 +159,14 @@ export class FetchHandler extends AbstractMessageHandler {
|
|
|
135
159
|
}
|
|
136
160
|
throw new Error('invalid protocol message response');
|
|
137
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Handles only messages with credentials/1.0/onchain-offer type
|
|
164
|
+
* @beta
|
|
165
|
+
*/
|
|
166
|
+
async handleOnchainOffer(offer) {
|
|
167
|
+
const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE);
|
|
168
|
+
return this.handleOnchainOfferMessage(offerMessage);
|
|
169
|
+
}
|
|
138
170
|
async handleFetchRequest(msgRequest) {
|
|
139
171
|
if (!msgRequest.to) {
|
|
140
172
|
throw new Error("failed request. empty 'to' field");
|
|
@@ -40,7 +40,7 @@ export async function verifyEIP712TypedData(data, resolver) {
|
|
|
40
40
|
? {
|
|
41
41
|
recipient: data.recipient,
|
|
42
42
|
amount: data.amount,
|
|
43
|
-
expirationDate: new Date(data.expirationDate)
|
|
43
|
+
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
44
44
|
nonce: data.nonce,
|
|
45
45
|
metadata: '0x'
|
|
46
46
|
}
|
|
@@ -48,7 +48,7 @@ export async function verifyEIP712TypedData(data, resolver) {
|
|
|
48
48
|
tokenAddress: data.tokenAddress,
|
|
49
49
|
recipient: data.recipient,
|
|
50
50
|
amount: data.amount,
|
|
51
|
-
expirationDate: new Date(data.expirationDate)
|
|
51
|
+
expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
|
|
52
52
|
nonce: data.nonce,
|
|
53
53
|
metadata: '0x'
|
|
54
54
|
};
|
|
@@ -257,37 +257,39 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
257
257
|
for (let i = 0; i < payments.length; i++) {
|
|
258
258
|
const { credentials, description } = payments[i];
|
|
259
259
|
const dataArr = [];
|
|
260
|
-
for (let j = 0; j < payments[i].
|
|
261
|
-
const {
|
|
260
|
+
for (let j = 0; j < payments[i].options.length; j++) {
|
|
261
|
+
const { nonce, amount, chainId, optionId, expirationDate } = payments[i].options[j];
|
|
262
262
|
const multiChainConfig = this._params.multiChainPaymentConfig?.find((c) => c.chainId === chainId);
|
|
263
263
|
if (!multiChainConfig) {
|
|
264
264
|
throw new Error(`failed request. no config for chain ${chainId}`);
|
|
265
265
|
}
|
|
266
|
-
const { recipient,
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
269
|
-
throw new Error(`failed request. no
|
|
266
|
+
const { recipient, paymentRails, options } = multiChainConfig;
|
|
267
|
+
const option = options.find((t) => t.id === optionId);
|
|
268
|
+
if (!option) {
|
|
269
|
+
throw new Error(`failed request. no option for id ${optionId}`);
|
|
270
270
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
if (option.type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 &&
|
|
272
|
+
!option.contractAddress) {
|
|
273
|
+
throw new Error(`failed request. no token address for option id ${optionId}`);
|
|
274
|
+
}
|
|
275
|
+
const expirationDateRequired = expirationDate ?? new Date(new Date().setHours(new Date().getHours() + 1));
|
|
276
|
+
const typeUrl = `https://schema.iden3.io/core/json/${option.type}.json`;
|
|
275
277
|
const typesFetchResult = await fetch(typeUrl);
|
|
276
278
|
const types = await typesFetchResult.json();
|
|
277
279
|
delete types.EIP712Domain;
|
|
278
|
-
const paymentData = type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
280
|
+
const paymentData = option.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
279
281
|
? {
|
|
280
282
|
recipient,
|
|
281
|
-
amount,
|
|
282
|
-
expirationDate:
|
|
283
|
+
amount: amount,
|
|
284
|
+
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
283
285
|
nonce,
|
|
284
286
|
metadata: '0x'
|
|
285
287
|
}
|
|
286
288
|
: {
|
|
287
|
-
tokenAddress,
|
|
289
|
+
tokenAddress: option.contractAddress,
|
|
288
290
|
recipient,
|
|
289
|
-
amount,
|
|
290
|
-
expirationDate:
|
|
291
|
+
amount: amount,
|
|
292
|
+
expirationDate: getUnixTimestamp(expirationDateRequired),
|
|
291
293
|
nonce,
|
|
292
294
|
metadata: '0x'
|
|
293
295
|
};
|
|
@@ -295,7 +297,7 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
295
297
|
name: 'MCPayment',
|
|
296
298
|
version: '1.0.0',
|
|
297
299
|
chainId,
|
|
298
|
-
verifyingContract:
|
|
300
|
+
verifyingContract: paymentRails
|
|
299
301
|
};
|
|
300
302
|
const signature = await signer.signTypedData(domain, types, paymentData);
|
|
301
303
|
const proof = [
|
|
@@ -315,20 +317,24 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
315
317
|
const d = {
|
|
316
318
|
type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
|
|
317
319
|
'@context': [
|
|
318
|
-
`https://schema.iden3.io/core/jsonld/payment.jsonld#${type}`,
|
|
320
|
+
`https://schema.iden3.io/core/jsonld/payment.jsonld#${option.type}`,
|
|
319
321
|
'https://w3id.org/security/suites/eip712sig-2021/v1'
|
|
320
322
|
],
|
|
321
323
|
recipient,
|
|
322
324
|
amount: amount.toString(),
|
|
323
|
-
|
|
324
|
-
expirationDate: new Date(expirationTime).toISOString(),
|
|
325
|
+
expirationDate: expirationDateRequired.toISOString(),
|
|
325
326
|
nonce: nonce.toString(),
|
|
326
327
|
metadata: '0x',
|
|
327
328
|
proof
|
|
328
329
|
};
|
|
329
|
-
dataArr.push(type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
330
|
+
dataArr.push(option.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
330
331
|
? d
|
|
331
|
-
: {
|
|
332
|
+
: {
|
|
333
|
+
...d,
|
|
334
|
+
type: option.type,
|
|
335
|
+
tokenAddress: option.contractAddress || '',
|
|
336
|
+
features: option.features || []
|
|
337
|
+
});
|
|
332
338
|
}
|
|
333
339
|
paymentRequestInfo.push({
|
|
334
340
|
data: dataArr,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { keccak256 } from 'ethers';
|
|
2
|
+
import { byteEncoder, hexToBytes, isEthereumIdentity } from '../../utils';
|
|
3
|
+
import { CircuitId } from '../../circuits';
|
|
4
|
+
import { Hex } from '@iden3/js-crypto';
|
|
5
|
+
/**
|
|
6
|
+
* @beta
|
|
7
|
+
* Retrieves the request ID from circuit string.
|
|
8
|
+
* CircuitId.AuthV2 - 940499666
|
|
9
|
+
* @returns The request ID.
|
|
10
|
+
*/
|
|
11
|
+
export function calculateRequestIdForCircuit(circuitId) {
|
|
12
|
+
const circuitHash = keccak256(byteEncoder.encode(circuitId));
|
|
13
|
+
const dataView = new DataView(Hex.decodeString(circuitHash.replace('0x', '')).buffer);
|
|
14
|
+
const id = dataView.getUint32(0);
|
|
15
|
+
return id;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Prepares the zero-knowledge proof response for the AuthV2 circuit.
|
|
19
|
+
* @beta
|
|
20
|
+
* @param address - The address associated with the request.
|
|
21
|
+
* @param senderDid - The sender's decentralized identifier (DID).
|
|
22
|
+
* @param proofService - The proof service used to generate the proof.
|
|
23
|
+
* @returns A promise that resolves to an array of ZeroKnowledgeProofResponse objects.
|
|
24
|
+
*/
|
|
25
|
+
export async function prepareAuthV2ZeroKnowledgeResponse(address, senderDid, proofService) {
|
|
26
|
+
const circuitId = CircuitId.AuthV2;
|
|
27
|
+
// this is now hardcoded calculated value for 'authV2' that can be changed in the future.
|
|
28
|
+
const id = 940499666;
|
|
29
|
+
if (isEthereumIdentity(senderDid)) {
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
circuitId,
|
|
33
|
+
id,
|
|
34
|
+
pub_signals: [],
|
|
35
|
+
proof: {
|
|
36
|
+
pi_a: [],
|
|
37
|
+
pi_b: [],
|
|
38
|
+
pi_c: [],
|
|
39
|
+
protocol: 'groth16'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
const hash = Uint8Array.from([...hexToBytes(address), ...new Uint8Array(12)]).reverse();
|
|
45
|
+
const { proof, pub_signals } = await proofService.generateAuthV2Proof(hash, senderDid);
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
circuitId,
|
|
49
|
+
id,
|
|
50
|
+
pub_signals,
|
|
51
|
+
proof
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
}
|
|
@@ -213,6 +213,12 @@ export class ProofService {
|
|
|
213
213
|
authInputs.gistProof = gistProof;
|
|
214
214
|
return authInputs.inputsMarshal();
|
|
215
215
|
}
|
|
216
|
+
/** {@inheritdoc IProofService.generateAuthV2Proof} */
|
|
217
|
+
async generateAuthV2Proof(challenge, did) {
|
|
218
|
+
const authInputs = await this.generateAuthV2Inputs(challenge, did, CircuitId.AuthV2);
|
|
219
|
+
const zkProof = await this._prover.generate(authInputs, CircuitId.AuthV2);
|
|
220
|
+
return zkProof;
|
|
221
|
+
}
|
|
216
222
|
async verifyState(circuitId, pubSignals, opts = {
|
|
217
223
|
acceptedStateTransitionDelay: PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY
|
|
218
224
|
}) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{ "inputs": [{ "internalType": "uint256", "name": "initialSupply", "type": "uint256" }], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "allowance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" }], "name": "ERC20InsufficientAllowance", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "uint256", "name": "balance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" }], "name": "ERC20InsufficientBalance", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "approver", "type": "address" }], "name": "ERC20InvalidApprover", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }], "name": "ERC20InvalidReceiver", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "sender", "type": "address" }], "name": "ERC20InvalidSender", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }], "name": "ERC20InvalidSpender", "type": "error" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [{ "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "Transfer", "type": "event" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }], "name": "allowance", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "approve", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], "name": "balanceOf", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "transfer", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }], "name": "transferFrom", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" }]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Hash } from '@iden3/js-merkletree';
|
|
2
|
+
import { resolveDidDocument } from '../../utils';
|
|
3
|
+
import { DID, Id } from '@iden3/js-iden3-core';
|
|
4
|
+
import { JsonRpcProvider } from 'ethers';
|
|
5
|
+
export class DidResolverStateReadonlyStorage {
|
|
6
|
+
constructor(resolverUrl) {
|
|
7
|
+
this.resolverUrl = resolverUrl;
|
|
8
|
+
}
|
|
9
|
+
async getLatestStateById(id) {
|
|
10
|
+
return this.getStateInfo(id);
|
|
11
|
+
}
|
|
12
|
+
async getStateInfoByIdAndState(id, state) {
|
|
13
|
+
return this.getStateInfo(id, state);
|
|
14
|
+
}
|
|
15
|
+
async getGISTProof(id) {
|
|
16
|
+
const { didDocument } = await resolveDidDocument(DID.parseFromId(Id.fromBigInt(id)), this.resolverUrl);
|
|
17
|
+
const { global } = this.getIden3StateInfo2023(didDocument);
|
|
18
|
+
if (!global) {
|
|
19
|
+
throw new Error('GIST root not found');
|
|
20
|
+
}
|
|
21
|
+
const { proof } = global;
|
|
22
|
+
if (!proof) {
|
|
23
|
+
throw new Error('GIST proof not found');
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
root: global.root,
|
|
27
|
+
existence: proof.existence,
|
|
28
|
+
siblings: proof.siblings?.map((sibling) => BigInt(sibling)),
|
|
29
|
+
index: BigInt(0),
|
|
30
|
+
value: BigInt(0),
|
|
31
|
+
auxExistence: !!proof.node_aux,
|
|
32
|
+
auxIndex: proof.node_aux ? BigInt(proof.node_aux.key) : BigInt(0),
|
|
33
|
+
auxValue: proof.node_aux ? BigInt(proof.node_aux.value) : BigInt(0)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async getGISTRootInfo(root, userId) {
|
|
37
|
+
const { didDocument } = await resolveDidDocument(DID.parseFromId(Id.fromBigInt(userId)), this.resolverUrl, {
|
|
38
|
+
gist: Hash.fromBigInt(root)
|
|
39
|
+
});
|
|
40
|
+
const { global } = this.getIden3StateInfo2023(didDocument);
|
|
41
|
+
if (!global) {
|
|
42
|
+
throw new Error('GIST root not found');
|
|
43
|
+
}
|
|
44
|
+
return global;
|
|
45
|
+
}
|
|
46
|
+
getRpcProvider() {
|
|
47
|
+
return new JsonRpcProvider();
|
|
48
|
+
}
|
|
49
|
+
publishState() {
|
|
50
|
+
throw new Error('publishState method not implemented.');
|
|
51
|
+
}
|
|
52
|
+
publishStateGeneric() {
|
|
53
|
+
throw new Error('publishStateGeneric method not implemented.');
|
|
54
|
+
}
|
|
55
|
+
async getStateInfo(id, state) {
|
|
56
|
+
const opts = state ? { state: Hash.fromBigInt(state) } : undefined;
|
|
57
|
+
const { didDocument } = await resolveDidDocument(DID.parseFromId(Id.fromBigInt(id)), this.resolverUrl, opts);
|
|
58
|
+
const { info } = this.getIden3StateInfo2023(didDocument);
|
|
59
|
+
return { ...info };
|
|
60
|
+
}
|
|
61
|
+
getIden3StateInfo2023(didDocument) {
|
|
62
|
+
const vm = didDocument.verificationMethod?.find((i) => i.type === 'Iden3StateInfo2023');
|
|
63
|
+
if (!vm) {
|
|
64
|
+
throw new Error('Iden3StateInfo2023 verification method not found');
|
|
65
|
+
}
|
|
66
|
+
return vm;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Contract } from 'ethers';
|
|
2
|
-
import
|
|
2
|
+
import permitAbi from './abi/ERC20Permit.json';
|
|
3
|
+
import erc20Abi from './abi/ERC20.json';
|
|
3
4
|
/**
|
|
4
5
|
* @beta
|
|
5
6
|
* getPermitSignature is a function to create EIP712 Permit signature
|
|
@@ -11,10 +12,11 @@ import abi from './abi/ERC20Permit.json';
|
|
|
11
12
|
* @returns {Promise<PaymentRequestMessage>}
|
|
12
13
|
*/
|
|
13
14
|
export async function getPermitSignature(signer, tokenAddress, spender, value, deadline) {
|
|
14
|
-
const erc20PermitContract = new Contract(tokenAddress,
|
|
15
|
+
const erc20PermitContract = new Contract(tokenAddress, permitAbi, signer);
|
|
15
16
|
const nonce = await erc20PermitContract.nonces(await signer.getAddress());
|
|
16
17
|
const domainData = await erc20PermitContract.eip712Domain();
|
|
17
18
|
const domain = {
|
|
19
|
+
name: domainData[1],
|
|
18
20
|
version: domainData[2],
|
|
19
21
|
chainId: domainData[3],
|
|
20
22
|
verifyingContract: tokenAddress
|
|
@@ -37,3 +39,13 @@ export async function getPermitSignature(signer, tokenAddress, spender, value, d
|
|
|
37
39
|
};
|
|
38
40
|
return signer.signTypedData(domain, types, message);
|
|
39
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* @beta
|
|
44
|
+
* getERC20Decimals is a function to retrieve the number of decimals of an ERC20 token
|
|
45
|
+
* @param {string} tokenAddress - Token address
|
|
46
|
+
* @param {ethers.ContractRunner} runner - Contract runner
|
|
47
|
+
*/
|
|
48
|
+
export async function getERC20Decimals(tokenAddress, runner) {
|
|
49
|
+
const erc20Contract = new Contract(tokenAddress, erc20Abi, runner);
|
|
50
|
+
return erc20Contract.decimals();
|
|
51
|
+
}
|