@0xpolygonid/js-sdk 1.21.3 → 1.24.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.
Files changed (114) hide show
  1. package/dist/browser/esm/index.js +4378 -545
  2. package/dist/browser/esm/index.js.map +1 -1
  3. package/dist/browser/umd/index.js +4388 -545
  4. package/dist/browser/umd/index.js.map +1 -1
  5. package/dist/node/cjs/credentials/credential-wallet.js +11 -78
  6. package/dist/node/cjs/credentials/index.js +1 -0
  7. package/dist/node/cjs/credentials/status/did-resolver-revocation.js +21 -0
  8. package/dist/node/cjs/iden3comm/constants.js +25 -1
  9. package/dist/node/cjs/iden3comm/handlers/auth.js +52 -8
  10. package/dist/node/cjs/iden3comm/handlers/common.js +13 -1
  11. package/dist/node/cjs/iden3comm/handlers/contract-request.js +5 -1
  12. package/dist/node/cjs/iden3comm/handlers/credential-proposal.js +14 -3
  13. package/dist/node/cjs/iden3comm/handlers/fetch.js +44 -2
  14. package/dist/node/cjs/iden3comm/handlers/message-handler.js +4 -0
  15. package/dist/node/cjs/iden3comm/handlers/payment.js +265 -28
  16. package/dist/node/cjs/iden3comm/handlers/revocation-status.js +4 -0
  17. package/dist/node/cjs/iden3comm/index.js +1 -0
  18. package/dist/node/cjs/iden3comm/packageManager.js +12 -0
  19. package/dist/node/cjs/iden3comm/packers/jws.js +21 -0
  20. package/dist/node/cjs/iden3comm/packers/plain.js +19 -0
  21. package/dist/node/cjs/iden3comm/packers/zkp.js +25 -0
  22. package/dist/node/cjs/iden3comm/types/index.js +1 -0
  23. package/dist/node/cjs/iden3comm/types/protocol/accept-profile.js +2 -0
  24. package/dist/node/cjs/iden3comm/utils/accept-profile.js +107 -0
  25. package/dist/node/cjs/iden3comm/utils/index.js +1 -0
  26. package/dist/node/cjs/storage/blockchain/abi/ERC20.json +1 -0
  27. package/dist/node/cjs/storage/blockchain/abi/ERC20Permit.json +1 -0
  28. package/dist/node/cjs/storage/blockchain/did-resolver-readonly-storage.js +72 -0
  29. package/dist/node/cjs/storage/blockchain/erc20-helper.js +59 -0
  30. package/dist/node/cjs/storage/blockchain/index.js +3 -0
  31. package/dist/node/cjs/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +245 -0
  32. package/dist/node/cjs/storage/blockchain/onchain-issuer.js +82 -0
  33. package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +38 -34
  34. package/dist/node/cjs/storage/interfaces/index.js +1 -0
  35. package/dist/node/cjs/storage/interfaces/onchain-issuer.js +2 -0
  36. package/dist/node/cjs/utils/did-helper.js +3 -3
  37. package/dist/node/cjs/verifiable/constants.js +29 -11
  38. package/dist/node/cjs/verifiable/credential.js +86 -0
  39. package/dist/node/esm/credentials/credential-wallet.js +12 -79
  40. package/dist/node/esm/credentials/index.js +1 -0
  41. package/dist/node/esm/credentials/status/did-resolver-revocation.js +17 -0
  42. package/dist/node/esm/iden3comm/constants.js +24 -0
  43. package/dist/node/esm/iden3comm/handlers/auth.js +55 -11
  44. package/dist/node/esm/iden3comm/handlers/common.js +11 -0
  45. package/dist/node/esm/iden3comm/handlers/contract-request.js +7 -3
  46. package/dist/node/esm/iden3comm/handlers/credential-proposal.js +15 -4
  47. package/dist/node/esm/iden3comm/handlers/fetch.js +44 -2
  48. package/dist/node/esm/iden3comm/handlers/message-handler.js +4 -0
  49. package/dist/node/esm/iden3comm/handlers/payment.js +264 -29
  50. package/dist/node/esm/iden3comm/handlers/revocation-status.js +4 -0
  51. package/dist/node/esm/iden3comm/index.js +1 -0
  52. package/dist/node/esm/iden3comm/packageManager.js +12 -0
  53. package/dist/node/esm/iden3comm/packers/jws.js +22 -1
  54. package/dist/node/esm/iden3comm/packers/plain.js +19 -0
  55. package/dist/node/esm/iden3comm/packers/zkp.js +26 -1
  56. package/dist/node/esm/iden3comm/types/index.js +1 -0
  57. package/dist/node/esm/iden3comm/types/protocol/accept-profile.js +1 -0
  58. package/dist/node/esm/iden3comm/utils/accept-profile.js +102 -0
  59. package/dist/node/esm/iden3comm/utils/index.js +1 -0
  60. package/dist/node/esm/storage/blockchain/abi/ERC20.json +1 -0
  61. package/dist/node/esm/storage/blockchain/abi/ERC20Permit.json +1 -0
  62. package/dist/node/esm/storage/blockchain/did-resolver-readonly-storage.js +68 -0
  63. package/dist/node/esm/storage/blockchain/erc20-helper.js +51 -0
  64. package/dist/node/esm/storage/blockchain/index.js +3 -0
  65. package/dist/node/esm/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.js +241 -0
  66. package/dist/node/esm/storage/blockchain/onchain-issuer.js +78 -0
  67. package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +38 -34
  68. package/dist/node/esm/storage/interfaces/index.js +1 -0
  69. package/dist/node/esm/storage/interfaces/onchain-issuer.js +1 -0
  70. package/dist/node/esm/utils/did-helper.js +3 -3
  71. package/dist/node/esm/verifiable/constants.js +28 -10
  72. package/dist/node/esm/verifiable/credential.js +88 -2
  73. package/dist/types/credentials/credential-wallet.d.ts +0 -6
  74. package/dist/types/credentials/index.d.ts +1 -0
  75. package/dist/types/credentials/models.d.ts +8 -0
  76. package/dist/types/credentials/status/did-resolver-revocation.d.ts +7 -0
  77. package/dist/types/iden3comm/constants.d.ts +16 -0
  78. package/dist/types/iden3comm/handlers/auth.d.ts +19 -7
  79. package/dist/types/iden3comm/handlers/common.d.ts +7 -1
  80. package/dist/types/iden3comm/handlers/contract-request.d.ts +2 -2
  81. package/dist/types/iden3comm/handlers/credential-proposal.d.ts +9 -4
  82. package/dist/types/iden3comm/handlers/fetch.d.ts +30 -6
  83. package/dist/types/iden3comm/handlers/message-handler.d.ts +6 -0
  84. package/dist/types/iden3comm/handlers/payment.d.ts +71 -10
  85. package/dist/types/iden3comm/handlers/revocation-status.d.ts +2 -2
  86. package/dist/types/iden3comm/index.d.ts +1 -0
  87. package/dist/types/iden3comm/packageManager.d.ts +4 -0
  88. package/dist/types/iden3comm/packers/jws.d.ts +5 -0
  89. package/dist/types/iden3comm/packers/plain.d.ts +4 -0
  90. package/dist/types/iden3comm/packers/zkp.d.ts +6 -0
  91. package/dist/types/iden3comm/types/index.d.ts +1 -0
  92. package/dist/types/iden3comm/types/packageManager.d.ts +14 -0
  93. package/dist/types/iden3comm/types/packer.d.ts +25 -0
  94. package/dist/types/iden3comm/types/protocol/accept-profile.d.ts +7 -0
  95. package/dist/types/iden3comm/types/protocol/auth.d.ts +1 -0
  96. package/dist/types/iden3comm/types/protocol/credentials.d.ts +6 -6
  97. package/dist/types/iden3comm/types/protocol/messages.d.ts +2 -2
  98. package/dist/types/iden3comm/types/protocol/payment.d.ts +87 -13
  99. package/dist/types/iden3comm/types/protocol/proof.d.ts +3 -3
  100. package/dist/types/iden3comm/types/protocol/revocation.d.ts +2 -2
  101. package/dist/types/iden3comm/utils/accept-profile.d.ts +3 -0
  102. package/dist/types/iden3comm/utils/index.d.ts +1 -0
  103. package/dist/types/storage/blockchain/did-resolver-readonly-storage.d.ts +16 -0
  104. package/dist/types/storage/blockchain/erc20-helper.d.ts +19 -0
  105. package/dist/types/storage/blockchain/index.d.ts +3 -0
  106. package/dist/types/storage/blockchain/onchain-issuer-adapter/non-merklized/version/v0.0.1/onchain-non-merklized-issuer-adapter.d.ts +66 -0
  107. package/dist/types/storage/blockchain/onchain-issuer.d.ts +40 -0
  108. package/dist/types/storage/blockchain/onchain-zkp-verifier.d.ts +11 -12
  109. package/dist/types/storage/entities/state.d.ts +2 -0
  110. package/dist/types/storage/interfaces/index.d.ts +1 -0
  111. package/dist/types/storage/interfaces/onchain-issuer.d.ts +12 -0
  112. package/dist/types/verifiable/constants.d.ts +28 -11
  113. package/dist/types/verifiable/credential.d.ts +15 -2
  114. package/package.json +3 -2
@@ -7,6 +7,7 @@ import { proving } from '@iden3/js-jwz';
7
7
  import { DID } from '@iden3/js-iden3-core';
8
8
  import * as uuid from 'uuid';
9
9
  import { AbstractMessageHandler } from './message-handler';
10
+ import { verifyExpiresTime } from './common';
10
11
  /**
11
12
  *
12
13
  * Allows to handle Credential offer protocol message and return fetched credential
@@ -46,10 +47,34 @@ export class FetchHandler extends AbstractMessageHandler {
46
47
  return this.handleFetchRequest(message);
47
48
  case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE:
48
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
+ }
49
61
  default:
50
62
  return super.handle(message, ctx);
51
63
  }
52
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
+ }
53
78
  async handleOfferMessage(offerMessage, ctx) {
54
79
  if (!ctx.mediaType) {
55
80
  ctx.mediaType = MediaType.ZKPMessage;
@@ -121,6 +146,9 @@ export class FetchHandler extends AbstractMessageHandler {
121
146
  throw new Error(`jws packer options are required for ${MediaType.SignedMessage}`);
122
147
  }
123
148
  const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE);
149
+ if (!opts?.allowExpiredMessages) {
150
+ verifyExpiresTime(offerMessage);
151
+ }
124
152
  const result = await this.handleOfferMessage(offerMessage, {
125
153
  mediaType: opts?.mediaType,
126
154
  headers: opts?.headers,
@@ -131,6 +159,14 @@ export class FetchHandler extends AbstractMessageHandler {
131
159
  }
132
160
  throw new Error('invalid protocol message response');
133
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
+ }
134
170
  async handleFetchRequest(msgRequest) {
135
171
  if (!msgRequest.to) {
136
172
  throw new Error("failed request. empty 'to' field");
@@ -168,8 +204,11 @@ export class FetchHandler extends AbstractMessageHandler {
168
204
  /**
169
205
  * @inheritdoc IFetchHandler#handleCredentialFetchRequest
170
206
  */
171
- async handleCredentialFetchRequest(envelope) {
207
+ async handleCredentialFetchRequest(envelope, opts) {
172
208
  const msgRequest = await FetchHandler.unpackMessage(this._packerMgr, envelope, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE);
209
+ if (!opts?.allowExpiredMessages) {
210
+ verifyExpiresTime(msgRequest);
211
+ }
173
212
  const request = await this.handleFetchRequest(msgRequest);
174
213
  return this._packerMgr.pack(MediaType.PlainMessage, byteEncoder.encode(JSON.stringify(request)), {});
175
214
  }
@@ -186,8 +225,11 @@ export class FetchHandler extends AbstractMessageHandler {
186
225
  /**
187
226
  * @inheritdoc IFetchHandler#handleIssuanceResponseMessage
188
227
  */
189
- async handleIssuanceResponseMessage(envelop) {
228
+ async handleIssuanceResponseMessage(envelop, opts) {
190
229
  const issuanceMsg = await FetchHandler.unpackMessage(this._packerMgr, envelop, PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE);
230
+ if (!opts?.allowExpiredMessages) {
231
+ verifyExpiresTime(issuanceMsg);
232
+ }
191
233
  await this.handleIssuanceResponseMsg(issuanceMsg);
192
234
  return Uint8Array.from([]);
193
235
  }
@@ -1,5 +1,6 @@
1
1
  import { MediaType } from '../constants';
2
2
  import { proving } from '@iden3/js-jwz';
3
+ import { verifyExpiresTime } from './common';
3
4
  /**
4
5
  * Base implementation of protocol message handler
5
6
  *
@@ -14,6 +15,9 @@ export class AbstractMessageHandler {
14
15
  return messageHandler;
15
16
  }
16
17
  async handle(message, context) {
18
+ if (!context.allowExpiredMessages) {
19
+ verifyExpiresTime(message);
20
+ }
17
21
  if (this.nextMessageHandler)
18
22
  return this.nextMessageHandler.handle(message, context);
19
23
  return Promise.reject('Message handler not provided or message not supported');
@@ -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 { PaymentRequestDataType, PaymentRequestType, PaymentType } from '../../verifiable';
8
+ import { PaymentFeatures, PaymentRequestDataType, PaymentType, SupportedCurrencies, SupportedPaymentProofType } from '../../verifiable';
9
+ import { ethers, parseEther, parseUnits } 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,82 @@ 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 convertedAmount = await convertPaymentAmount(data.amount, data.currency);
40
+ const paymentData = data.type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
41
+ ? {
42
+ recipient: data.recipient,
43
+ amount: convertedAmount,
44
+ expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
45
+ nonce: data.nonce,
46
+ metadata: '0x'
47
+ }
48
+ : {
49
+ tokenAddress: data.tokenAddress,
50
+ recipient: data.recipient,
51
+ amount: convertedAmount,
52
+ expirationDate: getUnixTimestamp(new Date(data.expirationDate)),
53
+ nonce: data.nonce,
54
+ metadata: '0x'
55
+ };
56
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
57
+ const typesFetchResult = await fetch(proof.eip712.types);
58
+ const types = await typesFetchResult.json();
59
+ delete types.EIP712Domain;
60
+ const recovered = ethers.verifyTypedData(proof.eip712.domain, types, paymentData, proof.proofValue);
61
+ const { didDocument } = await resolver.resolve(proof.verificationMethod);
62
+ if (didDocument?.verificationMethod) {
63
+ for (const verificationMethod of didDocument.verificationMethod) {
64
+ if (verificationMethod.blockchainAccountId?.split(':').slice(-1)[0].toLowerCase() ===
65
+ recovered.toLowerCase()) {
66
+ return recovered;
67
+ }
68
+ }
69
+ }
70
+ else {
71
+ throw new Error('failed request. issuer DIDDocument does not contain any verificationMethods');
72
+ }
73
+ throw new Error(`failed request. no matching verificationMethod`);
74
+ }
75
+ export async function convertPaymentAmount(amount, currency) {
76
+ let convertedAmount = 0n;
77
+ switch (currency) {
78
+ case SupportedCurrencies.ETH:
79
+ case SupportedCurrencies.POL:
80
+ case SupportedCurrencies.MATIC:
81
+ convertedAmount = parseEther(amount.toString());
82
+ break;
83
+ case SupportedCurrencies.ETH_WEI:
84
+ convertedAmount = parseUnits(amount.toString(), 'wei');
85
+ break;
86
+ case SupportedCurrencies.ETH_GWEI:
87
+ convertedAmount = parseUnits(amount.toString(), 'gwei');
88
+ break;
89
+ case SupportedCurrencies.USDC:
90
+ case SupportedCurrencies.USDT: {
91
+ convertedAmount = parseUnits(amount.toString(), 6);
92
+ break;
93
+ }
94
+ default:
95
+ throw new Error(`failed request. unsupported currency ${currency}`);
96
+ }
97
+ return convertedAmount;
98
+ }
34
99
  /**
35
100
  * @beta
36
101
  * createPayment is a function to create protocol payment message
37
102
  * @param {DID} sender - sender did
38
103
  * @param {DID} receiver - receiver did
39
- * @param {PaymentInfo[]} payments - payments
104
+ * @param {PaymentMessageBody} body - payments
40
105
  * @returns `PaymentMessage`
41
106
  */
42
- export function createPayment(sender, receiver, payments) {
107
+ export function createPayment(sender, receiver, payments, opts) {
43
108
  const uuidv4 = uuid.v4();
44
109
  const request = {
45
110
  id: uuidv4,
@@ -50,7 +115,9 @@ export function createPayment(sender, receiver, payments) {
50
115
  type: PROTOCOL_MESSAGE_TYPE.PAYMENT_MESSAGE_TYPE,
51
116
  body: {
52
117
  payments
53
- }
118
+ },
119
+ created_time: getUnixTimestamp(new Date()),
120
+ expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
54
121
  };
55
122
  return request;
56
123
  }
@@ -112,21 +179,28 @@ export class PaymentHandler extends AbstractMessageHandler {
112
179
  const receiverDID = DID.parse(paymentRequest.from);
113
180
  const payments = [];
114
181
  for (let i = 0; i < paymentRequest.body.payments.length; i++) {
115
- const paymentReq = paymentRequest.body.payments[i];
116
- if (paymentReq.type !== PaymentRequestType.PaymentRequest) {
117
- throw new Error(`failed request. not supported '${paymentReq.type}' payment type `);
182
+ const { data } = paymentRequest.body.payments[i];
183
+ const selectedPayment = Array.isArray(data)
184
+ ? data.find((p) => {
185
+ return p.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
186
+ ? p.id === ctx.nonce
187
+ : p.nonce === ctx.nonce;
188
+ })
189
+ : data;
190
+ if (!selectedPayment) {
191
+ throw new Error(`failed request. no payment in request for nonce ${ctx.nonce}`);
118
192
  }
119
- if (paymentReq.data.type !== PaymentRequestDataType.Iden3PaymentRequestCryptoV1) {
120
- throw new Error(`failed request. not supported '${paymentReq.data.type}' payment type `);
193
+ switch (selectedPayment.type) {
194
+ case PaymentRequestDataType.Iden3PaymentRequestCryptoV1:
195
+ payments.push(await this.handleIden3PaymentRequestCryptoV1(selectedPayment, ctx.paymentHandler));
196
+ break;
197
+ case PaymentRequestDataType.Iden3PaymentRailsRequestV1:
198
+ payments.push(await this.handleIden3PaymentRailsRequestV1(selectedPayment, ctx.paymentHandler));
199
+ break;
200
+ case PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1:
201
+ payments.push(await this.handleIden3PaymentRailsERC20RequestV1(selectedPayment, ctx.paymentHandler, ctx.erc20TokenApproveHandler));
202
+ break;
121
203
  }
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
204
  }
131
205
  const paymentMessage = createPayment(senderDID, receiverDID, payments);
132
206
  const response = await this.packMessage(paymentMessage, senderDID);
@@ -159,6 +233,9 @@ export class PaymentHandler extends AbstractMessageHandler {
159
233
  if (!paymentRequest.to) {
160
234
  throw new Error(`failed request. empty 'to' field`);
161
235
  }
236
+ if (!opts?.allowExpiredMessages) {
237
+ verifyExpiresTime(paymentRequest);
238
+ }
162
239
  const agentMessage = await this.handlePaymentRequestMessage(paymentRequest, opts);
163
240
  if (!agentMessage) {
164
241
  return null;
@@ -169,24 +246,121 @@ export class PaymentHandler extends AbstractMessageHandler {
169
246
  /**
170
247
  * @inheritdoc IPaymentHandler#handlePayment
171
248
  */
172
- async handlePayment(payment, opts) {
173
- if (opts.paymentRequest.from !== payment.to) {
174
- throw new Error(`sender of the request is not a target of response - expected ${opts.paymentRequest.from}, given ${payment.to}`);
249
+ async handlePayment(payment, params) {
250
+ if (!params?.allowExpiredMessages) {
251
+ verifyExpiresTime(payment);
252
+ }
253
+ if (params.paymentRequest.from !== payment.to) {
254
+ throw new Error(`sender of the request is not a target of response - expected ${params.paymentRequest.from}, given ${payment.to}`);
175
255
  }
176
256
  if (!payment.body.payments.length) {
177
257
  throw new Error(`failed request. empty 'payments' field in body`);
178
258
  }
259
+ if (!params.paymentValidationHandler) {
260
+ throw new Error(`please provide payment validation handler in options`);
261
+ }
179
262
  for (let i = 0; i < payment.body.payments.length; i++) {
180
263
  const p = payment.body.payments[i];
181
- const paymentRequestData = opts.paymentRequest.body.payments.find((r) => r.data.id === p.id);
182
- if (!paymentRequestData) {
183
- throw new Error(`can't find payment request for payment id ${p.id}`);
264
+ const nonce = p.type === PaymentType.Iden3PaymentCryptoV1 ? p.id : p.nonce;
265
+ const requestDataArr = params.paymentRequest.body.payments
266
+ .map((r) => (Array.isArray(r.data) ? r.data : [r.data]))
267
+ .flat();
268
+ const requestData = requestDataArr.find((r) => r.type === PaymentRequestDataType.Iden3PaymentRequestCryptoV1
269
+ ? r.id === nonce
270
+ : r.nonce === nonce);
271
+ if (!requestData) {
272
+ throw new Error(`can't find payment request for payment ${p.type === PaymentType.Iden3PaymentCryptoV1 ? 'id' : 'nonce'} ${nonce}`);
184
273
  }
185
- if (!opts.paymentValidationHandler) {
186
- throw new Error(`please provide payment validation handler in options`);
274
+ await params.paymentValidationHandler(p.paymentData.txId, requestData);
275
+ }
276
+ }
277
+ /**
278
+ * @inheritdoc IPaymentHandler#createPaymentRailsV1
279
+ */
280
+ async createPaymentRailsV1(sender, receiver, agent, signer, payments) {
281
+ const paymentRequestInfo = [];
282
+ for (let i = 0; i < payments.length; i++) {
283
+ const { credentials, description } = payments[i];
284
+ const dataArr = [];
285
+ for (let j = 0; j < payments[i].chains.length; j++) {
286
+ const { features, nonce, amount, currency, chainId, expirationDate, type } = payments[i].chains[j];
287
+ const multiChainConfig = this._params.multiChainPaymentConfig?.find((c) => c.chainId === chainId);
288
+ if (!multiChainConfig) {
289
+ throw new Error(`failed request. no config for chain ${chainId}`);
290
+ }
291
+ const { recipient, paymentContract, erc20TokenAddressArr } = multiChainConfig;
292
+ const tokenAddress = erc20TokenAddressArr.find((t) => t.symbol === currency)?.address;
293
+ if (type === PaymentRequestDataType.Iden3PaymentRailsERC20RequestV1 && !tokenAddress) {
294
+ throw new Error(`failed request. no token address for currency ${currency}`);
295
+ }
296
+ const expirationDateRequired = expirationDate ?? new Date(new Date().setHours(new Date().getHours() + 1));
297
+ const typeUrl = `https://schema.iden3.io/core/json/${type}.json`;
298
+ const typesFetchResult = await fetch(typeUrl);
299
+ const types = await typesFetchResult.json();
300
+ delete types.EIP712Domain;
301
+ const convertedAmount = await convertPaymentAmount(amount, currency);
302
+ const paymentData = type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
303
+ ? {
304
+ recipient,
305
+ amount: convertedAmount,
306
+ expirationDate: getUnixTimestamp(expirationDateRequired),
307
+ nonce,
308
+ metadata: '0x'
309
+ }
310
+ : {
311
+ tokenAddress,
312
+ recipient,
313
+ amount: convertedAmount,
314
+ expirationDate: getUnixTimestamp(expirationDateRequired),
315
+ nonce,
316
+ metadata: '0x'
317
+ };
318
+ const domain = {
319
+ name: 'MCPayment',
320
+ version: '1.0.0',
321
+ chainId,
322
+ verifyingContract: paymentContract
323
+ };
324
+ const signature = await signer.signTypedData(domain, types, paymentData);
325
+ const proof = [
326
+ {
327
+ type: SupportedPaymentProofType.EthereumEip712Signature2021,
328
+ proofPurpose: 'assertionMethod',
329
+ proofValue: signature,
330
+ verificationMethod: `did:pkh:eip155:${chainId}:${await signer.getAddress()}`,
331
+ created: new Date().toISOString(),
332
+ eip712: {
333
+ types: typeUrl,
334
+ primaryType: 'Iden3PaymentRailsRequestV1',
335
+ domain
336
+ }
337
+ }
338
+ ];
339
+ const d = {
340
+ type: PaymentRequestDataType.Iden3PaymentRailsRequestV1,
341
+ '@context': [
342
+ `https://schema.iden3.io/core/jsonld/payment.jsonld#${type}`,
343
+ 'https://w3id.org/security/suites/eip712sig-2021/v1'
344
+ ],
345
+ recipient,
346
+ amount: amount.toString(),
347
+ currency,
348
+ expirationDate: expirationDateRequired.toISOString(),
349
+ nonce: nonce.toString(),
350
+ metadata: '0x',
351
+ proof
352
+ };
353
+ dataArr.push(type === PaymentRequestDataType.Iden3PaymentRailsRequestV1
354
+ ? d
355
+ : { ...d, type, tokenAddress: tokenAddress || '', features: features || [] });
187
356
  }
188
- await opts.paymentValidationHandler(p.paymentData.txId, paymentRequestData.data);
357
+ paymentRequestInfo.push({
358
+ data: dataArr,
359
+ credentials,
360
+ description
361
+ });
189
362
  }
363
+ return createPaymentRequest(sender, receiver, agent, paymentRequestInfo);
190
364
  }
191
365
  async packMessage(message, senderDID) {
192
366
  const responseEncoded = byteEncoder.encode(JSON.stringify(message));
@@ -200,4 +374,65 @@ export class PaymentHandler extends AbstractMessageHandler {
200
374
  ...packerOpts
201
375
  });
202
376
  }
377
+ async handleIden3PaymentRequestCryptoV1(data, paymentHandler) {
378
+ if (data.expiration && new Date(data.expiration) < new Date()) {
379
+ throw new Error(`failed request. expired request`);
380
+ }
381
+ const txId = await paymentHandler(data);
382
+ return {
383
+ id: data.id,
384
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentCryptoV1',
385
+ type: PaymentType.Iden3PaymentCryptoV1,
386
+ paymentData: {
387
+ txId
388
+ }
389
+ };
390
+ }
391
+ async handleIden3PaymentRailsRequestV1(data, paymentHandler) {
392
+ if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
393
+ throw new Error(`failed request. expired request`);
394
+ }
395
+ const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
396
+ if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
397
+ throw new Error(`failed request. signer is not in the allowed signers list`);
398
+ }
399
+ const txId = await paymentHandler(data);
400
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
401
+ return {
402
+ nonce: data.nonce,
403
+ type: PaymentType.Iden3PaymentRailsV1,
404
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsV1',
405
+ paymentData: {
406
+ txId,
407
+ chainId: proof.eip712.domain.chainId
408
+ }
409
+ };
410
+ }
411
+ async handleIden3PaymentRailsERC20RequestV1(data, paymentHandler, approveHandler) {
412
+ if (data.expirationDate && new Date(data.expirationDate) < new Date()) {
413
+ throw new Error(`failed request. expired request`);
414
+ }
415
+ const signer = await verifyEIP712TypedData(data, this._params.documentResolver);
416
+ if (this._params.allowedSigners && !this._params.allowedSigners.includes(signer)) {
417
+ throw new Error(`failed request. signer is not in the allowed signers list`);
418
+ }
419
+ if (!data.features?.includes(PaymentFeatures.EIP_2612) && !approveHandler) {
420
+ throw new Error(`please provide erc20TokenApproveHandler in context for ERC-20 payment type`);
421
+ }
422
+ if (approveHandler) {
423
+ await approveHandler(data);
424
+ }
425
+ const txId = await paymentHandler(data);
426
+ const proof = Array.isArray(data.proof) ? data.proof[0] : data.proof;
427
+ return {
428
+ nonce: data.nonce,
429
+ type: PaymentType.Iden3PaymentRailsERC20V1,
430
+ '@context': 'https://schema.iden3.io/core/jsonld/payment.jsonld#Iden3PaymentRailsERC20V1',
431
+ paymentData: {
432
+ txId,
433
+ chainId: proof.eip712.domain.chainId,
434
+ tokenAddress: data.tokenAddress
435
+ }
436
+ };
437
+ }
203
438
  }
@@ -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,
@@ -3,5 +3,6 @@ export * from './packers';
3
3
  export * from './types';
4
4
  export * from './handlers';
5
5
  export * from './utils/did';
6
+ export * from './utils/accept-profile';
6
7
  import * as PROTOCOL_CONSTANTS from './constants';
7
8
  export { PROTOCOL_CONSTANTS };
@@ -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';