@cheqd/did-provider-cheqd 3.2.1 → 3.3.0-develop.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 (86) hide show
  1. package/build/cjs/agent/ICheqd.d.ts +513 -14
  2. package/build/cjs/agent/ICheqd.d.ts.map +1 -1
  3. package/build/cjs/agent/ICheqd.js +1446 -5
  4. package/build/cjs/agent/ICheqd.js.map +1 -1
  5. package/build/cjs/did-manager/cheqd-did-provider.d.ts +26 -7
  6. package/build/cjs/did-manager/cheqd-did-provider.d.ts.map +1 -1
  7. package/build/cjs/did-manager/cheqd-did-provider.js +30 -8
  8. package/build/cjs/did-manager/cheqd-did-provider.js.map +1 -1
  9. package/build/cjs/did-manager/cheqd-did-resolver.d.ts +5 -0
  10. package/build/cjs/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  11. package/build/cjs/did-manager/cheqd-did-resolver.js +7 -2
  12. package/build/cjs/did-manager/cheqd-did-resolver.js.map +1 -1
  13. package/build/cjs/dkg-threshold/lit-protocol.d.ts +92 -0
  14. package/build/cjs/dkg-threshold/lit-protocol.d.ts.map +1 -0
  15. package/build/cjs/dkg-threshold/lit-protocol.js +170 -0
  16. package/build/cjs/dkg-threshold/lit-protocol.js.map +1 -0
  17. package/build/cjs/global.d..d.ts +2 -0
  18. package/build/cjs/global.d..d.ts.map +1 -0
  19. package/build/cjs/global.d..js +2 -0
  20. package/build/cjs/global.d..js.map +1 -0
  21. package/build/cjs/index.js +1 -2
  22. package/build/cjs/index.js.map +1 -1
  23. package/build/cjs/utils/env.d.ts +7 -0
  24. package/build/cjs/utils/env.d.ts.map +1 -0
  25. package/build/cjs/utils/env.js +10 -0
  26. package/build/cjs/utils/env.js.map +1 -0
  27. package/build/cjs/utils/helpers.d.ts +12 -0
  28. package/build/cjs/utils/helpers.d.ts.map +1 -0
  29. package/build/cjs/utils/helpers.js +63 -0
  30. package/build/cjs/utils/helpers.js.map +1 -0
  31. package/build/esm/agent/ICheqd.d.ts +513 -14
  32. package/build/esm/agent/ICheqd.d.ts.map +1 -1
  33. package/build/esm/agent/ICheqd.js +1446 -5
  34. package/build/esm/agent/ICheqd.js.map +1 -1
  35. package/build/esm/did-manager/cheqd-did-provider.d.ts +26 -7
  36. package/build/esm/did-manager/cheqd-did-provider.d.ts.map +1 -1
  37. package/build/esm/did-manager/cheqd-did-provider.js +29 -7
  38. package/build/esm/did-manager/cheqd-did-provider.js.map +1 -1
  39. package/build/esm/did-manager/cheqd-did-resolver.d.ts +5 -0
  40. package/build/esm/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  41. package/build/esm/did-manager/cheqd-did-resolver.js +6 -1
  42. package/build/esm/did-manager/cheqd-did-resolver.js.map +1 -1
  43. package/build/esm/dkg-threshold/lit-protocol.d.ts +92 -0
  44. package/build/esm/dkg-threshold/lit-protocol.d.ts.map +1 -0
  45. package/build/esm/dkg-threshold/lit-protocol.js +166 -0
  46. package/build/esm/dkg-threshold/lit-protocol.js.map +1 -0
  47. package/build/esm/global.d..d.ts +2 -0
  48. package/build/esm/global.d..d.ts.map +1 -0
  49. package/build/esm/global.d..js +2 -0
  50. package/build/esm/global.d..js.map +1 -0
  51. package/build/esm/index.js +1 -1
  52. package/build/esm/index.js.map +1 -1
  53. package/build/esm/utils/env.d.ts +7 -0
  54. package/build/esm/utils/env.d.ts.map +1 -0
  55. package/build/esm/utils/env.js +7 -0
  56. package/build/esm/utils/env.js.map +1 -0
  57. package/build/esm/utils/helpers.d.ts +12 -0
  58. package/build/esm/utils/helpers.d.ts.map +1 -0
  59. package/build/esm/utils/helpers.js +51 -0
  60. package/build/esm/utils/helpers.js.map +1 -0
  61. package/build/tsconfig.cjs.tsbuildinfo +1 -1
  62. package/build/tsconfig.esm.tsbuildinfo +1 -1
  63. package/build/tsconfig.types.tsbuildinfo +1 -1
  64. package/build/types/agent/ICheqd.d.ts +513 -14
  65. package/build/types/agent/ICheqd.d.ts.map +1 -1
  66. package/build/types/did-manager/cheqd-did-provider.d.ts +26 -7
  67. package/build/types/did-manager/cheqd-did-provider.d.ts.map +1 -1
  68. package/build/types/did-manager/cheqd-did-resolver.d.ts +5 -0
  69. package/build/types/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  70. package/build/types/dkg-threshold/lit-protocol.d.ts +92 -0
  71. package/build/types/dkg-threshold/lit-protocol.d.ts.map +1 -0
  72. package/build/types/global.d..d.ts +2 -0
  73. package/build/types/global.d..d.ts.map +1 -0
  74. package/build/types/utils/env.d.ts +7 -0
  75. package/build/types/utils/env.d.ts.map +1 -0
  76. package/build/types/utils/helpers.d.ts +12 -0
  77. package/build/types/utils/helpers.d.ts.map +1 -0
  78. package/package.json +7 -1
  79. package/src/agent/ICheqd.ts +2209 -232
  80. package/src/did-manager/cheqd-did-provider.ts +55 -8
  81. package/src/did-manager/cheqd-did-resolver.ts +7 -1
  82. package/src/dkg-threshold/lit-protocol.ts +238 -0
  83. package/src/global.d..ts +1 -0
  84. package/src/utils/env.ts +6 -0
  85. package/src/utils/helpers.ts +66 -0
  86. package/tsconfig.json +1 -0
@@ -2,20 +2,45 @@
2
2
  // any is used for extensibility
3
3
  // unused vars are kept by convention
4
4
  // non-null assertion is used when we know better than the compiler that the value is not null or undefined
5
- import { createDidPayload, createDidVerificationMethod, createKeyPairBase64, createKeyPairHex, createVerificationKeys } from '@cheqd/sdk';
5
+ import { CheqdNetwork, createDidPayload, createDidVerificationMethod, createKeyPairBase64, createKeyPairHex, createVerificationKeys } from '@cheqd/sdk';
6
+ import { DefaultRESTUrls } from '../did-manager/cheqd-did-provider.js';
6
7
  import { fromString, toString } from 'uint8arrays';
8
+ import { decodeJWT } from 'did-jwt';
9
+ import { StatusList } from '@digitalbazaar/vc-status-list';
7
10
  import { v4 } from 'uuid';
8
11
  import fs from 'fs';
9
12
  import Debug from 'debug';
13
+ import { LitCompatibleCosmosChains, LitProtocol } from '../dkg-threshold/lit-protocol.js';
14
+ import { blobToHexString, randomFromRange, toBlob, unescapeUnicode } from '../utils/helpers.js';
15
+ import { resolverUrl } from '../did-manager/cheqd-did-resolver.js';
10
16
  const debug = Debug('veramo:did-provider-cheqd');
17
+ export const AccessControlConditionTypes = { memoNonce: 'memoNonce', balance: 'balance' };
18
+ export const AccessControlConditionReturnValueComparators = { lessThan: '<', greaterThan: '>', equalTo: '=', lessThanOrEqualTo: '<=', greaterThanOrEqualTo: '>=' };
11
19
  const CreateIdentifierMethodName = 'cheqdCreateIdentifier';
12
20
  const UpdateIdentifierMethodName = 'cheqdUpdateIdentifier';
13
21
  const DeactivateIdentifierMethodName = 'cheqdDeactivateIdentifier';
14
22
  const CreateResourceMethodName = 'cheqdCreateLinkedResource';
23
+ const CreateStatusList2021MethodName = 'cheqdCreateStatusList2021';
24
+ const CreateEncryptedStatusList2021MethodName = 'cheqdCreateEncryptedStatusList2021';
15
25
  const GenerateDidDocMethodName = 'cheqdGenerateDidDoc';
16
26
  const GenerateDidDocWithLinkedResourceMethodName = 'cheqdGenerateDidDocWithLinkedResource';
17
27
  const GenerateKeyPairMethodName = 'cheqdGenerateIdentityKeys';
18
28
  const GenerateVersionIdMethodName = 'cheqdGenerateVersionId';
29
+ const GenerateStatusList2021MethodName = 'cheqdGenerateStatusList2021';
30
+ const GenerateEncryptedStatusList2021MethodName = 'cheqdGenerateEncryptedStatusList2021';
31
+ const IssueRevocableCredentialWithStatusList2021MethodName = 'cheqdIssueRevocableCredentialWithStatusList2021';
32
+ const IssueSuspendableCredentialWithStatusList2021MethodName = 'cheqdIssueSuspendableCredentialWithStatusList2021';
33
+ const VerifyCredentialMethodName = 'cheqdVerifyCredential';
34
+ const VerifyPresentationMethodName = 'cheqdVerifyPresentation';
35
+ const CheckCredentialStatusMethodName = 'cheqdCheckCredentialStatus';
36
+ const RevokeCredentialMethodName = 'cheqdRevokeCredential';
37
+ const RevokeCredentialsMethodName = 'cheqdRevokeCredentials';
38
+ const SuspendCredentialMethodName = 'cheqdSuspendCredential';
39
+ const SuspendCredentialsMethodName = 'cheqdSuspendCredentials';
40
+ const UnsuspendCredentialMethodName = 'cheqdUnsuspendCredential';
41
+ const UnsuspendCredentialsMethodName = 'cheqdUnsuspendCredentials';
42
+ const TransactVerifierPaysIssuerMethodName = 'cheqdTransactVerifierPaysIssuer';
43
+ const ObserveVerifierPaysIssuerMethodName = 'cheqdObserveVerifierPaysIssuer';
19
44
  const DidPrefix = 'did';
20
45
  const CheqdDidMethod = 'cheqd';
21
46
  export class Cheqd {
@@ -92,6 +117,42 @@ export class Cheqd {
92
117
  "args"
93
118
  ]
94
119
  },
120
+ "returnType": {
121
+ "type": "boolean"
122
+ }
123
+ },
124
+ "cheqdCreateStatusList2021": {
125
+ "description": "Create a new Status List 2021",
126
+ "arguments": {
127
+ "type": "object",
128
+ "properties": {
129
+ "args": {
130
+ "type": "object",
131
+ "description": "A cheqdCreateStatusList2021Args object as any for extensibility"
132
+ }
133
+ },
134
+ "required": [
135
+ "args"
136
+ ]
137
+ },
138
+ "returnType": {
139
+ "type": "boolean"
140
+ }
141
+ },
142
+ "cheqdCreateEncryptedStatusList2021": {
143
+ "description": "Create a new Encrypted Status List 2021",
144
+ "arguments": {
145
+ "type": "object",
146
+ "properties": {
147
+ "args": {
148
+ "type": "object",
149
+ "description": "A cheqdCreateEncryptedStatusList2021Args object as any for extensibility"
150
+ }
151
+ },
152
+ "required": [
153
+ "args"
154
+ ]
155
+ },
95
156
  "returnType": {
96
157
  "type": "object"
97
158
  }
@@ -156,7 +217,274 @@ export class Cheqd {
156
217
  "type": "object",
157
218
  "description": "A cheqdGenerateVersionIdArgs object as any for extensibility"
158
219
  }
159
- }
220
+ },
221
+ },
222
+ "returnType": {
223
+ "type": "object"
224
+ }
225
+ },
226
+ "cheqdGenerateStatusList2021": {
227
+ "description": "Generate a new Status List 2021",
228
+ "arguments": {
229
+ "type": "object",
230
+ "properties": {
231
+ "args": {
232
+ "type": "object",
233
+ "description": "A cheqdGenerateStatusList2021Args object as any for extensibility"
234
+ }
235
+ },
236
+ },
237
+ "returnType": {
238
+ "type": "string"
239
+ }
240
+ },
241
+ "cheqdGenerateEncryptedStatusList2021": {
242
+ "description": "Generate a new encrypted Status List 2021",
243
+ "arguments": {
244
+ "type": "object",
245
+ "properties": {
246
+ "args": {
247
+ "type": "object",
248
+ "description": "A cheqdGenerateEncryptedStatusList2021Args object as any for extensibility"
249
+ }
250
+ },
251
+ "required": [
252
+ "args"
253
+ ]
254
+ },
255
+ "returnType": {
256
+ "type": "string"
257
+ }
258
+ },
259
+ "cheqdIssueRevocableCredentialWithStatusList2021": {
260
+ "description": "Issue a revocable credential with a Status List 2021 as credential status registry",
261
+ "arguments": {
262
+ "type": "object",
263
+ "properties": {
264
+ "args": {
265
+ "type": "object",
266
+ "description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
267
+ }
268
+ },
269
+ "required": [
270
+ "args"
271
+ ]
272
+ },
273
+ "returnType": {
274
+ "type": "object"
275
+ }
276
+ },
277
+ "cheqdIssueSuspendableCredentialWithStatusList2021": {
278
+ "description": "Issue a suspendable credential with a Status List 2021 as credential status registry",
279
+ "arguments": {
280
+ "type": "object",
281
+ "properties": {
282
+ "args": {
283
+ "type": "object",
284
+ "description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
285
+ }
286
+ },
287
+ "required": [
288
+ "args"
289
+ ]
290
+ },
291
+ "returnType": {
292
+ "type": "object"
293
+ }
294
+ },
295
+ "cheqdVerifyCredential": {
296
+ "description": "Verify a credential, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
297
+ "arguments": {
298
+ "type": "object",
299
+ "properties": {
300
+ "args": {
301
+ "type": "object",
302
+ "description": "A cheqdVerifyCredentialWithStatusList2021Args object as any for extensibility"
303
+ }
304
+ },
305
+ "required": [
306
+ "args"
307
+ ]
308
+ },
309
+ "returnType": {
310
+ "type": "object"
311
+ }
312
+ },
313
+ "cheqdVerifyPresentation": {
314
+ "description": "Verify a presentation, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
315
+ "arguments": {
316
+ "type": "object",
317
+ "properties": {
318
+ "args": {
319
+ "type": "object",
320
+ "description": "A cheqdVerifyPresentationWithStatusList2021Args object as any for extensibility"
321
+ }
322
+ },
323
+ "required": [
324
+ "args"
325
+ ]
326
+ },
327
+ "returnType": {
328
+ "type": "object"
329
+ }
330
+ },
331
+ "cheqdCheckCredentialStatus": {
332
+ "description": "Check the revocation / suspension status of a credential with a Status List 2021 as credential status registry",
333
+ "arguments": {
334
+ "type": "object",
335
+ "properties": {
336
+ "args": {
337
+ "type": "object",
338
+ "description": "A cheqdCheckCredentialStatusWithStatusList2021Args object as any for extensibility"
339
+ }
340
+ },
341
+ "required": [
342
+ "args"
343
+ ]
344
+ },
345
+ "returnType": {
346
+ "type": "object"
347
+ }
348
+ },
349
+ "cheqdRevokeCredential": {
350
+ "description": "Revoke a credential against a Status List 2021 as credential status registry",
351
+ "arguments": {
352
+ "type": "object",
353
+ "properties": {
354
+ "args": {
355
+ "type": "object",
356
+ "description": "A cheqdRevokeCredentialWithStatusList2021Args object as any for extensibility"
357
+ }
358
+ },
359
+ "required": [
360
+ "args"
361
+ ]
362
+ },
363
+ "returnType": {
364
+ "type": "object"
365
+ }
366
+ },
367
+ "cheqdRevokeCredentials": {
368
+ "description": "Revoke multiple credentials against a Status List 2021 as credential status registry",
369
+ "arguments": {
370
+ "type": "object",
371
+ "properties": {
372
+ "args": {
373
+ "type": "object",
374
+ "description": "A cheqdRevokeBulkCredentialsWithStatusList2021Args object as any for extensibility"
375
+ }
376
+ },
377
+ "required": [
378
+ "args"
379
+ ]
380
+ },
381
+ "returnType": {
382
+ "type": "array"
383
+ }
384
+ },
385
+ "cheqdSuspendCredential": {
386
+ "description": "Suspend a credential against a Status List 2021 as credential status registry",
387
+ "arguments": {
388
+ "type": "object",
389
+ "properties": {
390
+ "args": {
391
+ "type": "object",
392
+ "description": "A cheqdSuspendCredentialWithStatusList2021Args object as any for extensibility"
393
+ }
394
+ },
395
+ "required": [
396
+ "args"
397
+ ]
398
+ },
399
+ "returnType": {
400
+ "type": "object"
401
+ }
402
+ },
403
+ "cheqdSuspendCredentials": {
404
+ "description": "Suspend multiple credentials against a Status List 2021 as credential status registry",
405
+ "arguments": {
406
+ "type": "object",
407
+ "properties": {
408
+ "args": {
409
+ "type": "object",
410
+ "description": "A cheqdSuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
411
+ }
412
+ },
413
+ "required": [
414
+ "args"
415
+ ]
416
+ },
417
+ "returnType": {
418
+ "type": "array"
419
+ }
420
+ },
421
+ "cheqdUnsuspendCredential": {
422
+ "description": "Unsuspend a credential against a Status List 2021 as credential status registry",
423
+ "arguments": {
424
+ "type": "object",
425
+ "properties": {
426
+ "args": {
427
+ "type": "object",
428
+ "description": "cheqdUnsuspendCredentialWithStatusList2021Args object as any for extensibility"
429
+ }
430
+ },
431
+ "required": [
432
+ "args"
433
+ ]
434
+ },
435
+ "returnType": {
436
+ "type": "object"
437
+ }
438
+ },
439
+ "cheqdUnsuspendCredentials": {
440
+ "description": "Unsuspend multiple credentials against a Status List 2021 as credential status registry",
441
+ "arguments": {
442
+ "type": "object",
443
+ "properties": {
444
+ "args": {
445
+ "type": "object",
446
+ "description": "A cheqdUnsuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
447
+ }
448
+ },
449
+ "required": [
450
+ "args"
451
+ ]
452
+ },
453
+ "returnType": {
454
+ "type": "array"
455
+ }
456
+ },
457
+ "cheqdTransactVerifierPaysIssuer": {
458
+ "description": "Initiate a transaction where the verifier pays the issuer for a credential status check",
459
+ "arguments": {
460
+ "type": "object",
461
+ "properties": {
462
+ "args": {
463
+ "type": "object",
464
+ "description": "A cheqdTransactVerifierPaysIssuerArgs object as any for extensibility"
465
+ }
466
+ },
467
+ "required": [
468
+ "args"
469
+ ]
470
+ },
471
+ "returnType": {
472
+ "type": "object"
473
+ }
474
+ },
475
+ "cheqdObserveVerifierPaysIssuer": {
476
+ "description": "Observe a transaction where the verifier pays the issuer for a credential status check",
477
+ "arguments": {
478
+ "type": "object",
479
+ "properties": {
480
+ "args": {
481
+ "type": "object",
482
+ "description": "cheqdObserveVerifierPaysIssuerArgs object as any for extensibility"
483
+ }
484
+ },
485
+ "required": [
486
+ "args"
487
+ ]
160
488
  },
161
489
  "returnType": {
162
490
  "type": "object"
@@ -168,6 +496,9 @@ export class Cheqd {
168
496
  supportedDidProviders;
169
497
  didProvider;
170
498
  providerId;
499
+ static defaultStatusList2021Length = 16 * 1024 * 8; // 16KB in bits or 131072 bits / entries
500
+ static defaultContextV1 = 'https://www.w3.org/2018/credentials/v1';
501
+ static statusList2021Context = 'https://w3id.org/vc-status-list-2021/v1';
171
502
  constructor(args) {
172
503
  if (typeof args.providers !== 'object') {
173
504
  throw new Error('[did-provider-cheqd]: at least one did provider is required');
@@ -180,10 +511,27 @@ export class Cheqd {
180
511
  [UpdateIdentifierMethodName]: this.UpdateIdentifier.bind(this),
181
512
  [DeactivateIdentifierMethodName]: this.DeactivateIdentifier.bind(this),
182
513
  [CreateResourceMethodName]: this.CreateResource.bind(this),
514
+ [CreateStatusList2021MethodName]: this.CreateStatusList2021.bind(this),
515
+ [CreateEncryptedStatusList2021MethodName]: this.CreateEncryptedStatusList2021.bind(this),
183
516
  [GenerateDidDocMethodName]: this.GenerateDidDoc.bind(this),
184
517
  [GenerateDidDocWithLinkedResourceMethodName]: this.GenerateDidDocWithLinkedResource.bind(this),
185
518
  [GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
186
- [GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this)
519
+ [GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this),
520
+ [GenerateStatusList2021MethodName]: this.GenerateStatusList2021.bind(this),
521
+ [GenerateEncryptedStatusList2021MethodName]: this.GenerateEncryptedStatusList2021.bind(this),
522
+ [IssueRevocableCredentialWithStatusList2021MethodName]: this.IssueRevocableCredentialWithStatusList2021.bind(this),
523
+ [IssueSuspendableCredentialWithStatusList2021MethodName]: this.IssueSuspendableCredentialWithStatusList2021.bind(this),
524
+ [VerifyCredentialMethodName]: this.VerifyCredentialWithStatusList2021.bind(this),
525
+ [VerifyPresentationMethodName]: this.VerifyPresentationWithStatusList2021.bind(this),
526
+ [CheckCredentialStatusMethodName]: this.CheckCredentialStatusWithStatusList2021.bind(this),
527
+ [RevokeCredentialMethodName]: this.RevokeCredentialWithStatusList2021.bind(this),
528
+ [RevokeCredentialsMethodName]: this.RevokeBulkCredentialsWithStatusList2021.bind(this),
529
+ [SuspendCredentialMethodName]: this.SuspendCredentialWithStatusList2021.bind(this),
530
+ [SuspendCredentialsMethodName]: this.SuspendBulkCredentialsWithStatusList2021.bind(this),
531
+ [UnsuspendCredentialMethodName]: this.UnsuspendCredentialWithStatusList2021.bind(this),
532
+ [UnsuspendCredentialsMethodName]: this.UnsuspendBulkCredentialsWithStatusList2021.bind(this),
533
+ [TransactVerifierPaysIssuerMethodName]: this.TransactVerifierPaysIssuer.bind(this),
534
+ [ObserveVerifierPaysIssuerMethodName]: this.ObserveVerifierPaysIssuer.bind(this),
187
535
  };
188
536
  }
189
537
  async CreateIdentifier(args, context) {
@@ -224,7 +572,6 @@ export class Cheqd {
224
572
  return await context.agent.didManagerUpdate({
225
573
  did: args.document.id,
226
574
  document: args.document,
227
- provider: this.providerId,
228
575
  options: {
229
576
  kms: args.kms,
230
577
  keys: args.keys,
@@ -263,7 +610,7 @@ export class Cheqd {
263
610
  throw new Error('[did-provider-cheqd]: network is required');
264
611
  }
265
612
  if (args?.file) {
266
- args.payload.data = toString(await Cheqd.getFile(args.file), 'base64');
613
+ args.payload.data = await Cheqd.getFile(args.file);
267
614
  }
268
615
  if (typeof args?.payload?.data === 'string') {
269
616
  args.payload.data = fromString(args.payload.data, 'base64');
@@ -279,6 +626,110 @@ export class Cheqd {
279
626
  }
280
627
  }, context);
281
628
  }
629
+ async CreateStatusList2021(args, context) {
630
+ if (typeof args.kms !== 'string') {
631
+ throw new Error('[did-provider-cheqd]: kms is required');
632
+ }
633
+ if (typeof args.payload !== 'object') {
634
+ throw new Error('[did-provider-cheqd]: payload object is required');
635
+ }
636
+ if (typeof args.network !== 'string') {
637
+ throw new Error('[did-provider-cheqd]: network is required');
638
+ }
639
+ if (args?.file) {
640
+ args.payload.data = await Cheqd.getFile(args.file);
641
+ }
642
+ if (typeof args?.payload?.data === 'string') {
643
+ args.payload.data = fromString(args.payload.data, 'base64');
644
+ }
645
+ // TODO: validate data as per bitstring
646
+ // set default resource type in runtime
647
+ args.payload.resourceType = 'StatusList2021';
648
+ this.providerId = Cheqd.generateProviderId(args.network);
649
+ this.didProvider = await Cheqd.loadProvider({ id: this.providerId }, this.supportedDidProviders);
650
+ return await this.didProvider.createResource({
651
+ options: {
652
+ kms: args.kms,
653
+ payload: args.payload,
654
+ signInputs: args.signInputs,
655
+ fee: args?.fee
656
+ }
657
+ }, context);
658
+ }
659
+ async CreateEncryptedStatusList2021(args, context) {
660
+ if (typeof args.kms !== 'string') {
661
+ throw new Error('[did-provider-cheqd]: kms is required');
662
+ }
663
+ if (typeof args.payload !== 'object') {
664
+ throw new Error('[did-provider-cheqd]: payload object is required');
665
+ }
666
+ if (typeof args.network !== 'string') {
667
+ throw new Error('[did-provider-cheqd]: network is required');
668
+ }
669
+ if (args?.file) {
670
+ args.payload.data = await Cheqd.getFile(args.file);
671
+ }
672
+ if (typeof args?.payload?.data === 'string') {
673
+ args.payload.data = fromString(args.payload.data, 'base64');
674
+ }
675
+ // TODO: validate data as per bitstring
676
+ if (!args?.encryptionOptions) {
677
+ throw new Error('[did-provider-cheqd]: encryptionOptions is required');
678
+ }
679
+ if (!args?.bootstrapOptions) {
680
+ throw new Error('[did-provider-cheqd]: bootstrapOptions is required');
681
+ }
682
+ if (!args?.encryptionOptions?.accessControlConditions) {
683
+ throw new Error('[did-provider-cheqd]: accessControlConditions is required');
684
+ }
685
+ // instantiate dkg-threshold client, in which case lit-protocol is used
686
+ const lit = await LitProtocol.create({
687
+ chain: args.bootstrapOptions?.chain,
688
+ litNetwork: args.bootstrapOptions?.litNetwork
689
+ });
690
+ // construct access control conditions
691
+ const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
692
+ switch (condition.type) {
693
+ case AccessControlConditionTypes.memoNonce:
694
+ return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
695
+ key: '$.txs.*.body.memo',
696
+ comparator: 'contains',
697
+ value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
698
+ }, condition.amountObserved, condition.senderAddressObserved, condition.recipientAddressObserved, args.bootstrapOptions.chain);
699
+ case AccessControlConditionTypes.balance:
700
+ return await LitProtocol.generateCosmosAccessControlConditionBalance({
701
+ key: '$.balances[0].amount',
702
+ comparator: condition.comparator,
703
+ value: condition.amountObserved
704
+ }, args.bootstrapOptions.chain, condition.addressObserved);
705
+ default:
706
+ throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`);
707
+ }
708
+ }));
709
+ // encrypt data
710
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(toString(args.payload.data, 'base64url'), unifiedAccessControlConditions, true);
711
+ // set encrypted data
712
+ args.payload.data = new Uint8Array(await encryptedString.arrayBuffer());
713
+ // set default resource type in runtime
714
+ args.payload.resourceType = 'StatusList2021';
715
+ this.providerId = Cheqd.generateProviderId(args.network);
716
+ this.didProvider = await Cheqd.loadProvider({ id: this.providerId }, this.supportedDidProviders);
717
+ const created = await this.didProvider.createResource({
718
+ options: {
719
+ kms: args.kms,
720
+ payload: args.payload,
721
+ signInputs: args.signInputs,
722
+ fee: args?.fee
723
+ }
724
+ }, context);
725
+ return {
726
+ created,
727
+ encryptedSymmetricKey,
728
+ encryptedStatusList2021: await blobToHexString(encryptedString),
729
+ symmetricKey: args?.encryptionOptions?.returnSymmetricKey ? toString(symmetricKey, 'hex') : undefined,
730
+ unifiedAccessControlConditions
731
+ };
732
+ }
282
733
  async GenerateDidDoc(args, context) {
283
734
  if (typeof args.verificationMethod !== 'string') {
284
735
  throw new Error('[did-provider-cheqd]: verificationMethod is required');
@@ -355,6 +806,978 @@ export class Cheqd {
355
806
  async GenerateVersionId(args, context) {
356
807
  return v4();
357
808
  }
809
+ async GenerateStatusList2021(args, context) {
810
+ const statusList = args?.buffer
811
+ ? new StatusList({ buffer: args.buffer })
812
+ : new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length });
813
+ const encoded = await statusList.encode();
814
+ switch (args?.bitstringEncoding) {
815
+ case 'base64url':
816
+ return encoded;
817
+ case 'base64':
818
+ return toString(fromString(encoded, 'base64url'), 'base64');
819
+ case 'hex':
820
+ return toString(fromString(encoded, 'base64url'), 'hex');
821
+ default:
822
+ return encoded;
823
+ }
824
+ }
825
+ async GenerateEncryptedStatusList2021(args, context) {
826
+ // validate encryptionOptions
827
+ if (!args.encryptionOptions) {
828
+ throw new Error('[did-provider-cheqd]: encryptionOptions is required');
829
+ }
830
+ // validate encryptionOptions.accessControlConditions
831
+ if (!args.encryptionOptions.accessControlConditions) {
832
+ throw new Error('[did-provider-cheqd]: encryptionOptions.accessControlConditions is required');
833
+ }
834
+ // generate status list
835
+ const statusList = args?.buffer
836
+ ? new StatusList({ buffer: args.buffer })
837
+ : new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length });
838
+ // encode status list
839
+ const encoded = await statusList.encode();
840
+ // instantiate dkg-threshold client, in which case lit-protocol is used
841
+ const lit = await LitProtocol.create({
842
+ chain: args.bootstrapOptions.chain,
843
+ litNetwork: args.bootstrapOptions.litNetwork,
844
+ });
845
+ // construct access control conditions
846
+ const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
847
+ switch (condition.type) {
848
+ case AccessControlConditionTypes.memoNonce:
849
+ return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
850
+ key: '$.txs.*.body.memo',
851
+ comparator: 'contains',
852
+ value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
853
+ }, condition.amountObserved, condition.senderAddressObserved, condition.recipientAddressObserved, args.bootstrapOptions.chain);
854
+ case AccessControlConditionTypes.balance:
855
+ return await LitProtocol.generateCosmosAccessControlConditionBalance({
856
+ key: '$.balances[0].amount',
857
+ comparator: condition.comparator,
858
+ value: condition.amountObserved
859
+ }, args.bootstrapOptions.chain, condition.addressObserved);
860
+ default:
861
+ throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`);
862
+ }
863
+ }));
864
+ // encrypt data
865
+ const { encryptedString, encryptedSymmetricKey } = await lit.encrypt(encoded, unifiedAccessControlConditions);
866
+ // return result
867
+ return {
868
+ encryptedStatusList2021: await blobToHexString(encryptedString),
869
+ encryptedSymmetricKey,
870
+ unifiedAccessControlConditions
871
+ };
872
+ }
873
+ async IssueRevocableCredentialWithStatusList2021(args, context) {
874
+ // generate index
875
+ const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || []);
876
+ // construct issuer
877
+ const issuer = (args.issuanceOptions.credential.issuer.id)
878
+ ? args.issuanceOptions.credential.issuer.id
879
+ : args.issuanceOptions.credential.issuer;
880
+ // generate status list credential
881
+ const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`;
882
+ // construct credential status
883
+ const credentialStatus = {
884
+ id: `${statusListCredential}#${statusListIndex}`,
885
+ type: 'StatusList2021Entry',
886
+ statusPurpose: 'revocation',
887
+ statusListIndex: `${statusListIndex}`,
888
+ statusListCredential,
889
+ };
890
+ // add credential status to credential
891
+ args.issuanceOptions.credential.credentialStatus = credentialStatus;
892
+ // add relevant context
893
+ args.issuanceOptions.credential['@context'] = function () {
894
+ // if no context is provided, add default context
895
+ if (!args.issuanceOptions.credential['@context']) {
896
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
897
+ }
898
+ // if context is provided as an array, add default context if it is not already present
899
+ if (Array.isArray(args.issuanceOptions.credential['@context'])) {
900
+ if (args.issuanceOptions.credential['@context'].length === 0) {
901
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
902
+ }
903
+ if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
904
+ return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
905
+ }
906
+ }
907
+ // if context is provided as a string, add default context if it is not already present
908
+ if (typeof args.issuanceOptions.credential['@context'] === 'string')
909
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
910
+ }();
911
+ // create a credential
912
+ const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
913
+ return credential;
914
+ }
915
+ async IssueSuspendableCredentialWithStatusList2021(args, context) {
916
+ // generate index
917
+ const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || []);
918
+ // construct issuer
919
+ const issuer = (args.issuanceOptions.credential.issuer.id)
920
+ ? args.issuanceOptions.credential.issuer.id
921
+ : args.issuanceOptions.credential.issuer;
922
+ // generate status list credential
923
+ const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`;
924
+ // construct credential status
925
+ const credentialStatus = {
926
+ id: `${statusListCredential}#${statusListIndex}`,
927
+ type: 'StatusList2021Entry',
928
+ statusPurpose: 'suspension',
929
+ statusListIndex: `${statusListIndex}`,
930
+ statusListCredential,
931
+ };
932
+ // add credential status to credential
933
+ args.issuanceOptions.credential.credentialStatus = credentialStatus;
934
+ // add relevant context
935
+ args.issuanceOptions.credential['@context'] = function () {
936
+ // if no context is provided, add default context
937
+ if (!args.issuanceOptions.credential['@context']) {
938
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
939
+ }
940
+ // if context is provided as an array, add default context if it is not already present
941
+ if (Array.isArray(args.issuanceOptions.credential['@context'])) {
942
+ if (args.issuanceOptions.credential['@context'].length === 0) {
943
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
944
+ }
945
+ if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
946
+ return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
947
+ }
948
+ }
949
+ // if context is provided as a string, add default context if it is not already present
950
+ if (typeof args.issuanceOptions.credential['@context'] === 'string')
951
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
952
+ }();
953
+ // create a credential
954
+ const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
955
+ return credential;
956
+ }
957
+ async VerifyCredentialWithStatusList2021(args, context) {
958
+ // verify default policies
959
+ const verificationResult = await context.agent.verifyCredential({
960
+ credential: args.credential,
961
+ policies: {
962
+ credentialStatus: false
963
+ }
964
+ });
965
+ // early return if verification failed
966
+ if (!verificationResult.verified) {
967
+ return { verified: false, error: verificationResult.error };
968
+ }
969
+ // verify credential status
970
+ switch (args.credential.credentialStatus?.statusPurpose) {
971
+ case 'revocation':
972
+ if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args }))
973
+ return { verified: false, revoked: true };
974
+ return { verified: true, revoked: false };
975
+ case 'suspension':
976
+ if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args }))
977
+ return { verified: false, suspended: true };
978
+ return { verified: true, suspended: false };
979
+ default:
980
+ throw new Error(`[did-provider-cheqd]: verify credential: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
981
+ }
982
+ }
983
+ async VerifyPresentationWithStatusList2021(args, context) {
984
+ // verify default policies
985
+ const verificationResult = await context.agent.verifyPresentation({
986
+ presentation: args.presentation,
987
+ policies: {
988
+ credentialStatus: false
989
+ }
990
+ });
991
+ // early return if verification failed
992
+ if (!verificationResult.verified) {
993
+ return { verified: false, error: verificationResult.error };
994
+ }
995
+ if (!args.presentation.verifiableCredential)
996
+ throw new Error('[did-provider-cheqd]: verify presentation: presentation.verifiableCredential is required');
997
+ // verify credential(s) status(es)
998
+ for (let credential of args.presentation.verifiableCredential) {
999
+ // if jwt credential, decode it
1000
+ if (typeof credential === 'string') {
1001
+ const decodedCredential = decodeJWT(credential);
1002
+ // validate credential payload
1003
+ if (!decodedCredential.payload)
1004
+ throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload is required');
1005
+ // validate credential payload ref as VerifiableCredential
1006
+ if (!decodedCredential.payload.vc)
1007
+ throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload.vc is required');
1008
+ credential = decodedCredential.payload.vc;
1009
+ }
1010
+ switch (credential.credentialStatus?.statusPurpose) {
1011
+ case 'revocation':
1012
+ if (await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }))
1013
+ return { verified: false, revoked: true };
1014
+ break;
1015
+ case 'suspension':
1016
+ if (await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }))
1017
+ return { verified: false, suspended: true };
1018
+ break;
1019
+ default:
1020
+ throw new Error(`[did-provider-cheqd]: verify presentation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
1021
+ }
1022
+ }
1023
+ return { verified: true };
1024
+ }
1025
+ async CheckCredentialStatusWithStatusList2021(args, context) {
1026
+ switch (args.credential.credentialStatus?.statusPurpose) {
1027
+ case 'revocation':
1028
+ if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args }))
1029
+ return { revoked: true };
1030
+ return { revoked: false };
1031
+ case 'suspension':
1032
+ if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args }))
1033
+ return { suspended: true };
1034
+ return { suspended: false };
1035
+ default:
1036
+ throw new Error(`[did-provider-cheqd]: check status: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
1037
+ }
1038
+ }
1039
+ async RevokeCredentialWithStatusList2021(args, context) {
1040
+ // validate status purpose
1041
+ if (args.credential.credentialStatus?.statusPurpose !== 'revocation') {
1042
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
1043
+ }
1044
+ // validate args in pairs - case: statusListFile and statusList
1045
+ if (args.options?.statusListFile && args.options?.statusList) {
1046
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and statusList are mutually exclusive');
1047
+ }
1048
+ // validate args in pairs - case: statusListFile and fetchList
1049
+ if (args.options?.statusListFile && args.options?.fetchList) {
1050
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and fetchList are mutually exclusive');
1051
+ }
1052
+ // validate args in pairs - case: statusList and fetchList
1053
+ if (args.options?.statusList && args.options?.fetchList) {
1054
+ throw new Error('[did-provider-cheqd]: revocation: statusList and fetchList are mutually exclusive');
1055
+ }
1056
+ // validate args in pairs - case: publish
1057
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1058
+ throw new Error('[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled');
1059
+ }
1060
+ // revoke credential
1061
+ return await Cheqd.revokeCredential(args.credential, {
1062
+ ...args.options,
1063
+ topArgs: args,
1064
+ publishOptions: {
1065
+ context,
1066
+ resourceId: args?.options?.resourceId,
1067
+ resourceVersion: args?.options?.resourceVersion,
1068
+ signInputs: args?.options?.signInputs,
1069
+ fee: args?.options?.fee
1070
+ }
1071
+ });
1072
+ }
1073
+ async RevokeBulkCredentialsWithStatusList2021(args, context) {
1074
+ // TODO: implement
1075
+ throw new Error('[did-provider-cheqd]: revocation: bulk revocation is not implemented yet');
1076
+ }
1077
+ async SuspendCredentialWithStatusList2021(args, context) {
1078
+ // validate status purpose
1079
+ if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
1080
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
1081
+ }
1082
+ // validate args in pairs - case: statusListFile and statusList
1083
+ if (args.options?.statusListFile && args.options?.statusList) {
1084
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive');
1085
+ }
1086
+ // validate args in pairs - case: statusListFile and fetchList
1087
+ if (args.options?.statusListFile && args.options?.fetchList) {
1088
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive');
1089
+ }
1090
+ // validate args in pairs - case: statusList and fetchList
1091
+ if (args.options?.statusList && args.options?.fetchList) {
1092
+ throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive');
1093
+ }
1094
+ // validate args in pairs - case: publish
1095
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1096
+ throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled');
1097
+ }
1098
+ // suspend credential
1099
+ return await Cheqd.suspendCredential(args.credential, {
1100
+ ...args.options,
1101
+ topArgs: args,
1102
+ publishOptions: {
1103
+ context,
1104
+ resourceId: args?.options?.resourceId,
1105
+ resourceVersion: args?.options?.resourceVersion,
1106
+ signInputs: args?.options?.signInputs,
1107
+ fee: args?.options?.fee
1108
+ }
1109
+ });
1110
+ }
1111
+ async SuspendBulkCredentialsWithStatusList2021(args, context) {
1112
+ // TODO: implement
1113
+ throw new Error('[did-provider-cheqd]: suspension: bulk suspension is not implemented yet');
1114
+ }
1115
+ async UnsuspendCredentialWithStatusList2021(args, context) {
1116
+ // validate status purpose
1117
+ if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
1118
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
1119
+ }
1120
+ // validate args in pairs - case: statusListFile and statusList
1121
+ if (args.options?.statusListFile && args.options?.statusList) {
1122
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive');
1123
+ }
1124
+ // validate args in pairs - case: statusListFile and fetchList
1125
+ if (args.options?.statusListFile && args.options?.fetchList) {
1126
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive');
1127
+ }
1128
+ // validate args in pairs - case: statusList and fetchList
1129
+ if (args.options?.statusList && args.options?.fetchList) {
1130
+ throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive');
1131
+ }
1132
+ // validate args in pairs - case: publish
1133
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1134
+ throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled');
1135
+ }
1136
+ // suspend credential
1137
+ return await Cheqd.unsuspendCredential(args.credential, {
1138
+ ...args.options,
1139
+ topArgs: args,
1140
+ publishOptions: {
1141
+ context,
1142
+ resourceId: args?.options?.resourceId,
1143
+ resourceVersion: args?.options?.resourceVersion,
1144
+ signInputs: args?.options?.signInputs,
1145
+ fee: args?.options?.fee
1146
+ }
1147
+ });
1148
+ }
1149
+ async UnsuspendBulkCredentialsWithStatusList2021(args, context) {
1150
+ // TODO: implement
1151
+ throw new Error('[did-provider-cheqd]: suspension: bulk unsuspension is not implemented yet');
1152
+ }
1153
+ async TransactVerifierPaysIssuer(args, context) {
1154
+ try {
1155
+ // delegate to provider
1156
+ const transactionResult = await this.didProvider.transactSendTokens({
1157
+ recipientAddress: args.recipientAddress,
1158
+ amount: args.amount,
1159
+ memoNonce: args.memoNonce,
1160
+ txBytes: args.txBytes,
1161
+ });
1162
+ // return transaction result
1163
+ return {
1164
+ successful: !transactionResult.code,
1165
+ transactionHash: transactionResult.transactionHash,
1166
+ events: transactionResult.events,
1167
+ rawLog: transactionResult.rawLog,
1168
+ txResponse: args?.returnTxResponse ? transactionResult : undefined
1169
+ };
1170
+ }
1171
+ catch (error) {
1172
+ // return error
1173
+ return {
1174
+ successful: false,
1175
+ error: error
1176
+ };
1177
+ }
1178
+ }
1179
+ async ObserveVerifierPaysIssuer(args, context) {
1180
+ // verify with raw unified access control conditions, if any
1181
+ if (args?.unifiedAccessControlCondition) {
1182
+ try {
1183
+ // define network
1184
+ const network = (function () {
1185
+ switch (args.unifiedAccessControlCondition.chain) {
1186
+ case LitCompatibleCosmosChains.cheqdMainnet:
1187
+ return CheqdNetwork.Mainnet;
1188
+ case LitCompatibleCosmosChains.cheqdTestnet:
1189
+ return CheqdNetwork.Testnet;
1190
+ default:
1191
+ throw new Error(`[did-provider-cheqd]: observe: Unsupported chain: ${args.unifiedAccessControlCondition.chain}`);
1192
+ }
1193
+ }());
1194
+ // construct url
1195
+ const url = `${DefaultRESTUrls[network]}${args.unifiedAccessControlCondition.path}`;
1196
+ // fetch relevant txs
1197
+ const txs = await (await fetch(url)).json();
1198
+ // skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
1199
+ const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.unifiedAccessControlCondition.returnValueTest.value));
1200
+ // define meetsCondition
1201
+ const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
1202
+ // return observation result
1203
+ return {
1204
+ subscribed: true,
1205
+ meetsCondition: meetsCondition,
1206
+ transactionHash: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].txhash : undefined,
1207
+ events: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].events : undefined,
1208
+ rawLog: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].raw_log : undefined,
1209
+ txResponse: meetsCondition ? (args?.returnTxResponse ? txs.tx_responses[meetsConditionTxIndex] : undefined) : undefined
1210
+ };
1211
+ }
1212
+ catch (error) {
1213
+ // return error
1214
+ return {
1215
+ subscribed: false,
1216
+ meetsCondition: false,
1217
+ error: error
1218
+ };
1219
+ }
1220
+ }
1221
+ // validate access control conditions components - case: senderAddress
1222
+ if (!args.senderAddress) {
1223
+ throw new Error('[did-provider-cheqd]: observation: senderAddress is required');
1224
+ }
1225
+ // validate access control conditions components - case: recipientAddress
1226
+ if (!args.recipientAddress) {
1227
+ throw new Error('[did-provider-cheqd]: observation: recipientAddress is required');
1228
+ }
1229
+ // validate access control conditions components - case: amount
1230
+ if (!args.amount || !args.amount.amount || !args.amount.denom || args.amount.denom !== 'ncheq') {
1231
+ throw new Error('[did-provider-cheqd]: observation: amount is required, and must be an object with amount and denom valid string properties, amongst which denom must be `ncheq`');
1232
+ }
1233
+ // validate access control conditions components - case: memoNonce
1234
+ if (!args.memoNonce) {
1235
+ throw new Error('[did-provider-cheqd]: observation: memoNonce is required');
1236
+ }
1237
+ // validate access control conditions components - case: network
1238
+ if (!args.network) {
1239
+ throw new Error('[did-provider-cheqd]: observation: network is required');
1240
+ }
1241
+ try {
1242
+ // otherwise, construct url, as per components
1243
+ const url = `${DefaultRESTUrls[args.network]}/cosmos/tx/v1beta1/txs?events=transfer.recipient='${args.recipientAddress}'&events=transfer.sender='${args.senderAddress}'&events=transfer.amount='${args.amount.amount}${args.amount.denom}'`;
1244
+ // fetch relevant txs
1245
+ const txs = await (await fetch(url)).json();
1246
+ // skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
1247
+ const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.memoNonce));
1248
+ // define meetsCondition
1249
+ const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
1250
+ // return observation result
1251
+ return {
1252
+ subscribed: true,
1253
+ meetsCondition: meetsCondition,
1254
+ transactionHash: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].txhash : undefined,
1255
+ events: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].events : undefined,
1256
+ rawLog: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].raw_log : undefined,
1257
+ txResponse: meetsCondition ? (args?.returnTxResponse ? txs.tx_responses[meetsConditionTxIndex] : undefined) : undefined
1258
+ };
1259
+ }
1260
+ catch (error) {
1261
+ // return error
1262
+ return {
1263
+ subscribed: false,
1264
+ meetsCondition: false,
1265
+ error: error
1266
+ };
1267
+ }
1268
+ }
1269
+ static async revokeCredential(credential, options) {
1270
+ try {
1271
+ // validate status purpose
1272
+ if (credential?.credentialStatus?.statusPurpose !== 'revocation')
1273
+ throw new Error('[did-provider-cheqd]: revocation: Invalid status purpose');
1274
+ // fetch status list 2021 metadata
1275
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
1276
+ // detect if encrypted
1277
+ const isEncrypted = function () {
1278
+ switch (metadata.mediaType) {
1279
+ case 'application/octet-stream':
1280
+ return true;
1281
+ case 'application/gzip':
1282
+ return false;
1283
+ default:
1284
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`);
1285
+ }
1286
+ }();
1287
+ // early return, if encrypted and no decryption key provided
1288
+ if (isEncrypted && !options?.topArgs?.symmetricKey)
1289
+ throw new Error('[did-provider-cheqd]: revocation: symmetricKey is required, if status list 2021 is encrypted');
1290
+ // fetch status list 2021 inscribed in credential
1291
+ const statusList2021 = options?.topArgs?.fetchList
1292
+ ? (await async function () {
1293
+ // if not encrypted, return bitstring
1294
+ if (!isEncrypted)
1295
+ return await Cheqd.fetchStatusList2021(credential);
1296
+ // otherwise, decrypt and return bitstring
1297
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
1298
+ // decrypt
1299
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1300
+ }())
1301
+ : (await async function () {
1302
+ // if status list 2021 is not fetched, read from file
1303
+ if (options?.statusListFile) {
1304
+ // if not encrypted, return bitstring
1305
+ if (!isEncrypted)
1306
+ return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
1307
+ // otherwise, decrypt and return bitstring
1308
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
1309
+ // decrypt
1310
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1311
+ }
1312
+ if (!options?.statusListInlineBitstring)
1313
+ throw new Error('[did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
1314
+ // otherwise, read from inline bitstring
1315
+ return options?.statusListInlineBitstring;
1316
+ }());
1317
+ // parse status list 2021
1318
+ const statusList = await StatusList.decode({ encodedList: statusList2021 });
1319
+ // early exit, if credential is already revoked
1320
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
1321
+ return { revoked: false };
1322
+ // update revocation status
1323
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
1324
+ // set in-memory status list ref
1325
+ const bitstring = await statusList.encode();
1326
+ // cast top-level args
1327
+ const topArgs = options?.topArgs;
1328
+ // write status list 2021 to file, if provided
1329
+ if (topArgs?.writeToFile) {
1330
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
1331
+ }
1332
+ // publish status list 2021, if provided
1333
+ const published = topArgs?.publish
1334
+ ? (await async function () {
1335
+ // fetch status list 2021 metadata
1336
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
1337
+ // publish status list 2021 as new version
1338
+ const scoped = topArgs.publishEncrypted
1339
+ ? (await async function () {
1340
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1341
+ const lit = await LitProtocol.create({
1342
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1343
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1344
+ });
1345
+ // encrypt
1346
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
1347
+ // return tuple of publish result and encryption relevant metadata
1348
+ return [
1349
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
1350
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
1351
+ ];
1352
+ }())
1353
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
1354
+ // early exit, if publish failed
1355
+ if (!scoped[0])
1356
+ throw new Error('[did-provider-cheqd]: revocation: Failed to publish status list 2021');
1357
+ // return publish result
1358
+ return scoped;
1359
+ }())
1360
+ : undefined;
1361
+ return {
1362
+ revoked: true,
1363
+ published: topArgs?.publish ? true : undefined,
1364
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
1365
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
1366
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
1367
+ symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
1368
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
1369
+ };
1370
+ }
1371
+ catch (error) {
1372
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
1373
+ console.error(error);
1374
+ return { revoked: false, error: error };
1375
+ }
1376
+ }
1377
+ static async suspendCredential(credential, options) {
1378
+ try {
1379
+ // validate status purpose
1380
+ if (credential?.credentialStatus?.statusPurpose !== 'suspension')
1381
+ throw new Error('[did-provider-cheqd]: suspension: Invalid status purpose');
1382
+ // fetch status list 2021 metadata
1383
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
1384
+ // detect if encrypted
1385
+ const isEncrypted = function () {
1386
+ switch (metadata.mediaType) {
1387
+ case 'application/octet-stream':
1388
+ return true;
1389
+ case 'application/gzip':
1390
+ return false;
1391
+ default:
1392
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`);
1393
+ }
1394
+ }();
1395
+ // early return, if encrypted and no decryption key provided
1396
+ if (isEncrypted && !options?.topArgs?.symmetricKey)
1397
+ throw new Error('[did-provider-cheqd]: suspension: symmetricKey is required, if status list 2021 is encrypted');
1398
+ // fetch status list 2021 inscribed in credential
1399
+ const statusList2021 = options?.topArgs?.fetchList
1400
+ ? (await async function () {
1401
+ // if not encrypted, return bitstring
1402
+ if (!isEncrypted)
1403
+ return await Cheqd.fetchStatusList2021(credential);
1404
+ // otherwise, decrypt and return bitstring
1405
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
1406
+ // decrypt
1407
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1408
+ }())
1409
+ : (await async function () {
1410
+ // if status list 2021 is not fetched, read from file
1411
+ if (options?.statusListFile) {
1412
+ // if not encrypted, return bitstring
1413
+ if (!isEncrypted)
1414
+ return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
1415
+ // otherwise, decrypt and return bitstring
1416
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
1417
+ // decrypt
1418
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1419
+ }
1420
+ if (!options?.statusListInlineBitstring)
1421
+ throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
1422
+ // otherwise, read from inline bitstring
1423
+ return options?.statusListInlineBitstring;
1424
+ }());
1425
+ // parse status list 2021
1426
+ const statusList = await StatusList.decode({ encodedList: statusList2021 });
1427
+ // early exit, if already suspended
1428
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
1429
+ return { suspended: false };
1430
+ // update suspension status
1431
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
1432
+ // set in-memory status list ref
1433
+ const bitstring = await statusList.encode();
1434
+ // cast top-level args
1435
+ const topArgs = options?.topArgs;
1436
+ // write status list 2021 to file, if provided
1437
+ if (topArgs?.writeToFile) {
1438
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
1439
+ }
1440
+ // publish status list 2021, if provided
1441
+ const published = topArgs?.publish
1442
+ ? (await async function () {
1443
+ // fetch status list 2021 metadata
1444
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
1445
+ // publish status list 2021 as new version
1446
+ const scoped = topArgs.publishEncrypted
1447
+ ? (await async function () {
1448
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1449
+ const lit = await LitProtocol.create({
1450
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1451
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1452
+ });
1453
+ // encrypt
1454
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
1455
+ // return tuple of publish result and encryption relevant metadata
1456
+ return [
1457
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
1458
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
1459
+ ];
1460
+ }())
1461
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
1462
+ // early exit, if publish failed
1463
+ if (!scoped[0])
1464
+ throw new Error('[did-provider-cheqd]: suspension: Failed to publish status list 2021');
1465
+ // return publish result
1466
+ return scoped;
1467
+ }())
1468
+ : undefined;
1469
+ return {
1470
+ suspended: true,
1471
+ published: topArgs?.publish ? true : undefined,
1472
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
1473
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
1474
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
1475
+ symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
1476
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
1477
+ };
1478
+ }
1479
+ catch (error) {
1480
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
1481
+ console.error(error);
1482
+ return { suspended: false, error: error };
1483
+ }
1484
+ }
1485
+ static async unsuspendCredential(credential, options) {
1486
+ try {
1487
+ // validate status purpose
1488
+ if (credential?.credentialStatus?.statusPurpose !== 'suspension')
1489
+ throw new Error('[did-provider-cheqd]: unsuspension: Invalid status purpose');
1490
+ // fetch status list 2021 metadata
1491
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
1492
+ // detect if encrypted
1493
+ const isEncrypted = function () {
1494
+ switch (metadata.mediaType) {
1495
+ case 'application/octet-stream':
1496
+ return true;
1497
+ case 'application/gzip':
1498
+ return false;
1499
+ default:
1500
+ throw new Error(`[did-provider-cheqd]: unsuspension: Unsupported media type: ${metadata.mediaType}`);
1501
+ }
1502
+ }();
1503
+ // early return, if encrypted and no decryption key provided
1504
+ if (isEncrypted && !options?.topArgs?.symmetricKey)
1505
+ throw new Error('[did-provider-cheqd]: unsuspension: symmetricKey is required, if status list 2021 is encrypted');
1506
+ // fetch status list 2021 inscribed in credential
1507
+ const statusList2021 = options?.topArgs?.fetchList
1508
+ ? (await async function () {
1509
+ // if not encrypted, return bitstring
1510
+ if (!isEncrypted)
1511
+ return await Cheqd.fetchStatusList2021(credential);
1512
+ // otherwise, decrypt and return bitstring
1513
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
1514
+ // decrypt
1515
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1516
+ }())
1517
+ : (await async function () {
1518
+ // if status list 2021 is not fetched, read from file
1519
+ if (options?.statusListFile) {
1520
+ // if not encrypted, return bitstring
1521
+ if (!isEncrypted)
1522
+ return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
1523
+ // otherwise, decrypt and return bitstring
1524
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
1525
+ // decrypt
1526
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
1527
+ }
1528
+ if (!options?.statusListInlineBitstring)
1529
+ throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring is required, if statusListFile is not provided');
1530
+ // otherwise, read from inline bitstring
1531
+ return options?.statusListInlineBitstring;
1532
+ }());
1533
+ // parse status list 2021
1534
+ const statusList = await StatusList.decode({ encodedList: statusList2021 });
1535
+ // early exit, if already suspended
1536
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
1537
+ return { unsuspended: false };
1538
+ // update suspension status
1539
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
1540
+ // set in-memory status list ref
1541
+ const bitstring = await statusList.encode();
1542
+ // cast top-level args
1543
+ const topArgs = options?.topArgs;
1544
+ // write status list 2021 to file, if provided
1545
+ if (topArgs?.writeToFile) {
1546
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
1547
+ }
1548
+ // publish status list 2021, if provided
1549
+ const published = topArgs?.publish
1550
+ ? (await async function () {
1551
+ // fetch status list 2021 metadata
1552
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
1553
+ // publish status list 2021 as new version
1554
+ const scoped = topArgs.publishEncrypted
1555
+ ? (await async function () {
1556
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1557
+ const lit = await LitProtocol.create({
1558
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1559
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1560
+ });
1561
+ // encrypt
1562
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
1563
+ // return tuple of publish result and encryption relevant metadata
1564
+ return [
1565
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
1566
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
1567
+ ];
1568
+ }())
1569
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
1570
+ // early exit, if publish failed
1571
+ if (!scoped[0])
1572
+ throw new Error('[did-provider-cheqd]: unsuspension: Failed to publish status list 2021');
1573
+ // return publish result
1574
+ return scoped;
1575
+ }())
1576
+ : undefined;
1577
+ return {
1578
+ unsuspended: true,
1579
+ published: topArgs?.publish ? true : undefined,
1580
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
1581
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
1582
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
1583
+ symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
1584
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
1585
+ };
1586
+ }
1587
+ catch (error) {
1588
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
1589
+ console.error(error);
1590
+ return { unsuspended: false, error: error };
1591
+ }
1592
+ }
1593
+ static async checkRevoked(credential, options = { fetchList: true }) {
1594
+ // validate status purpose
1595
+ if (credential.credentialStatus?.statusPurpose !== 'revocation') {
1596
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
1597
+ }
1598
+ // fetch status list 2021 metadata
1599
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
1600
+ // detect if encrypted
1601
+ const isEncrypted = function () {
1602
+ switch (metadata.mediaType) {
1603
+ case 'application/octet-stream':
1604
+ return true;
1605
+ case 'application/gzip':
1606
+ return false;
1607
+ default:
1608
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`);
1609
+ }
1610
+ }();
1611
+ // early return, if encrypted and decryption key is not provided
1612
+ if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey)
1613
+ throw new Error('[did-provider-cheqd]: revocation: encryptedSymmetricKey is required, if status list 2021 is encrypted');
1614
+ // fetch status list 2021 inscribed in credential
1615
+ const statusList2021 = options?.topArgs?.fetchList
1616
+ ? (await async function () {
1617
+ // if not encrypted, return bitstring
1618
+ if (!isEncrypted)
1619
+ return await Cheqd.fetchStatusList2021(credential);
1620
+ // otherwise, decrypt and return bitstring
1621
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
1622
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1623
+ const lit = await LitProtocol.create({
1624
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1625
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1626
+ });
1627
+ // decrypt
1628
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
1629
+ }())
1630
+ : (await async function () {
1631
+ // if status list 2021 is not fetched, read from file
1632
+ if (options?.statusListFile) {
1633
+ // if not encrypted, return bitstring
1634
+ if (!isEncrypted)
1635
+ return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
1636
+ // otherwise, decrypt and return bitstring
1637
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
1638
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1639
+ const lit = await LitProtocol.create({
1640
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1641
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1642
+ });
1643
+ // decrypt
1644
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
1645
+ }
1646
+ if (!options?.statusListInlineBitstring)
1647
+ throw new Error(' [did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
1648
+ // otherwise, read from inline bitstring
1649
+ return options?.statusListInlineBitstring;
1650
+ }());
1651
+ // parse status list 2021
1652
+ const statusList = await StatusList.decode({ encodedList: statusList2021 });
1653
+ // get status by index
1654
+ return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex));
1655
+ }
1656
+ static async checkSuspended(credential, options = { fetchList: true }) {
1657
+ // validate status purpose
1658
+ if (credential.credentialStatus?.statusPurpose !== 'suspension') {
1659
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
1660
+ }
1661
+ // fetch status list 2021 metadata
1662
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
1663
+ // detect if encrypted
1664
+ const isEncrypted = function () {
1665
+ switch (metadata.mediaType) {
1666
+ case 'application/octet-stream':
1667
+ return true;
1668
+ case 'application/gzip':
1669
+ return false;
1670
+ default:
1671
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`);
1672
+ }
1673
+ }();
1674
+ // early return, if encrypted and decryption key is not provided
1675
+ if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey)
1676
+ throw new Error('[did-provider-cheqd]: suspension: encryptedSymmetricKey is required, if status list 2021 is encrypted');
1677
+ // fetch status list 2021 inscribed in credential
1678
+ const statusList2021 = options?.topArgs?.fetchList
1679
+ ? (await async function () {
1680
+ // if not encrypted, return bitstring
1681
+ if (!isEncrypted)
1682
+ return await Cheqd.fetchStatusList2021(credential);
1683
+ // otherwise, decrypt and return bitstring
1684
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
1685
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1686
+ const lit = await LitProtocol.create({
1687
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1688
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1689
+ });
1690
+ // decrypt
1691
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
1692
+ }())
1693
+ : (await async function () {
1694
+ // if status list 2021 is not fetched, read from file
1695
+ if (options?.statusListFile) {
1696
+ // if not encrypted, return bitstring
1697
+ if (!isEncrypted)
1698
+ return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
1699
+ // otherwise, decrypt and return bitstring
1700
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
1701
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1702
+ const lit = await LitProtocol.create({
1703
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1704
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1705
+ });
1706
+ // decrypt
1707
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
1708
+ }
1709
+ if (!options?.statusListInlineBitstring)
1710
+ throw new Error(' [did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
1711
+ // otherwise, read from inline bitstring
1712
+ return options?.statusListInlineBitstring;
1713
+ }());
1714
+ // parse status list 2021
1715
+ const statusList = await StatusList.decode({ encodedList: statusList2021 });
1716
+ // get status by index
1717
+ return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex));
1718
+ }
1719
+ static async publishStatusList2021(statusList2021Raw, statusList2021Metadata, options) {
1720
+ // construct status list 2021 payload from previous version + new version
1721
+ const payload = {
1722
+ collectionId: statusList2021Metadata.resourceCollectionId,
1723
+ id: options?.resourceId || v4(),
1724
+ name: statusList2021Metadata.resourceName,
1725
+ version: options?.resourceVersion || new Date().toISOString(),
1726
+ resourceType: 'StatusList2021',
1727
+ data: statusList2021Raw
1728
+ };
1729
+ return await options.context.agent[CreateStatusList2021MethodName]({
1730
+ kms: (await options.context.agent.keyManagerGetKeyManagementSystems())[0],
1731
+ payload,
1732
+ network: statusList2021Metadata.resourceURI.split(':')[2],
1733
+ signInputs: options?.signInputs,
1734
+ fee: options?.fee
1735
+ });
1736
+ }
1737
+ static async fetchStatusList2021(credential, returnRaw = false) {
1738
+ // validate credential status
1739
+ if (!credential.credentialStatus)
1740
+ throw new Error('[did-provider-cheqd]: fetch status list: Credential status is not present');
1741
+ // validate credential status type
1742
+ if (credential.credentialStatus.type !== 'StatusList2021Entry')
1743
+ throw new Error('[did-provider-cheqd]: fetch status list: Credential status type is not valid');
1744
+ // validate credential status list status purpose
1745
+ if (credential.credentialStatus.statusPurpose !== 'revocation' && credential.credentialStatus.statusPurpose !== 'suspension')
1746
+ throw new Error('[did-provider-cheqd]: fetch status list: Credential status purpose is not valid');
1747
+ // validate credential status list status list credential
1748
+ if (!credential.credentialStatus.statusListCredential)
1749
+ throw new Error('[did-provider-cheqd]: fetch status list: Credential status list credential is not present');
1750
+ // fetch status list 2021
1751
+ const raw = await (await fetch(credential.credentialStatus.statusListCredential)).arrayBuffer();
1752
+ // return raw if requested
1753
+ if (returnRaw)
1754
+ return new Uint8Array(raw);
1755
+ // otherwise, parse to bitstring and return
1756
+ const bitstring = toString(new Uint8Array(raw), 'base64url');
1757
+ return bitstring;
1758
+ }
1759
+ static async fetchStatusList2021Metadata(credential) {
1760
+ // get base url
1761
+ const baseUrl = new URL(credential.credentialStatus?.statusListCredential);
1762
+ // get resource name
1763
+ const resourceName = baseUrl.searchParams.get('resourceName');
1764
+ // unset resource name
1765
+ baseUrl.searchParams.delete('resourceName');
1766
+ // construct metadata url
1767
+ const metadataUrl = `${baseUrl.toString()}/metadata`;
1768
+ // fetch collection metadata
1769
+ const collectionMetadata = await (await fetch(metadataUrl)).json();
1770
+ // early exit if no linked resources
1771
+ if (!collectionMetadata?.contentStream?.linkedResourceMetadata)
1772
+ throw new Error('[did-provider-cheqd]: fetch status list metadata: No linked resources found');
1773
+ // find relevant resources by resource name
1774
+ const resourceVersioning = collectionMetadata.contentStream.linkedResourceMetadata.filter((resource) => resource.resourceName === resourceName);
1775
+ // early exit if no relevant resources
1776
+ if (!resourceVersioning.length || resourceVersioning.length === 0)
1777
+ throw new Error(`[did-provider-cheqd]: fetch status list metadata: No relevant resources found by resource name ${resourceName}`);
1778
+ // get latest resource version by nextVersionId null pointer, or by latest created date as fallback
1779
+ return resourceVersioning.find((resource) => !resource.nextVersionId) || resourceVersioning.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())[0];
1780
+ }
358
1781
  static async loadProvider(document, providers) {
359
1782
  const provider = providers.find((provider) => document.id.includes(`${DidPrefix}:${CheqdDidMethod}:${provider.network}`));
360
1783
  if (!provider) {
@@ -381,5 +1804,23 @@ export class Cheqd {
381
1804
  resolve(new Uint8Array(content));
382
1805
  });
383
1806
  }
1807
+ static async writeFile(content, filename) {
1808
+ if (!filename) {
1809
+ filename = `statusList2021-${v4()}`;
1810
+ }
1811
+ // alert if file exists
1812
+ if (fs.existsSync(filename)) {
1813
+ debug(`[did-provider-cheqd]: File ${filename} already exists`);
1814
+ console.warn(`[did-provider-cheqd]: File ${filename} already exists. Overwriting...`);
1815
+ }
1816
+ return new Promise((resolve, reject) => {
1817
+ fs.writeFile(filename, content, (err) => {
1818
+ if (err) {
1819
+ reject(new Error(`[did-provider-cheqd]: Error writing file ${filename}: reason: ${err}`));
1820
+ }
1821
+ resolve();
1822
+ });
1823
+ });
1824
+ }
384
1825
  }
385
1826
  //# sourceMappingURL=ICheqd.js.map