@0xpolygonid/js-sdk 1.21.3 → 1.23.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/dist/browser/esm/index.js +1358 -270
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +1363 -270
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/iden3comm/constants.js +25 -1
- package/dist/node/cjs/iden3comm/handlers/auth.js +52 -8
- package/dist/node/cjs/iden3comm/handlers/common.js +13 -1
- package/dist/node/cjs/iden3comm/handlers/contract-request.js +5 -1
- package/dist/node/cjs/iden3comm/handlers/credential-proposal.js +14 -3
- package/dist/node/cjs/iden3comm/handlers/fetch.js +12 -2
- package/dist/node/cjs/iden3comm/handlers/message-handler.js +4 -0
- package/dist/node/cjs/iden3comm/handlers/payment.js +240 -28
- package/dist/node/cjs/iden3comm/handlers/revocation-status.js +4 -0
- package/dist/node/cjs/iden3comm/index.js +1 -0
- package/dist/node/cjs/iden3comm/packageManager.js +12 -0
- package/dist/node/cjs/iden3comm/packers/jws.js +21 -0
- package/dist/node/cjs/iden3comm/packers/plain.js +19 -0
- package/dist/node/cjs/iden3comm/packers/zkp.js +25 -0
- package/dist/node/cjs/iden3comm/types/index.js +1 -0
- package/dist/node/cjs/iden3comm/types/protocol/accept-profile.js +2 -0
- package/dist/node/cjs/iden3comm/utils/accept-profile.js +107 -0
- package/dist/node/cjs/iden3comm/utils/index.js +1 -0
- package/dist/node/cjs/storage/blockchain/abi/ERC20Permit.json +1 -0
- package/dist/node/cjs/storage/blockchain/erc20-permit-sig.js +46 -0
- package/dist/node/cjs/storage/blockchain/index.js +1 -0
- package/dist/node/cjs/verifiable/constants.js +28 -11
- package/dist/node/esm/iden3comm/constants.js +24 -0
- package/dist/node/esm/iden3comm/handlers/auth.js +55 -11
- package/dist/node/esm/iden3comm/handlers/common.js +11 -0
- package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -3
- package/dist/node/esm/iden3comm/handlers/credential-proposal.js +15 -4
- package/dist/node/esm/iden3comm/handlers/fetch.js +12 -2
- package/dist/node/esm/iden3comm/handlers/message-handler.js +4 -0
- package/dist/node/esm/iden3comm/handlers/payment.js +240 -29
- package/dist/node/esm/iden3comm/handlers/revocation-status.js +4 -0
- package/dist/node/esm/iden3comm/index.js +1 -0
- package/dist/node/esm/iden3comm/packageManager.js +12 -0
- package/dist/node/esm/iden3comm/packers/jws.js +22 -1
- package/dist/node/esm/iden3comm/packers/plain.js +19 -0
- package/dist/node/esm/iden3comm/packers/zkp.js +26 -1
- package/dist/node/esm/iden3comm/types/index.js +1 -0
- package/dist/node/esm/iden3comm/types/protocol/accept-profile.js +1 -0
- package/dist/node/esm/iden3comm/utils/accept-profile.js +102 -0
- package/dist/node/esm/iden3comm/utils/index.js +1 -0
- package/dist/node/esm/storage/blockchain/abi/ERC20Permit.json +1 -0
- package/dist/node/esm/storage/blockchain/erc20-permit-sig.js +39 -0
- package/dist/node/esm/storage/blockchain/index.js +1 -0
- package/dist/node/esm/verifiable/constants.js +27 -10
- package/dist/types/iden3comm/constants.d.ts +16 -0
- package/dist/types/iden3comm/handlers/auth.d.ts +19 -7
- package/dist/types/iden3comm/handlers/common.d.ts +7 -1
- package/dist/types/iden3comm/handlers/contract-request.d.ts +2 -2
- package/dist/types/iden3comm/handlers/credential-proposal.d.ts +9 -4
- package/dist/types/iden3comm/handlers/fetch.d.ts +22 -6
- package/dist/types/iden3comm/handlers/message-handler.d.ts +6 -0
- package/dist/types/iden3comm/handlers/payment.d.ts +70 -10
- package/dist/types/iden3comm/handlers/revocation-status.d.ts +2 -2
- package/dist/types/iden3comm/index.d.ts +1 -0
- package/dist/types/iden3comm/packageManager.d.ts +4 -0
- package/dist/types/iden3comm/packers/jws.d.ts +5 -0
- package/dist/types/iden3comm/packers/plain.d.ts +4 -0
- package/dist/types/iden3comm/packers/zkp.d.ts +6 -0
- package/dist/types/iden3comm/types/index.d.ts +1 -0
- package/dist/types/iden3comm/types/packageManager.d.ts +14 -0
- package/dist/types/iden3comm/types/packer.d.ts +25 -0
- package/dist/types/iden3comm/types/protocol/accept-profile.d.ts +7 -0
- package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
- package/dist/types/iden3comm/types/protocol/credentials.d.ts +6 -6
- package/dist/types/iden3comm/types/protocol/messages.d.ts +2 -2
- package/dist/types/iden3comm/types/protocol/payment.d.ts +87 -13
- package/dist/types/iden3comm/types/protocol/proof.d.ts +3 -3
- package/dist/types/iden3comm/types/protocol/revocation.d.ts +2 -2
- package/dist/types/iden3comm/utils/accept-profile.d.ts +3 -0
- package/dist/types/iden3comm/utils/index.d.ts +1 -0
- package/dist/types/storage/blockchain/erc20-permit-sig.d.ts +12 -0
- package/dist/types/storage/blockchain/index.d.ts +1 -0
- package/dist/types/verifiable/constants.d.ts +27 -11
- package/package.json +2 -2
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
|
|
2
2
|
import { MediaType } from '../constants';
|
|
3
|
-
import { DID } from '@iden3/js-iden3-core';
|
|
3
|
+
import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
|
|
4
4
|
import * as uuid from 'uuid';
|
|
5
5
|
import { proving } from '@iden3/js-jwz';
|
|
6
6
|
import { byteEncoder } from '../../utils';
|
|
7
7
|
import { AbstractMessageHandler } from './message-handler';
|
|
8
|
-
import {
|
|
8
|
+
import { PaymentFeatures, PaymentRequestDataType, PaymentType, SupportedPaymentProofType } from '../../verifiable';
|
|
9
|
+
import { ethers } from 'ethers';
|
|
10
|
+
import { verifyExpiresTime } from './common';
|
|
9
11
|
/**
|
|
10
12
|
* @beta
|
|
11
13
|
* createPaymentRequest is a function to create protocol payment-request message
|
|
@@ -15,7 +17,7 @@ import { PaymentRequestDataType, PaymentRequestType, PaymentType } from '../../v
|
|
|
15
17
|
* @param {PaymentRequestInfo[]} payments - payments
|
|
16
18
|
* @returns `PaymentRequestMessage`
|
|
17
19
|
*/
|
|
18
|
-
export function createPaymentRequest(sender, receiver, agent, payments) {
|
|
20
|
+
export function createPaymentRequest(sender, receiver, agent, payments, opts) {
|
|
19
21
|
const uuidv4 = uuid.v4();
|
|
20
22
|
const request = {
|
|
21
23
|
id: uuidv4,
|
|
@@ -27,19 +29,57 @@ export function createPaymentRequest(sender, receiver, agent, payments) {
|
|
|
27
29
|
body: {
|
|
28
30
|
agent,
|
|
29
31
|
payments
|
|
30
|
-
}
|
|
32
|
+
},
|
|
33
|
+
created_time: getUnixTimestamp(new Date()),
|
|
34
|
+
expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
|
|
31
35
|
};
|
|
32
36
|
return request;
|
|
33
37
|
}
|
|
38
|
+
export async function verifyEIP712TypedData(data, resolver) {
|
|
39
|
+
const paymentData = data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
40
|
+
? {
|
|
41
|
+
recipient: data.recipient,
|
|
42
|
+
amount: data.amount,
|
|
43
|
+
expirationDate: new Date(data.expirationDate).getTime(),
|
|
44
|
+
nonce: data.nonce,
|
|
45
|
+
metadata: '0x'
|
|
46
|
+
}
|
|
47
|
+
: {
|
|
48
|
+
tokenAddress: data.tokenAddress,
|
|
49
|
+
recipient: data.recipient,
|
|
50
|
+
amount: data.amount,
|
|
51
|
+
expirationDate: new Date(data.expirationDate).getTime(),
|
|
52
|
+
nonce: data.nonce,
|
|
53
|
+
metadata: '0x'
|
|
54
|
+
};
|
|
55
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
56
|
+
const typesFetchResult = await fetch(proof.eip712.types);
|
|
57
|
+
const types = await typesFetchResult.json();
|
|
58
|
+
delete types.EIP712Domain;
|
|
59
|
+
const recovered = ethers.verifyTypedData(proof.eip712.domain, types, paymentData, proof.proofValue);
|
|
60
|
+
const { didDocument } = await resolver.resolve(proof.verificationMethod);
|
|
61
|
+
if (didDocument?.verificationMethod) {
|
|
62
|
+
for (const verificationMethod of didDocument.verificationMethod) {
|
|
63
|
+
if (verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
|
|
64
|
+
recovered.toLowerCase()) {
|
|
65
|
+
return recovered;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`failed request. no matching verificationMethod`);
|
|
73
|
+
}
|
|
34
74
|
/**
|
|
35
75
|
* @beta
|
|
36
76
|
* createPayment is a function to create protocol payment message
|
|
37
77
|
* @param {DID} sender - sender did
|
|
38
78
|
* @param {DID} receiver - receiver did
|
|
39
|
-
* @param {
|
|
79
|
+
* @param {PaymentMessageBody} body - payments
|
|
40
80
|
* @returns `PaymentMessage`
|
|
41
81
|
*/
|
|
42
|
-
export function createPayment(sender, receiver, payments) {
|
|
82
|
+
export function createPayment(sender, receiver, payments, opts) {
|
|
43
83
|
const uuidv4 = uuid.v4();
|
|
44
84
|
const request = {
|
|
45
85
|
id: uuidv4,
|
|
@@ -50,7 +90,9 @@ export function createPayment(sender, receiver, payments) {
|
|
|
50
90
|
type: PROTOCOL_MESSAGE_TYPE.PAYMENT_MESSAGE_TYPE,
|
|
51
91
|
body: {
|
|
52
92
|
payments
|
|
53
|
-
}
|
|
93
|
+
},
|
|
94
|
+
created_time: getUnixTimestamp(new Date()),
|
|
95
|
+
expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
|
|
54
96
|
};
|
|
55
97
|
return request;
|
|
56
98
|
}
|
|
@@ -112,21 +154,28 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
112
154
|
const receiverDID = DID.parse(paymentRequest.from);
|
|
113
155
|
const payments = [];
|
|
114
156
|
for (let i = 0; i < paymentRequest.body.payments.length; i++) {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
157
|
+
const { data } = paymentRequest.body.payments[i];
|
|
158
|
+
const selectedPayment = Array.isArray(data)
|
|
159
|
+
? data.find((p) => {
|
|
160
|
+
return p.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
|
|
161
|
+
? p.id === ctx.nonce
|
|
162
|
+
: p.nonce === ctx.nonce;
|
|
163
|
+
})
|
|
164
|
+
: data;
|
|
165
|
+
if (!selectedPayment) {
|
|
166
|
+
throw new Error(`failed request. no payment in request for nonce ${ctx.nonce}`);
|
|
118
167
|
}
|
|
119
|
-
|
|
120
|
-
|
|
168
|
+
switch (selectedPayment.type) {
|
|
169
|
+
case PaymentRequestDataType.Iden3PaymentRequestCryptoV1:
|
|
170
|
+
payments.push(await this.handleIden3PaymentRequestCryptoV1(selectedPayment, ctx.paymentHandler));
|
|
171
|
+
break;
|
|
172
|
+
case PaymentRequestDataType.Iden3PaymentRailsRequestV1:
|
|
173
|
+
payments.push(await this.handleIden3PaymentRailsRequestV1(selectedPayment, ctx.paymentHandler));
|
|
174
|
+
break;
|
|
175
|
+
case PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1:
|
|
176
|
+
payments.push(await this.handleIden3PaymentRailsERC20RequestV1(selectedPayment, ctx.paymentHandler, ctx.erc20TokenApproveHandler));
|
|
177
|
+
break;
|
|
121
178
|
}
|
|
122
|
-
const txId = await ctx.paymentHandler(paymentReq.data);
|
|
123
|
-
payments.push({
|
|
124
|
-
id: paymentReq.data.id,
|
|
125
|
-
type: PaymentType.Iden3PaymentCryptoV1,
|
|
126
|
-
paymentData: {
|
|
127
|
-
txId
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
179
|
}
|
|
131
180
|
const paymentMessage = createPayment(senderDID, receiverDID, payments);
|
|
132
181
|
const response = await this.packMessage(paymentMessage, senderDID);
|
|
@@ -159,6 +208,9 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
159
208
|
if (!paymentRequest.to) {
|
|
160
209
|
throw new Error(`failed request. empty 'to' field`);
|
|
161
210
|
}
|
|
211
|
+
if (!opts?.allowExpiredMessages) {
|
|
212
|
+
verifyExpiresTime(paymentRequest);
|
|
213
|
+
}
|
|
162
214
|
const agentMessage = await this.handlePaymentRequestMessage(paymentRequest, opts);
|
|
163
215
|
if (!agentMessage) {
|
|
164
216
|
return null;
|
|
@@ -169,24 +221,122 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
169
221
|
/**
|
|
170
222
|
* @inheritdoc IPaymentHandler#handlePayment
|
|
171
223
|
*/
|
|
172
|
-
async handlePayment(payment,
|
|
173
|
-
if (
|
|
174
|
-
|
|
224
|
+
async handlePayment(payment, params) {
|
|
225
|
+
if (!params?.allowExpiredMessages) {
|
|
226
|
+
verifyExpiresTime(payment);
|
|
227
|
+
}
|
|
228
|
+
if (params.paymentRequest.from !== payment.to) {
|
|
229
|
+
throw new Error(`sender of the request is not a target of response - expected ${params.paymentRequest.from}, given ${payment.to}`);
|
|
175
230
|
}
|
|
176
231
|
if (!payment.body.payments.length) {
|
|
177
232
|
throw new Error(`failed request. empty 'payments' field in body`);
|
|
178
233
|
}
|
|
234
|
+
if (!params.paymentValidationHandler) {
|
|
235
|
+
throw new Error(`please provide payment validation handler in options`);
|
|
236
|
+
}
|
|
179
237
|
for (let i = 0; i < payment.body.payments.length; i++) {
|
|
180
238
|
const p = payment.body.payments[i];
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
239
|
+
const nonce = p.type === PaymentType.Iden3PaymentCryptoV1 ? p.id : p.nonce;
|
|
240
|
+
const requestDataArr = params.paymentRequest.body.payments
|
|
241
|
+
.map((r) => (Array.isArray(r.data) ? r.data : [r.data]))
|
|
242
|
+
.flat();
|
|
243
|
+
const requestData = requestDataArr.find((r) => r.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
|
|
244
|
+
? r.id === nonce
|
|
245
|
+
: r.nonce === nonce);
|
|
246
|
+
if (!requestData) {
|
|
247
|
+
throw new Error(`can't find payment request for payment ${p.type === PaymentType.Iden3PaymentCryptoV1 ? 'id' : 'nonce'} ${nonce}`);
|
|
184
248
|
}
|
|
185
|
-
|
|
186
|
-
|
|
249
|
+
await params.paymentValidationHandler(p.paymentData.txId, requestData);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* @inheritdoc IPaymentHandler#createPaymentRailsV1
|
|
254
|
+
*/
|
|
255
|
+
async createPaymentRailsV1(sender, receiver, agent, signer, payments) {
|
|
256
|
+
const paymentRequestInfo = [];
|
|
257
|
+
for (let i = 0; i < payments.length; i++) {
|
|
258
|
+
const { credentials, description } = payments[i];
|
|
259
|
+
const dataArr = [];
|
|
260
|
+
for (let j = 0; j < payments[i].chains.length; j++) {
|
|
261
|
+
const { features, nonce, amount, currency, chainId, expirationDate, type } = payments[i].chains[j];
|
|
262
|
+
const multiChainConfig = this._params.multiChainPaymentConfig?.find((c) => c.chainId === chainId);
|
|
263
|
+
if (!multiChainConfig) {
|
|
264
|
+
throw new Error(`failed request. no config for chain ${chainId}`);
|
|
265
|
+
}
|
|
266
|
+
const { recipient, paymentContract, erc20TokenAddressArr } = multiChainConfig;
|
|
267
|
+
const tokenAddress = erc20TokenAddressArr.find((t) => t.symbol === currency)?.address;
|
|
268
|
+
if (type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 && !tokenAddress) {
|
|
269
|
+
throw new Error(`failed request. no token address for currency ${currency}`);
|
|
270
|
+
}
|
|
271
|
+
const expirationTime = expirationDate
|
|
272
|
+
? new Date(expirationDate).getTime()
|
|
273
|
+
: new Date(new Date().setHours(new Date().getHours() + 1)).getTime();
|
|
274
|
+
const typeUrl = `https://schema.iden3.io/core/json/${type}.json`;
|
|
275
|
+
const typesFetchResult = await fetch(typeUrl);
|
|
276
|
+
const types = await typesFetchResult.json();
|
|
277
|
+
delete types.EIP712Domain;
|
|
278
|
+
const paymentData = type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
279
|
+
? {
|
|
280
|
+
recipient,
|
|
281
|
+
amount,
|
|
282
|
+
expirationDate: expirationTime,
|
|
283
|
+
nonce,
|
|
284
|
+
metadata: '0x'
|
|
285
|
+
}
|
|
286
|
+
: {
|
|
287
|
+
tokenAddress,
|
|
288
|
+
recipient,
|
|
289
|
+
amount,
|
|
290
|
+
expirationDate: expirationTime,
|
|
291
|
+
nonce,
|
|
292
|
+
metadata: '0x'
|
|
293
|
+
};
|
|
294
|
+
const domain = {
|
|
295
|
+
name: 'MCPayment',
|
|
296
|
+
version: '1.0.0',
|
|
297
|
+
chainId,
|
|
298
|
+
verifyingContract: paymentContract
|
|
299
|
+
};
|
|
300
|
+
const signature = await signer.signTypedData(domain, types, paymentData);
|
|
301
|
+
const proof = [
|
|
302
|
+
{
|
|
303
|
+
type: SupportedPaymentProofType.EthereumEip712Signature2021,
|
|
304
|
+
proofPurpose: 'assertionMethod',
|
|
305
|
+
proofValue: signature,
|
|
306
|
+
verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
|
|
307
|
+
created: new Date().toISOString(),
|
|
308
|
+
eip712: {
|
|
309
|
+
types: typeUrl,
|
|
310
|
+
primaryType: 'Iden3PaymentRailsRequestV1',
|
|
311
|
+
domain
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
];
|
|
315
|
+
const d = {
|
|
316
|
+
type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
|
|
317
|
+
'@context': [
|
|
318
|
+
`https://schema.iden3.io/core/jsonld/payment.jsonld#${type}`,
|
|
319
|
+
'https://w3id.org/security/suites/eip712sig-2021/v1'
|
|
320
|
+
],
|
|
321
|
+
recipient,
|
|
322
|
+
amount: amount.toString(),
|
|
323
|
+
currency,
|
|
324
|
+
expirationDate: new Date(expirationTime).toISOString(),
|
|
325
|
+
nonce: nonce.toString(),
|
|
326
|
+
metadata: '0x',
|
|
327
|
+
proof
|
|
328
|
+
};
|
|
329
|
+
dataArr.push(type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
|
|
330
|
+
? d
|
|
331
|
+
: { ...d, type, tokenAddress: tokenAddress || '', features: features || [] });
|
|
187
332
|
}
|
|
188
|
-
|
|
333
|
+
paymentRequestInfo.push({
|
|
334
|
+
data: dataArr,
|
|
335
|
+
credentials,
|
|
336
|
+
description
|
|
337
|
+
});
|
|
189
338
|
}
|
|
339
|
+
return createPaymentRequest(sender, receiver, agent, paymentRequestInfo);
|
|
190
340
|
}
|
|
191
341
|
async packMessage(message, senderDID) {
|
|
192
342
|
const responseEncoded = byteEncoder.encode(JSON.stringify(message));
|
|
@@ -200,4 +350,65 @@ export class PaymentHandler extends AbstractMessageHandler {
|
|
|
200
350
|
...packerOpts
|
|
201
351
|
});
|
|
202
352
|
}
|
|
353
|
+
async handleIden3PaymentRequestCryptoV1(data, paymentHandler) {
|
|
354
|
+
if (data.expiration && new Date(data.expiration) < new Date()) {
|
|
355
|
+
throw new Error(`failed request. expired request`);
|
|
356
|
+
}
|
|
357
|
+
const txId = await paymentHandler(data);
|
|
358
|
+
return {
|
|
359
|
+
id: data.id,
|
|
360
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentCryptoV1',
|
|
361
|
+
type: PaymentType.Iden3PaymentCryptoV1,
|
|
362
|
+
paymentData: {
|
|
363
|
+
txId
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
async handleIden3PaymentRailsRequestV1(data, paymentHandler) {
|
|
368
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
369
|
+
throw new Error(`failed request. expired request`);
|
|
370
|
+
}
|
|
371
|
+
const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
|
|
372
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
373
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
374
|
+
}
|
|
375
|
+
const txId = await paymentHandler(data);
|
|
376
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
377
|
+
return {
|
|
378
|
+
nonce: data.nonce,
|
|
379
|
+
type: PaymentType.Iden3PaymentRailsV1,
|
|
380
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsV1',
|
|
381
|
+
paymentData: {
|
|
382
|
+
txId,
|
|
383
|
+
chainId: proof.eip712.domain.chainId
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
async handleIden3PaymentRailsERC20RequestV1(data, paymentHandler, approveHandler) {
|
|
388
|
+
if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
|
|
389
|
+
throw new Error(`failed request. expired request`);
|
|
390
|
+
}
|
|
391
|
+
const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
|
|
392
|
+
if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
|
|
393
|
+
throw new Error(`failed request. signer is not in the allowed signers list`);
|
|
394
|
+
}
|
|
395
|
+
if (!data.features?.includes(PaymentFeatures.EIP_2612) && !approveHandler) {
|
|
396
|
+
throw new Error(`please provide erc20TokenApproveHandler in context for ERC-20 payment type`);
|
|
397
|
+
}
|
|
398
|
+
if (approveHandler) {
|
|
399
|
+
await approveHandler(data);
|
|
400
|
+
}
|
|
401
|
+
const txId = await paymentHandler(data);
|
|
402
|
+
const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
|
|
403
|
+
return {
|
|
404
|
+
nonce: data.nonce,
|
|
405
|
+
type: PaymentType.Iden3PaymentRailsERC20V1,
|
|
406
|
+
'@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsERC20V1',
|
|
407
|
+
paymentData: {
|
|
408
|
+
txId,
|
|
409
|
+
chainId: proof.eip712.domain.chainId,
|
|
410
|
+
tokenAddress: data.tokenAddress
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
203
414
|
}
|
|
@@ -5,6 +5,7 @@ import * as uuid from 'uuid';
|
|
|
5
5
|
import { byteEncoder } from '../../utils';
|
|
6
6
|
import { proving } from '@iden3/js-jwz';
|
|
7
7
|
import { AbstractMessageHandler } from './message-handler';
|
|
8
|
+
import { verifyExpiresTime } from './common';
|
|
8
9
|
/**
|
|
9
10
|
*
|
|
10
11
|
* Allows to process RevocationStatusRequest protocol message
|
|
@@ -97,6 +98,9 @@ export class RevocationStatusHandler extends AbstractMessageHandler {
|
|
|
97
98
|
throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
|
|
98
99
|
}
|
|
99
100
|
const rsRequest = await this.parseRevocationStatusRequest(request);
|
|
101
|
+
if (!opts.allowExpiredMessages) {
|
|
102
|
+
verifyExpiresTime(rsRequest);
|
|
103
|
+
}
|
|
100
104
|
const response = await this.handleRevocationStatusRequestMessage(rsRequest, {
|
|
101
105
|
senderDid: did,
|
|
102
106
|
mediaType: opts.mediaType,
|
|
@@ -15,6 +15,18 @@ export class PackageManager {
|
|
|
15
15
|
constructor() {
|
|
16
16
|
this.packers = new Map();
|
|
17
17
|
}
|
|
18
|
+
/** {@inheritDoc IPackageManager.isProfileSupported} */
|
|
19
|
+
isProfileSupported(mediaType, profile) {
|
|
20
|
+
const p = this.packers.get(mediaType);
|
|
21
|
+
if (!p) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return p.isProfileSupported(profile);
|
|
25
|
+
}
|
|
26
|
+
/** {@inheritDoc IPackageManager.getSupportedMediaTypes} */
|
|
27
|
+
getSupportedMediaTypes() {
|
|
28
|
+
return [...this.packers.keys()];
|
|
29
|
+
}
|
|
18
30
|
/** {@inheritDoc IPackageManager.registerPackers} */
|
|
19
31
|
registerPackers(packers) {
|
|
20
32
|
packers.forEach((p) => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
|
|
1
|
+
import { AcceptJwsAlgorithms, MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
|
|
2
2
|
import { extractPublicKeyBytes, resolveVerificationMethods } from '../utils/did';
|
|
3
3
|
import { keyPath } from '../../kms/';
|
|
4
4
|
import { verifyJWS } from 'did-jwt';
|
|
5
5
|
import { parse } from 'did-resolver';
|
|
6
6
|
import { bytesToBase64url } from '../../utils/encoding';
|
|
7
7
|
import { byteDecoder, byteEncoder, bytesToHex, decodeBase64url, encodeBase64url } from '../../utils';
|
|
8
|
+
import { parseAcceptProfile } from '../utils';
|
|
8
9
|
/**
|
|
9
10
|
* Packer that can pack message to JWZ token,
|
|
10
11
|
* and unpack and validate JWZ envelope
|
|
@@ -83,6 +84,26 @@ export class JWSPacker {
|
|
|
83
84
|
mediaType() {
|
|
84
85
|
return MediaType.SignedMessage;
|
|
85
86
|
}
|
|
87
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
88
|
+
getSupportedProfiles() {
|
|
89
|
+
return [`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}`];
|
|
90
|
+
}
|
|
91
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
92
|
+
isProfileSupported(profile) {
|
|
93
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
94
|
+
if (env !== this.mediaType()) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (circuits) {
|
|
98
|
+
throw new Error(`Circuits are not supported for ${env} media type`);
|
|
99
|
+
}
|
|
100
|
+
const supportedAlgArr = this.getSupportedAlgorithms();
|
|
101
|
+
const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
|
|
102
|
+
return algSupported;
|
|
103
|
+
}
|
|
104
|
+
getSupportedAlgorithms() {
|
|
105
|
+
return [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR];
|
|
106
|
+
}
|
|
86
107
|
async resolveDidDoc(from) {
|
|
87
108
|
let didDocument;
|
|
88
109
|
try {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MediaType } from '../constants';
|
|
2
2
|
import { byteDecoder, byteEncoder } from '../../utils';
|
|
3
|
+
import { parseAcceptProfile } from '../utils';
|
|
3
4
|
/**
|
|
4
5
|
* Plain packer just serializes bytes to JSON and adds media type
|
|
5
6
|
*
|
|
@@ -49,4 +50,22 @@ export class PlainPacker {
|
|
|
49
50
|
mediaType() {
|
|
50
51
|
return MediaType.PlainMessage;
|
|
51
52
|
}
|
|
53
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
54
|
+
getSupportedProfiles() {
|
|
55
|
+
return [`env=${this.mediaType()}`];
|
|
56
|
+
}
|
|
57
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
58
|
+
isProfileSupported(profile) {
|
|
59
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
60
|
+
if (env !== this.mediaType()) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (circuits) {
|
|
64
|
+
throw new Error(`Circuits are not supported for ${env} media type`);
|
|
65
|
+
}
|
|
66
|
+
if (alg) {
|
|
67
|
+
throw new Error(`Algorithms are not supported for ${env} media type`);
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
52
71
|
}
|
|
@@ -3,9 +3,10 @@ import { AuthV2PubSignals, CircuitId } from '../../circuits/index';
|
|
|
3
3
|
import { BytesHelper, DID } from '@iden3/js-iden3-core';
|
|
4
4
|
import { bytesToProtocolMessage } from '../utils/envelope';
|
|
5
5
|
import { ErrNoProvingMethodAlg, ErrPackedWithUnsupportedCircuit, ErrProofIsInvalid, ErrSenderNotUsedTokenCreation, ErrStateVerificationFailed, ErrUnknownCircuitID } from '../errors';
|
|
6
|
-
import { MediaType } from '../constants';
|
|
6
|
+
import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType } from '../constants';
|
|
7
7
|
import { byteDecoder, byteEncoder } from '../../utils';
|
|
8
8
|
import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants';
|
|
9
|
+
import { parseAcceptProfile } from '../utils';
|
|
9
10
|
const { getProvingMethod } = proving;
|
|
10
11
|
/**
|
|
11
12
|
* Handler to
|
|
@@ -136,6 +137,30 @@ export class ZKPPacker {
|
|
|
136
137
|
mediaType() {
|
|
137
138
|
return MediaType.ZKPMessage;
|
|
138
139
|
}
|
|
140
|
+
/** {@inheritDoc IPacker.getSupportedProfiles} */
|
|
141
|
+
getSupportedProfiles() {
|
|
142
|
+
return [
|
|
143
|
+
`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}&circuitIds=${this.getSupportedCircuitIds().join(',')}`
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
/** {@inheritDoc IPacker.isProfileSupported} */
|
|
147
|
+
isProfileSupported(profile) {
|
|
148
|
+
const { env, circuits, alg } = parseAcceptProfile(profile);
|
|
149
|
+
if (env !== this.mediaType()) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
const supportedCircuitIds = this.getSupportedCircuitIds();
|
|
153
|
+
const circuitIdSupported = !circuits?.length || circuits.some((c) => supportedCircuitIds.includes(c));
|
|
154
|
+
const supportedAlgArr = this.getSupportedAlgorithms();
|
|
155
|
+
const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a));
|
|
156
|
+
return algSupported && circuitIdSupported;
|
|
157
|
+
}
|
|
158
|
+
getSupportedAlgorithms() {
|
|
159
|
+
return [AcceptJwzAlgorithms.Groth16];
|
|
160
|
+
}
|
|
161
|
+
getSupportedCircuitIds() {
|
|
162
|
+
return [AcceptAuthCircuits.AuthV2];
|
|
163
|
+
}
|
|
139
164
|
}
|
|
140
165
|
const verifySender = async (token, msg) => {
|
|
141
166
|
switch (token.circuitId) {
|
|
@@ -6,6 +6,7 @@ export * from './protocol/revocation';
|
|
|
6
6
|
export * from './protocol/contract-request';
|
|
7
7
|
export * from './protocol/proposal-request';
|
|
8
8
|
export * from './protocol/payment';
|
|
9
|
+
export * from './protocol/accept-profile';
|
|
9
10
|
export * from './packer';
|
|
10
11
|
export * from './models';
|
|
11
12
|
export * from './packageManager';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { MediaType, ProtocolVersion, AcceptAuthCircuits, AcceptJwzAlgorithms, AcceptJwsAlgorithms } from '../constants';
|
|
2
|
+
function isProtocolVersion(value) {
|
|
3
|
+
return Object.values(ProtocolVersion).includes(value);
|
|
4
|
+
}
|
|
5
|
+
function isMediaType(value) {
|
|
6
|
+
return Object.values(MediaType).includes(value);
|
|
7
|
+
}
|
|
8
|
+
function isAcceptAuthCircuits(value) {
|
|
9
|
+
return Object.values(AcceptAuthCircuits).includes(value);
|
|
10
|
+
}
|
|
11
|
+
function isAcceptJwsAlgorithms(value) {
|
|
12
|
+
return Object.values(AcceptJwsAlgorithms).includes(value);
|
|
13
|
+
}
|
|
14
|
+
function isAcceptJwzAlgorithms(value) {
|
|
15
|
+
return Object.values(AcceptJwzAlgorithms).includes(value);
|
|
16
|
+
}
|
|
17
|
+
export const buildAccept = (profiles) => {
|
|
18
|
+
const result = [];
|
|
19
|
+
for (const profile of profiles) {
|
|
20
|
+
let accept = `${profile.protocolVersion};env=${profile.env}`;
|
|
21
|
+
if (profile.circuits?.length) {
|
|
22
|
+
accept += `;circuitId=${profile.circuits.join(',')}`;
|
|
23
|
+
}
|
|
24
|
+
if (profile.alg?.length) {
|
|
25
|
+
accept += `;alg=${profile.alg.join(',')}`;
|
|
26
|
+
}
|
|
27
|
+
result.push(accept);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
export const parseAcceptProfile = (profile) => {
|
|
32
|
+
const params = profile.split(';');
|
|
33
|
+
if (params.length < 2) {
|
|
34
|
+
throw new Error('Invalid accept profile');
|
|
35
|
+
}
|
|
36
|
+
const protocolVersion = params[0].trim();
|
|
37
|
+
if (!isProtocolVersion(protocolVersion)) {
|
|
38
|
+
throw new Error(`Protocol version '${protocolVersion}' not supported`);
|
|
39
|
+
}
|
|
40
|
+
const envParam = params[1].split('=');
|
|
41
|
+
if (envParam.length !== 2) {
|
|
42
|
+
throw new Error(`Invalid accept profile 'env' parameter`);
|
|
43
|
+
}
|
|
44
|
+
const env = params[1].split('=')[1].trim();
|
|
45
|
+
if (!isMediaType(env)) {
|
|
46
|
+
throw new Error(`Envelop '${env}' not supported`);
|
|
47
|
+
}
|
|
48
|
+
const circuitsIndex = params.findIndex((i) => i.includes('circuitId='));
|
|
49
|
+
if (env !== MediaType.ZKPMessage && circuitsIndex > 0) {
|
|
50
|
+
throw new Error(`Circuits not supported for env '${env}'`);
|
|
51
|
+
}
|
|
52
|
+
let circuits = undefined;
|
|
53
|
+
if (circuitsIndex > 0) {
|
|
54
|
+
circuits = params[circuitsIndex]
|
|
55
|
+
.split('=')[1]
|
|
56
|
+
.split(',')
|
|
57
|
+
.map((i) => i.trim())
|
|
58
|
+
.map((i) => {
|
|
59
|
+
if (!isAcceptAuthCircuits(i)) {
|
|
60
|
+
throw new Error(`Circuit '${i}' not supported`);
|
|
61
|
+
}
|
|
62
|
+
return i;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const algIndex = params.findIndex((i) => i.includes('alg='));
|
|
66
|
+
let alg = undefined;
|
|
67
|
+
if (algIndex > 0) {
|
|
68
|
+
if (env === MediaType.ZKPMessage) {
|
|
69
|
+
alg = params[algIndex]
|
|
70
|
+
.split('=')[1]
|
|
71
|
+
.split(',')
|
|
72
|
+
.map((i) => {
|
|
73
|
+
i = i.trim();
|
|
74
|
+
if (!isAcceptJwzAlgorithms(i)) {
|
|
75
|
+
throw new Error(`Algorithm '${i}' not supported for '${env}'`);
|
|
76
|
+
}
|
|
77
|
+
return i;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else if (env === MediaType.SignedMessage) {
|
|
81
|
+
alg = params[algIndex]
|
|
82
|
+
.split('=')[1]
|
|
83
|
+
.split(',')
|
|
84
|
+
.map((i) => {
|
|
85
|
+
i = i.trim();
|
|
86
|
+
if (!isAcceptJwsAlgorithms(i)) {
|
|
87
|
+
throw new Error(`Algorithm '${i}' not supported for '${env}'`);
|
|
88
|
+
}
|
|
89
|
+
return i;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw new Error(`Algorithm not supported for '${env}'`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
protocolVersion,
|
|
98
|
+
env,
|
|
99
|
+
circuits,
|
|
100
|
+
alg
|
|
101
|
+
};
|
|
102
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{ "inputs": [], "name": "ECDSAInvalidSignature", "type": "error" }, { "inputs": [{ "internalType": "uint256", "name": "length", "type": "uint256" }], "name": "ECDSAInvalidSignatureLength", "type": "error" }, { "inputs": [{ "internalType": "bytes32", "name": "s", "type": "bytes32" }], "name": "ECDSAInvalidSignatureS", "type": "error" }, { "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" }, { "inputs": [{ "internalType": "uint256", "name": "deadline", "type": "uint256" }], "name": "ERC2612ExpiredSignature", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "signer", "type": "address" }, { "internalType": "address", "name": "owner", "type": "address" }], "name": "ERC2612InvalidSigner", "type": "error" }, { "inputs": [{ "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "currentNonce", "type": "uint256" }], "name": "InvalidAccountNonce", "type": "error" }, { "inputs": [], "name": "InvalidShortString", "type": "error" }, { "inputs": [{ "internalType": "string", "name": "str", "type": "string" }], "name": "StringTooLong", "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": [], "name": "EIP712DomainChanged", "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": [], "name": "DOMAIN_SEPARATOR", "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], "stateMutability": "view", "type": "function" }, { "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": "eip712Domain", "outputs": [{ "internalType": "bytes1", "name": "fields", "type": "bytes1" }, { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "string", "name": "version", "type": "string" }, { "internalType": "uint256", "name": "chainId", "type": "uint256" }, { "internalType": "address", "name": "verifyingContract", "type": "address" }, { "internalType": "bytes32", "name": "salt", "type": "bytes32" }, { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], "name": "nonces", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "uint256", "name": "deadline", "type": "uint256" }, { "internalType": "uint8", "name": "v", "type": "uint8" }, { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" }], "name": "permit", "outputs": [], "stateMutability": "nonpayable", "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" }]
|